我碰到a question about XPath and Delphi TXmlDocument。
尽管选择单个xml节点的答案很好,但我想用它来选择节点列表。
我发现了一个similar utility function应该可以做到这一点,但是它不能正常工作。
显然是 buggy 的功能:
uses
Xml.Xmldom, Xml.XMLIntf, Xml.XMLDoc;
function SelectNodes(xnRoot: IXmlNode; const nodePath: WideString): IXMLNodeList;
var
intfSelect : IDomNodeSelect;
intfAccess : IXmlNodeAccess;
dnlResult : IDomNodeList;
intfDocAccess : IXmlDocumentAccess;
doc: TXmlDocument;
i : Integer;
dn : IDomNode;
begin
Result := nil;
if not Assigned(xnRoot)
or not Supports(xnRoot, IXmlNodeAccess, intfAccess)
or not Supports(xnRoot.DOMNode, IDomNodeSelect, intfSelect) then
Exit;
dnlResult := intfSelect.selectNodes(nodePath);
if Assigned(dnlResult) then
begin
Result := TXmlNodeList.Create(intfAccess.GetNodeObject, '', nil);
if Supports(xnRoot.OwnerDocument, IXmlDocumentAccess, intfDocAccess) then
doc := intfDocAccess.DocumentObject
else
doc := nil;
for i := 0 to dnlResult.length - 1 do
begin
dn := dnlResult.item[i];
Result.Add(TXmlNode.Create(dn, nil, doc));
end;
end;
end;
一个简化版本,不使用
IXMLNodeList
,而是使用“raw” IDomNodeList
:function SimpleSelectNodes(xnRoot: IXmlNode; const nodePath: WideString): IDOMNodeList;
var
intfSelect : IDomNodeSelect;
begin
Result := nil;
if not Assigned(xnRoot)
or not Supports(xnRoot.DOMNode, IDomNodeSelect, intfSelect) then
Exit;
Result := intfSelect.selectNodes(nodePath);
end;
测试代码:
procedure TForm1.FormCreate(Sender: TObject);
var
Doc: IXMLDocument;
Root: IXMLNode;
DomNodeList: IDomNodeList;
XmlNodeList: IXMLNodeList;
XmlNode : IXMLNode;
I: Integer;
begin
// Build a test DOM tree in memory
Doc := NewXMLDocument;
Root := Doc.AddChild('root');
Root.AddChild('C1');
Root.AddChild('C2');
Root.AddChild('C3');
// Select using the IDomNodeList interface
DomNodeList := SimpleSelectNodes(Root, '/root/*');
for I := 0 to DomNodeList.length - 1 do
ShowMessage(DomNodeList.item[I].nodeName);
// Select using the IXMLNodeList interface
XmlNodeList := SelectNodes(Root, '/root/*');
XmlNode := XmlNodeList.First;
while XmlNode <> nil do
begin
ShowMessage(XmlNode.NodeName);
XmlNode := XmlNode.NextSibling;
end;
end;
虽然
SimpleSelectNodes
版本可以正常工作,但SelectNodes
函数却不能。它返回一个
IXMLNodeList
,但是当我尝试实际遍历此列表时,我只得到第一项,NextSibling
是nil
。我如何才能使
IXMLNodeList
正常工作? 最佳答案
我遇到了同样的问题(使用基本相同的代码)。
我能解决的唯一方法是按索引遍历节点,因为NextSibling
每次都会出于某些原因返回nil。像这样的作品:
var
i: Integer;
Nodes: IXMLNodeList;
Node: IXMLNode;
begin
Nodes := SelectNodes(...);
for i := 0 to NodeList.Count - 1 do
begin
Node := NodeList.Nodes[i];
// Process node
end;
end;