Enable TXMLDocument in Vcl and FireMonkey applications XPath (selectNode, selectNodes) method

The TXMLDocument of classes allow you to manipulate XML files VCL and FireMonkey applications, but this class is no direct way to call the relevant method of XPath ( selectNode , the selectNodes ), so you have to write a set of auxiliary functions to call these methods .

Usually you can write something like

function selectSingleNode(ADOMDocument: IDOMDocument; const nodePath: WideString): IDOMNode;
var
  LDomNodeSelect : IDomNodeSelect;
begin
  if not Assigned(ADOMDocument) or not Supports(ADOMDocument.documentElement, IDomNodeSelect, LDomNodeSelect) then
   Exit;
  //or just LDomNodeSelect:= (ADOMDocument.documentElement as IDOMNodeSelect);
  Result:=LDomNodeSelect.selectNode(nodePath);
end;
function SelectNodes(ADOMDocument: IDOMDocument; const nodePath: WideString): IDOMNodeList; var LDomNodeSelect : IDomNodeSelect; begin if not Assigned(ADOMDocument) or not Supports(ADOMDocument.documentElement, IDomNodeSelect, LDomNodeSelect) then Exit; //or just LDomNodeSelect:= (ADOMDocument.documentElement as IDOMNodeSelect); Result:=LDomNodeSelect.selectNodes(nodePath); end;

 

And used like this:

var
  XmlDoc: IXMLDocument;
  LNode : IDOMNode;
  i : Integer;
begin
  XmlDoc := TXMLDocument.Create(nil);
  XmlDoc.Active := True;
  XmlDoc.Options := XmlDoc.Options + [doNodeAutoIndent];
  XmlDoc.Version := '1.0';
  ...
  ...
  LNode:=selectSingleNode(XmlDoc.DOMDocument,XPathExpr);

The above code used in Windows MSXML provider as the default DOM vendors can work, but must run in OSX and Windows in the FireMonkey application, you must be the default DOM vendor set to ADOM (OpenXML).

DefaultDOMVendor := OpenXML4Factory.Description;

Now, if you try to use these functions (selectSingleNode, SelectNodes) in ADOM provider, you will get a very good exception

EOleException Catastrophic failure 8000FFFF

The root of this problem is Tox4DOMNode.selectNode and Tox4DOMNode.selectNodes implementation of these methods, please check the next code.

function Tox4DOMNode.selectNode(const nodePath: WideString): IDOMNode;
var
  xpath: TXpathExpression;
  xdomText: TDomText;
begin
  Result := nil;
  if not Assigned(WrapperDocument) or not Assigned(WrapperDocument.WrapperDOMImpl) then
    Exit;
 
  xpath := WrapperDocument.WrapperDOMImpl.FXpath; //here the xpath is set with a nil value because the FXpath was no initialized  
  xpath.ContextNode := NativeNode; //Here the App crash because xpath is nil

FXpath field Tox4DOMImplementation.InitParserAgent method is initialized, the method is never called you Tox4DOMImplementation.loadFromStream or Tox4DOMImplementation.loadxml method approach. Therefore, to solve this problem, you must call before calling selectNode and selectNodes method Tox4DOMImplementation.InitParserAgent function.

function selectSingleNode(ADOMDocument: IDOMDocument; const nodePath: WideString): IDOMNode;
var
  LDomNodeSelect : IDomNodeSelect;
begin
  if not Assigned(ADOMDocument) or not Supports(ADOMDocument.documentElement, IDomNodeSelect, LDomNodeSelect) then
   Exit;
  //or just LDomNodeSelect:= (ADOMDocument.documentElement as IDOMNodeSelect);
  if (DefaultDOMVendor = OpenXML4Factory.Description) then
    Tox4DOMNode(LDomNodeSelect).WrapperDocument.WrapperDOMImpl.InitParserAgent;
  Result:=LDomNodeSelect.selectNode(nodePath);
end;
function SelectNodes(ADOMDocument: IDOMDocument; const nodePath: WideString): IDOMNodeList; var LDomNodeSelect : IDomNodeSelect; begin if not Assigned(ADOMDocument) or not Supports(ADOMDocument.documentElement, IDomNodeSelect, LDomNodeSelect) then Exit; //or just LDomNodeSelect:= (ADOMDocument.documentElement as IDOMNodeSelect); if (DefaultDOMVendor = OpenXML4Factory.Description) then Tox4DOMNode(LDomNodeSelect).WrapperDocument.WrapperDOMImpl.InitParserAgent; Result:=LDomNodeSelect.selectNodes(nodePath); end;

By now these changes, you will be able to use ADOM supplier evaluation XPath expression VCL and FireMonkey applications.

