Extract XPath from HTML in the format "/html/body/div[1]/main/div[2]"
lazarus / 21-General
----------------------------------------------------------------------
Mig.BR · 2022-07-02 23:38
Is there any way native to FPC (without third party libraries) to
extract the contents of an HTML based on the Full XPath returned by
browsers?
E.g.:
/html/body/div[1]/main/div[2]/div[2]/div[2]/div/div[1]
I tested many ways found on the forum like EvaluateXPathExpression but
could not get it to work for this XPath format.
I found a lot of documentation for XML but nothing that works properly
for HTML.
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
sRetText, sIdHTTPText: String; Doc: THTMLDocument; XPathResult:
TXPathVariable; Stream: TStringStream;begin ... try Stream
:= TStringStream.Create(sIdHTTPText); ReadHTMLFile(Doc,
Stream); XPathResult := EvaluateXPathExpression('/html/body/div[1
]/main/div[2]/div[2]/div[2]/div/div[1]', Doc.DocumentElement);
sRetText := String(XPathResult.AsText); finally
XPathResult.Free; Doc.Free; Stream.Free; end; ...end;
----------------------------------------------------------------------
dje · 2022-07-03 00:53
sax_html is a subset/minimal html parser. ie: any unknown tags are
ignored and not added to the document.
You can use something like this to show a THTMLDocument structure in a
TTreeView:
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
TreeViewAddDOMNode(ATreeView: TTreeView; AParent: TTreeNode; ADOMNode:
TDOMNode);var LIndex: integer;begin AParent :=
ATreeView.Items.AddChild(AParent, ADOMNode.NodeName + ' = ' +
Trim(ADOMNode.TextContent)); for LIndex := 0 to
ADOMNode.ChildNodes.Count - 1 do begin
TreeViewAddDOMNode(ATreeView, AParent, ADOMNode.ChildNodes[LIndex]);
end;end;
Call the code with:
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
TreeViewAddDOMNode(Form1.TreeView1, nil,
LHTMLDocument.DocumentElement);
You should see nodes missing and the nodes available.
Using a XPath for the subset document tree does work, although it
might not be the answer you want.
----------------------------------------------------------------------
PascalDragon · 2022-07-03 12:21
Quote from: Miguel.BR on July 03, 2022, 01:38:07 amIs there any way
native to FPC (without third party libraries) to extract the contents
of an HTML based on the Full XPath returned by browsers?
E.g.:
/html/body/div[1]/main/div[2]/div[2]/div[2]/div/div[1]
I tested many ways found on the forum like EvaluateXPathExpression but
could not get it to work for this XPath format.
I found a lot of documentation for XML but nothing that works properly
for HTML.
Do you have an example of the HTML in question? Can you provide a full
example of what you tried with EvaluateXPathExpression? Does it work
correctly if you convert your example HTML to XML?
----------------------------------------------------------------------
Mig.BR · 2022-07-03 23:31
First I want to thank everyone who tried to help.
Initially I had no return due to the fact that the HTML came with only
the content inside the
... and not the entire HTML.
My main problem was extracting text with line breaks
that where
suppressed and with special characters on some sites.
derek.john.evans, I liked the tree idea for exploring the content of
an HTML.
PascalDragon, your request for an HTML example made me realize that in
another part of the application I was clipping part of the HTML
content and was only parsing the content inside the . For this
reason I always got null returns.
Below is the code: It might be useful for someone.
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 function
ExtractHTMLXPath(sHTML, sXPath: String): String;var vlDoc:
THTMLDocument; vlXPathResult: TXPathVariable; vlStream:
TStringStream;begin Result := ''; try sHTML :=
StringReplace(sHTML, '
', '
'+LineEnding, [rfReplaceAll]);
vlStream := TStringStream.Create(sHTML); ReadHTMLFile(vlDoc,
vlStream); vlXPathResult :=
EvaluateXPathExpression(UTF8ToUTF16(sXPath), vlDoc.DocumentElement);
Result := UTF16ToUTF8(vlXPathResult.AsText); finally
vlXPathResult.Free; vlDoc.Free; vlStream.Free; end;end;
----------------------------------------------------------------------
PascalDragon · 2022-07-04 11:31
Quote from: Miguel.BR on July 04, 2022, 01:31:31 amPascalDragon, your
request for an HTML example made me realize that in another part of
the application I was clipping part of the HTML content and was only
parsing the content inside the . For this reason I always got
null returns.
So to clarify: it's working correctly now for you?
Quote from: Miguel.BR on July 04, 2022, 01:31:31 amBelow is the code:
It might be useful for someone.
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 function
ExtractHTMLXPath(sHTML, sXPath: String): String;var vlDoc:
THTMLDocument; vlXPathResult: TXPathVariable; vlStream:
TStringStream;begin Result := ''; try sHTML :=
StringReplace(sHTML, '
', '
'+LineEnding, [rfReplaceAll]);
vlStream := TStringStream.Create(sHTML); ReadHTMLFile(vlDoc,
vlStream); vlXPathResult :=
EvaluateXPathExpression(UTF8ToUTF16(sXPath), vlDoc.DocumentElement);
Result := UTF16ToUTF8(vlXPathResult.AsText); finally
vlXPathResult.Free; vlDoc.Free; vlStream.Free; end;end;
You should initialize vlXPathResult, vlDoc and vlStream to Nil at the
start of the function as otherwise if e.g. ReadHTMLFile fails with an
exception vlXPathResult will (still) contain garbage and thus lead to
another exception when calling vlXPathResult.Free.
----------------------------------------------------------------------
Mig.BR · 2022-07-04 17:57
Yes, PascalDragon, that way worked perfectly.
I added another StringReplace to handle the line breaks
(with
space between
).
Thanks for the tip to initialize the classes with nil, I would only
run into that problem the moment this would return an exception.
I also liked the tip on converting HTML to XML. I will test that one
too as it may come in handy in the future.
Thanks again for your help.
----------------------------------------------------------------------
Mig.BR · 2022-07-07 04:58
Quote from: PascalDragon on July 04, 2022, 01:31:35 pmSo to clarify:
it's working correctly now for you?
It seems that my happiness was short-lived. I just came across my
first XHTML and again I didn't get any return. I tried the most
diverse modifications, but all without result.
Apparently EvaluateXPathExpression can't extract anything of this
type. I even tried the XHTML unit but it seems incomplete.
Any idea how to use EvaluateXPathExpression to extract from XHTMLs or
is it not implemented yet?
e.g.:
Code: HTML5 [Select][+][-]window.onload = function(){var x1 =
document.getElementById("main_content_section"); if (x1) { var x =
document.getElementsByClassName("geshi");for (var i = 0; i ...
It has no , or . How could I convert this to
HTML or XML?
Validator.w3.org found 26 errors on this page. Is there a way around
this or just brute force?
----------------------------------------------------------------------
PascalDragon · 2022-07-07 11:50
Quote from: Miguel.BR on July 07, 2022, 06:58:05 amQuote from:
PascalDragon on July 04, 2022, 01:31:35 pmSo to clarify: it's working
correctly now for you?
It seems that my happiness was short-lived. I just came across my
first XHTML and again I didn't get any return. I tried the most
diverse modifications, but all without result.
Apparently EvaluateXPathExpression can't extract anything of this
type. I even tried the XHTML unit but it seems incomplete.
Any idea how to use EvaluateXPathExpression to extract from XHTMLs or
is it not implemented yet?
e.g.:
Code: HTML5 [Select][+][-]window.onload = function(){var x1 =
document.getElementById("main_content_section"); if (x1) { var x =
document.getElementsByClassName("geshi");for (var i = 0; i ...
It has no ,