Parsing HTML in TLabel - Read by Tag
lazarus / 62-General
----------------------------------------------------------------------
andriesh · 2020-05-01 08:01
Hi, guys. Found this solution on forum here ->
https://forum.lazarus.freepascal.org/index.php?topic=35607.0
(Leledumbo Solution)
Its work for me, but I have an downloaded HTML file... 'test.HTML' in
project,
this file is reloading every time when App is starting. How to edit
this code so I can read the html file from the folder? Need to extract
some text from this file and put in Label. Thanks in advance
Code: Pascal [Select][+][-]window.onload = function(){var x1 =
document.getElementById("main_content_section"); if (x1) { var x =
document.getElementsByClassName("geshi");for (var i = 0; i uses
classes,sax_html,dom_html,dom;const testdata = '
' + 'this is just a simple example' +
'
' ;var doc: thtmldocument; els: tdomnodelist;begin
readhtmlfile(doc,tstringstream.create(testdata)); els :=
doc.GetElementsByTagName('div'); if els.Count > 0 then begin
ronB1.Caption:=tdomelement(els[0]).getattribute('id');
ronB2.Caption:=tdomelement(els[0]).getattribute('multiple');
ronB3.Caption:=tdomelement(els[0]).textcontent); end;end.
----------------------------------------------------------------------
wp · 2020-05-01 08:34
There is an overloaded ReadHtmlFile which accepts a filename as second
parameter.
Code: Pascal [Select][+][-]window.onload = function(){var x1 =
document.getElementById("main_content_section"); if (x1) { var x =
document.getElementsByClassName("geshi");for (var i = 0; i
ReadHtmlFile(doc, 'test.HTML'); ...
BTW, the way the stream is created in the sample code is not ok
because there is not way to free the stream again. Better to create
the stream before ReadHtmlFile and use the variable there:
Code: Pascal [Select][+][-]window.onload = function(){var x1 =
document.getElementById("main_content_section"); if (x1) { var x =
document.getElementsByClassName("geshi");for (var i = 0; i var doc:
thtmldocument; stream: TStream; els: tdomnodelist;begin stream =
TStringStream.Create(testdata); try ReadHtmlFile(doc, stream);
els := doc.GetElementsByTagName('div'); ... finally
stream.Free; end;
----------------------------------------------------------------------
andriesh · 2020-05-01 09:25
Thanks for answer, but in stream need the file... how to achieve
this...
----------------------------------------------------------------------
bytebites · 2020-05-01 09:31
Code: Pascal [Select][+][-]window.onload = function(){var x1 =
document.getElementById("main_content_section"); if (x1) { var x =
document.getElementsByClassName("geshi");for (var i = 0; i stream =
TFileStream.Create(filename);
----------------------------------------------------------------------
andriesh · 2020-05-01 09:53
Oh... I do some wrong... Error...
Code: Pascal [Select][+][-]window.onload = function(){var x1 =
document.getElementById("main_content_section"); if (x1) { var x =
document.getElementsByClassName("geshi");for (var i = 0; i procedure
TForm1.Button1Click(Sender: TObject); var doc: thtmldocument;
stream: TStream; els: tdomnodelist;begin stream:=
TStringStream.Create('test.html'); try ReadHtmlFile(doc, stream);
els := doc.GetElementsByTagName('title');
ronBuy.Caption:=tdomelement(els[0]).TextContent; finally
stream.Free; end; end;
----------------------------------------------------------------------
wp · 2020-05-01 09:59
Why don't you do what people are advising you?
I told you to use the ReadHtmlFile() variant with a filename as
parameter, instead of a stream (the text following "BTW" was just a
comment on the code that you had shown). And bytebites told you to use
a TFileStream instead of a TStringstream. Both ways are correct.
What's wrong is using a TStringStream with a filename as parameter
because this stream type is designed such that the provided string,
'test.html', is passed to the ReadHtmlFile() command, not the CONTENTS
of the file.
----------------------------------------------------------------------
andriesh · 2020-05-01 10:07
I have an HTML file in the project folder (which I download when the
application starts), and I would like to extract some data (text) from
the file from certain tags so that I can insert it afterwards in the
Label. Maybe I didn't express myself correctly in the post. Forgive my
mistakes, I'm a beginner.
----------------------------------------------------------------------
wp · 2020-05-01 10:13
I know, communication sometimes is difficult in this medium. To be
more specific, this is the complete modification of your source code
according to my suggestion:
Code: Pascal [Select][+][-]window.onload = function(){var x1 =
document.getElementById("main_content_section"); if (x1) { var x =
document.getElementsByClassName("geshi");for (var i = 0; i uses
classes,sax_html,dom_html,dom; var doc: thtmldocument;
els: tdomnodelist; begin readhtmlfile(doc,'test.html');
els := doc.GetElementsByTagName('div'); if els.Count > 0 then
begin ronB1.Caption:=tdomelement(els[0]).getattribute('id');
ronB2.Caption:=tdomelement(els[0]).getattribute('multiple');
ronB3.Caption:=tdomelement(els[0]).textcontent); end; end.
And this is the idea of bytebites (which is exactly the same
internally):
Code: Pascal [Select][+][-]window.onload = function(){var x1 =
document.getElementById("main_content_section"); if (x1) { var x =
document.getElementsByClassName("geshi");for (var i = 0; i uses
classes,sax_html,dom_html,dom; var doc: thtmldocument;
els: tdomnodelist; stream: TStream; begin stream :=
TFileStream.Create('test.html', fmOpenRead); try
readhtmlfile(doc, stream); els :=
doc.GetElementsByTagName('div'); if els.Count > 0 then begin
ronB1.Caption:=tdomelement(els[0]).getattribute('id');
ronB2.Caption:=tdomelement(els[0]).getattribute('multiple');
ronB3.Caption:=tdomelement(els[0]).textcontent); end;
finally stream.Free; end; end.Unless there is a type
anywhere both versions should work.
----------------------------------------------------------------------
andriesh · 2020-05-01 10:26
Thanks a lot wp... But I still have error. I don't understand why it
doesn't work ... it's as if everything is clear but I still can't get
a result.
----------------------------------------------------------------------
wp · 2020-05-01 11:06
It probably depends on the html file. I only checked the html of your
1st post, and this is working. See attached project.
----------------------------------------------------------------------
andriesh · 2020-05-01 11:32
...yes is something wrong with my html wont work in your demo project
to.
I'm trying to make a currency converter for college. And I take the
currency data from a site that is saved as html. when application is
launching. I don't understand what's wrong with the html file ... but
it doesn't read in the written code. thank you for your time and help.
I may have to look for other ways ... I honestly don't know how yet.
p.s. i attached the html file (I changed the extension so that it can
be uploaded)
----------------------------------------------------------------------
andriesh · 2020-05-01 14:06
wp -> Can I have serve you a beer throw paypal? need your help...
----------------------------------------------------------------------
wp · 2020-05-01 14:22
Usually the html/xml parsers are very strict. So, when something is
not according to their likings, then they reject it.
Normally I work with the FastHtmlParser which is very simple. It scans
the input string character by character and detects tags (i.e. text
between (including) '<' and '>') and text (between '>' and '<',
without the brackets). In each case an event OnFoundTag or OnFoundText
is fired. The events get the tag/text as parameters. Then all you have
to do is to decide: is this tag/text interesting for me? and if yes,
what do I do with it.
In the attached demo I am analyzing your html file with the
fasthtmlparser, extracting the table and writing it to a StringGrid.
Studying your file, I see that the interesting part is the part
between '' tags. Therefore, there is a boolean
status variable FInTable which is set to true when the opening tag,
''
tag. As long as FInTable is false, the analysis of the other tags and
texts is skipped.
Now when the scanner is within a table, i.e. when FInTable is true, we
look for | (table header), | (table rows) and | (normal
cells) tags. At the end of a row ( |
tag), we increment a row
counter variable, at the end of a cell ( or tag) we
increment a column counter and write the collected text into a string
grid. (of course we must make sure that the grid has enought rows and
columns). The text is collected in the OnFoundText events.
Note that the demo provided is not perfect, it does not calculate the
column and row count correctly - I was too lazy to fix this. The zip
file contains also a local copy of the fasthtmlparser and htmlutil
units which is very helpful for debugging purposes.
----------------------------------------------------------------------
andriesh · 2020-05-01 14:54
WP thanks a lot for all, try to learn your code and put it in my
concept where every currency have dedicated TLabel. but sincerly is
complicated for me.....
P>S>send a private message. Thanks for your time.
----------------------------------------------------------------------
andriesh · 2020-05-01 16:03
I will probably give up the project ... It seemed so simple but ...
oops.'
----------------------------------------------------------------------
wp · 2020-05-01 16:39
Hey come on, don't give up. You almost have it... Really. Instead of
putting the number of the html table cells into cells of StringGrid,
put them into a 2d array. Add the titles of the HTML table to the bank
combobox. Then later, when the user selects an item from the bank
combo, copy the values of the selected bank into the labels.
----------------------------------------------------------------------
andriesh · 2020-05-02 02:12
Thanks WP for your support. What you sugest it's a bit complicated for
me if honestly,.. a simpler solution I'm thinking about is just to
take the data from StringGrid put it in the necessary TLabels and make
StringGrid invisible or place it in another inaccessible form. When
selecting the options from the ComboBox, the data from the chosen bank
cells will be loaded ... I know it's not correct, and not good
solution, but otherwise I don't really know how I could do it.
----------------------------------------------------------------------
wp · 2020-05-02 08:27
OK, that would be a very ugly solution. Suppose the 2d array is called
Data[x, y] of string. What is the difference in assigning a string
from the demo to Data[x, y] instead of assigning it to
StringGrid.Cells[col, row]? And what is the difference in extending
the grid's column count from expanding the array by calling Setlength?
But anyway. Stick to your idea and implement it. Just do something.
Otherwise I'd be getting the impression that you are waiting for
somebody else to do your college work.
----------------------------------------------------------------------
Bart · 2020-05-02 12:42
I have a TStringTable class you could maybe use. It's a non-visual
component.
Also a SimpleHtmlTablepParser unit.
It's all purpose made for my own needs, but probably simple to adopt
to your's.
Bart
----------------------------------------------------------------------
andriesh · 2020-05-04 18:29
Thank you all for your support and help, however I went with the ugly
solution, .. but in the end it was beautiful ... (just kidding).
There is still a small effort to make the project finished (max value
from two-dimensional array) but I hope to manage. Anyway, I'm not the
person who wants someone to do my homework... I just took on a pretty
difficult project for a beginner... and the hardest part was with
dataParsing from html... adding machine and design was the simplest
part.
Thanks again for your support and responsiveness.