在Vcl和FireMonkey应用程序中启用TXMLDocument 的XPath(selectNode,selectNodes)方法

TXMLDocument的类让你来操作VCL和FireMonkey应用程序的XML文件,但这个类没有实现直接的方式来调用XPath的相关方法(selectNode的selectNodes),所以你必须编写一组辅助函数来调用这些方法。

通常你可以写这样的东西

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;

 

并这样使用:

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);

上面的代码在Windows下使用MSXML提供程序作为默认DOM供应商可以正常工作,但在必须在OSX和Windows中运行FireMonkey应用程序中,必须将默认DOM供应商设置为ADOM(OpenXML)。

DefaultDOMVendor := OpenXML4Factory.Description;

现在,如果您尝试在ADOM供应商下使用上述功能(selectSingleNode,SelectNodes),您将获得一个非常好的例外

EOleException Catastrophic failure 8000FFFF

这个问题的根目录是Tox4DOMNode.selectNodeTox4DOMNode.selectNodes这些方法的实现,请检查下一个代码。

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字段在Tox4DOMImplementation.InitParserAgent方法中初始化,该方法永远不会调用您使用Tox4DOMImplementation.loadFromStreamTox4DOMImplementation.loadxml方法的方法。因此,要解决此问题,必须在调用selectNode和selectNodes方法之前调用Tox4DOMImplementation.InitParserAgent函数。

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;

现在通过这些更改,您将能够使用ADOM供应商评估VCL和FireMonkey应用程序中的XPath表达式。

这是在Windows和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.
posted @ 2019-06-27 11:23  塞翁失身  阅读(492)  评论(0编辑  收藏  举报