该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.selectNode和Tox4DOMNode.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.loadFromStream或Tox4DOMImplementation.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.
来源:oschina
链接:https://my.oschina.net/u/4366528/blog/3485670