XML,NextSibling 我做 NodeAutoIndent。空(#9)节点问题

XML, NextSibling i doNodeAutoIndent. Empty (#9) nodes problem

我的代码是:

  XmlDoc := NewXMLDocument;
  with XmlDoc do
    Options := Options + [doNodeAutoIndent];
[...]
  N := Parent.ChildNodes.FindNode('KONTRAHENT');
  while N <> nil do
  begin
    if N.ChildNodes['ID_KONTRAHENTA'].NodeValue = KontrNr then
      DoSomething;
    N := N.NextSibling;
  end;

和XML像这样:

<KARTOTEKA_KONTRAHENTOW>
   <KONTRAHENT>
      <ID_KONTRAHENTA>925</ID_KONTRAHENTA>
   </KONTRAHENT>
   <KONTRAHENT>
      <ID_KONTRAHENTA>1208</ID_KONTRAHENTA>
   </KONTRAHENT>
</KARTOTEKA_KONTRAHENTOW>

在 Watch Parent.XML 中查看的数据如下:

'<KARTOTEKA_KONTRAHENTOW>'#$D#$A#9#9'<KONTRAHENT>'#$D#$A#9#9#9'<ID_KONTRAHENTA>925</ID_KONTRAHENTA>'#$D#$A#9#9'</KONTRAHENT>'#$D#$A#9#9'<KONTRAHENT>'#$D#$A#9#9#9'<ID_KONTRAHENTA>1208</ID_KONTRAHENTA>'#$D#$A#9#9'</KONTRAHENT>'#$D#$A#9'</KARTOTEKA_KONTRAHENTOW>'

当我在循环中读取节点时,设置选项:[doNodeAutoIndent] 然后我有一些这样的节点:N = '#$D#$A#9#9' 和节点数 = 7(而不是 2,在这个例子中)

没有 doNodeAutoIndent,一切正常,节点数 = 2,但我的 XML 文件在一行中:(

问题是: 如何在启用 doNodeAutoIndent 时绕过空的 NextSibling?

您所描述的完全正常。元素之间的空白被视为层次结构中的附加文本节点,例如,对于您的示例 XML,其 DOM 树如下所示:

KARTOTEKA_KONTRAHENTOW
|_ '#$D#$A#9#9'
|_ KONTRAHENT
|  |_ '#$D#$A#9#9#9'
|  |_ ID_KONTRAHENTA
|  |  |_ '925'
|  |_ '#$D#$A#9#9'
|_ '#$D#$A#9#9'
|_ KONTRAHENT
|  |_ '#$D#$A#9#9#9'
|  |_ ID_KONTRAHENTA
|  |  |_ '1208'
|  |_ '#$D#$A#9#9'
|_ '#$D#$A#9'

这就是节点数高于您预期的原因。

您需要在遍历元素时考虑这些额外的文本节点,例如:

N := Parent.ChildNodes.First;
while N <> nil do
begin
  if (N.NodeType = ntElement) and (N.NodeName = 'KONTRAHENT') then
  begin
    if N.ChildNodes['ID_KONTRAHENTA'].NodeValue = KontrNr then
    begin
      // Do something with N ...
    end;
  end;
  N := N.NextSibling;
end;

或者,使用 XPath 查询来只关注您真正需要的节点,例如:

uses
  ..., XmlIntf, XmlDom;

var
  ...
  XPath: IDOMNodeSelect;
  Nodes: IDOMNodeList;
  N: IDOMNode;
  I: Integer;

...

if Supports(Parent.DOMNode, IDOMNodeSelect, XPath) then
begin
  Nodes := XPath.selectNodes('KONTRAHENT[ID_KONTRAHENTA='+IntToStr(KontrNr)+']');
  for I := 0 to Nodes.length-1 do
  begin
    N := Nodes[i];
    // do something with N ...
  end;
end else
begin
  // code shown above ...
end;