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 '' and '
' 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 rows) and 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.
(table header),
(normal cells) tags. At the end of a row (