This is a demo console application testing in Windows and OSX (Delphi 10.3.2 Rio):

  1 // reference  https://theroadtodelphi.wordpress.com/2013/05/29/enabling-xpath-selectnode-selectnodes-methods-in-vcl-and-firemonkey-apps/
  2 
  3 {$APPTYPE CONSOLE}
  4 uses
  5 {$IFDEF MSWINDOWS}
  6   System.Win.ComObj,
  7   Winapi.ActiveX,
  8 {$ENDIF}
  9   System.SysUtils,
 10   Xml.XMLIntf,
 11   Xml.adomxmldom,
 12   Xml.XMLDom,
 13   Xml.XMLDoc;
 14 
 15 function selectSingleNode(ADOMDocument: IDOMDocument; const nodePath: WideString): IDOMNode;
 16 var
 17   LDomNodeSelect: IDomNodeSelect;
 18 begin
 19   if not Assigned(ADOMDocument) or not Supports(ADOMDocument.documentElement, IDomNodeSelect, LDomNodeSelect) then
 20     Exit;
 21   // or just LDomNodeSelect:= (ADOMDocument.documentElement as IDOMNodeSelect);
 22   if (DefaultDOMVendor = OpenXML4Factory.Description) then
 23     Tox4DOMNode(LDomNodeSelect).WrapperDocument.WrapperDOMImpl.InitParserAgent;
 24   Result := LDomNodeSelect.selectNode(nodePath);
 25 end;
 26 
 27 function SelectNodes(ADOMDocument: IDOMDocument; const nodePath: WideString): IDOMNodeList;
 28 var
 29   LDomNodeSelect: IDomNodeSelect;
 30 begin
 31   if not Assigned(ADOMDocument) or not Supports(ADOMDocument.documentElement, IDomNodeSelect, LDomNodeSelect) then
 32     Exit;
 33   // or just LDomNodeSelect:= (ADOMDocument.documentElement as IDOMNodeSelect);
 34   if (DefaultDOMVendor = OpenXML4Factory.Description) then
 35     Tox4DOMNode(LDomNodeSelect).WrapperDocument.WrapperDOMImpl.InitParserAgent;
 36   Result := LDomNodeSelect.SelectNodes(nodePath);
 37 end;
 38 
 39 procedure TestXPath;
 40 var
 41   XMLDoc: IXMLDocument;
 42   Root, Book, Author, Publisher: IXMLNode;
 43   LNodeList: IDOMNodeList;
 44   LNode: IDOMNode;
 45   i: Integer;
 46 begin
 47   XMLDoc := TXMLDocument.Create(nil);
 48   XMLDoc.Active := True;
 49   XMLDoc.Options := XMLDoc.Options + [doNodeAutoIndent];
 50   XMLDoc.Version := '1.0';
 51 
 52   Root := XMLDoc.CreateNode('BookStore');
 53   Root.Attributes['url'] := 'http://www.amazon.com';
 54   XMLDoc.documentElement := Root;
 55 
 56   Book := XMLDoc.CreateNode('Book');
 57   Book.Attributes['Name'] := 'Steve Jobs';
 58   Author := XMLDoc.CreateNode('Author');
 59   Author.Text := 'Walter Isaacson';
 60   Publisher := XMLDoc.CreateNode('Publisher');
 61   Publisher.Text := 'Simon Schuster (October 24, 2011)';
 62   Root.ChildNodes.Add(Book);
 63   Book.ChildNodes.Add(Author);
 64   Book.ChildNodes.Add(Publisher);
 65 
 66   Book := XMLDoc.CreateNode('Book');
 67   Book.Attributes['Name'] := 'Clean Code: A Handbook of Agile Software Craftsmanship';
 68   Author := XMLDoc.CreateNode('Author');
 69   Author.Text := 'Robert C. Martin';
 70   Publisher := XMLDoc.CreateNode('Publisher');
 71   Publisher.Text := 'Prentice Hall; 1 edition (August 11, 2008)';
 72   Root.ChildNodes.Add(Book);
 73   Book.ChildNodes.Add(Author);
 74   Book.ChildNodes.Add(Publisher);
 75 
 76   Book := XMLDoc.CreateNode('Book');
 77   Book.Attributes['Name'] := 'Paradox Lost';
 78   Author := XMLDoc.CreateNode('Author');
 79   Author.Text := 'Kress, Peter';
 80   Publisher := XMLDoc.CreateNode('Publisher');
 81   Publisher.Text := 'Prentice Hall; 1 edition (February 2, 2000)';
 82   Root.ChildNodes.Add(Book);
 83   Book.ChildNodes.Add(Author);
 84   Book.ChildNodes.Add(Publisher);
 85 
 86   Writeln(XMLDoc.Xml.Text);
 87 
 88   Writeln('selectSingleNode');
 89   LNode := selectSingleNode(XMLDoc.DOMDocument, '/BookStore/Book[2]/Author["Robert C. Martin"]');
 90   if LNode <> nil then
 91     Writeln(LNode.firstChild.nodeValue);
 92 
 93   Writeln;
 94 
 95   Writeln('SelectNodes');
 96   LNodeList := SelectNodes(XMLDoc.DOMDocument, '//BookStore/Book/Author');
 97   if LNodeList <> nil then
 98     for i := 0 to LNodeList.length - 1 do
 99       Writeln(LNodeList[i].firstChild.nodeValue);
100 end;
101 
102 begin
103   try
104     ReportMemoryLeaksOnShutdown := True;
105     DefaultDOMVendor := OpenXML4Factory.Description;
106 {$IFDEF MSWINDOWS}CoInitialize(nil); {$ENDIF}
107     try
108       TestXPath;
109     finally
110 {$IFDEF MSWINDOWS}CoUninitialize; {$ENDIF}
111     end;
112   except
113 {$IFDEF MSWINDOWS}
114     on E: EOleException do
115       Writeln(Format('EOleException %s %x', [E.Message, E.ErrorCode]));
116 {$ENDIF}
117     on E: Exception do
118       Writeln(E.Classname, ':', E.Message);
119   end;
120   Writeln;
121   Writeln('Press Enter to exit');
122   Readln;
123 
124 end.

Guess you like

Origin www.cnblogs.com/rtcmw/p/11095993.html