Pertanyaan Bagaimana saya bisa mendapatkan IXMLNodeList dari seleksi XPath?


Saya datang pertanyaan tentang XPath dan Delphi TXmlDocument.

Sementara jawabannya berfungsi dengan baik untuk memilih simpul xml tunggal, saya ingin menggunakannya untuk memilih daftar node.

saya menemukan sebuah fungsi utilitas serupa yang seharusnya melakukan hal itu, tetapi tidak berfungsi dengan benar.

Fungsi yang tampaknya bermasalah:

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;

Versi yang disederhanakan yang tidak menggunakan IXMLNodeList, tetapi "mentah" IDomNodeList sebagai gantinya:

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;

Kode pengujian:

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;

Selagi SimpleSelectNodes versi berfungsi dengan baik, SelectNodes fungsi tidak.

Ini mengembalikan a IXMLNodeList, tetapi ketika saya mencoba untuk benar-benar mengulang melalui daftar ini, saya hanya mendapatkan item pertama, NextSibling aku s nil.

Bagaimana saya bisa mendapatkan IXMLNodeList bekerja?


5
2018-04-28 11:19


asal


Jawaban:


Saya memiliki masalah yang sama (dengan kode yang pada dasarnya sama).

Satu-satunya cara saya bisa menyelesaikannya adalah dengan mengiterasi node melalui index, seperti NextSibling mengembalikan nil untuk beberapa alasan setiap saat. Sesuatu seperti ini berfungsi:

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;

2
2018-04-28 12:40