为什么XmlNodeList.count变为0?

问题描述 投票:1回答:1

我有一个xml文档,我正在尝试将节点彼此分离。我只希望根节点,然后只希望第二个节点,然后是第二个节点内存在的节点列表。我遇到了一个问题,当我从第二个节点或主节点中删除节点时,我的列表变为空。我不明白为什么会发生这种情况,尤其是由于以下这种奇怪的行为。

  class Program
{
    static void Main(string[] args)
    {
        XmlDocument doc = new XmlDocument();

        doc.Load(@"C:\Users\Username\Desktop\Diagram.xml");

        XmlNode rootNode = doc.DocumentElement;
        XmlNode secondNode = doc.SelectSingleNode(rootNode.Name + "/root");

        XmlNodeList nodelist = doc.SelectNodes("//root/mxCell");


        Console.WriteLine("-----------------------------------------");
        Console.WriteLine(RemoveChildren(rootNode).OuterXml);
        Console.WriteLine("-----------------------------------------");
       Console.WriteLine(RemoveChildren(secondNode).OuterXml);
        Console.WriteLine("-----------------------------------------");
        //Console.WriteLine(rootNode.OuterXml);
        Console.WriteLine(nodelist.Count); //Becomes 0
        if (nodelist != null && nodelist.Count > 0)
        {

            foreach (XmlNode n in nodelist)
            {

                Console.WriteLine(n.OuterXml);

            }

        }


        Console.ReadLine();
    }

    private static XmlNode RemoveChildren(XmlNode n) {

        while (n.FirstChild != null)
        {
            n.RemoveChild(n.FirstChild);
        }

        return n;
    }
}

如果运行此代码,我的nodelist.count将变为0。为什么节点列表变为0,但是为什么我仍然可以访问第二个节点?

enter image description here

但是,如果我在doc.SelectNodes(“ // root / mxCell”)之后添加foreach循环;计数将变为4。

像这样,

static void Main(string[] args)
    {
        XmlDocument doc = new XmlDocument();

        doc.Load(@"C:\Users\Username\Desktop\Diagram.xml");

        XmlNode rootNode = doc.DocumentElement;
        XmlNode secondNode = doc.SelectSingleNode(rootNode.Name + "/root");

        XmlNodeList nodelist = doc.SelectNodes("//root/mxCell");

        if (nodelist != null && nodelist.Count > 0)
        {

            foreach (XmlNode n in nodelist)
            {

                Console.WriteLine(n.OuterXml);

            }

        }



        Console.WriteLine("-----------------------------------------");
        Console.WriteLine(RemoveChildren(rootNode).OuterXml);
        Console.WriteLine("-----------------------------------------");
       Console.WriteLine(RemoveChildren(secondNode).OuterXml);
        Console.WriteLine("-----------------------------------------");
        //Console.WriteLine(rootNode.OuterXml);
        Console.WriteLine(nodelist.Count); //Becomes 4
        if (nodelist != null && nodelist.Count > 0)
        {

            foreach (XmlNode n in nodelist)
            {

                Console.WriteLine(n.OuterXml);

            }

        }


        Console.ReadLine();
    }

    private static XmlNode RemoveChildren(XmlNode n) {

        while (n.FirstChild != null)
        {
            n.RemoveChild(n.FirstChild);
        }

        return n;
    }
}

现在计数为4。

enter image description here

这里是使用的xml:

<mxGraphModel dx="1086" dy="596" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="850" pageHeight="1100" math="0" shadow="0">
  <root>
    <mxCell id="0"/>
    <mxCell id="1" parent="0"/>
    <mxCell id="YJb7HCrh72y2aGPrfETQ-1" value="" style="endArrow=classic;html=1;" parent="1" edge="1">
      <mxGeometry width="50" height="50" relative="1" as="geometry">
        <mxPoint x="130" y="310" as="sourcePoint"/>
        <mxPoint x="180" y="260" as="targetPoint"/>
      </mxGeometry>
    </mxCell>
    <mxCell id="YJb7HCrh72y2aGPrfETQ-2" value="" style="endArrow=classic;html=1;" parent="1" edge="1">
      <mxGeometry width="50" height="50" relative="1" as="geometry">
        <mxPoint x="290" y="270" as="sourcePoint"/>
        <mxPoint x="340" y="220" as="targetPoint"/>
      </mxGeometry>
    </mxCell>
  </root>
</mxGraphModel>
c# xml xmlnode xmlnodelist
1个回答
0
投票

您正在观察的行为可以更简单地说明如下。以下单元测试将成功(演示小提琴here):

XmlNodeList nodelist = doc.SelectNodes("*/*"); // Select all children of the root node
RemoveChildren(doc.DocumentElement);
Assert.IsTrue(nodelist.Count == 0); // Passes

虽然以下操作将失败:

XmlNodeList nodelist = doc.SelectNodes("*/*"); // Select all children of the root node
Assert.IsTrue(nodelist.Count > 0);  // Passes
RemoveChildren(doc.DocumentElement);
Assert.IsTrue(nodelist.Count == 0); // FAILS!?

为什么在删除某些节点之前仅添加nodelist.Count会导致在删除节点后nodelist的内容不一致?

事实证明,在这种情况下XmlNodeList返回的SelectNodes()没有指定的行为。来自documentation remarks for XmlNode.SelectNodes()

此方法返回的XmlNode.SelectNodes()对象将在基础文档保持不变的情况下有效。 如果基础文档发生更改,则可能会返回意外结果(不会引发异常)。>

此类“意外结果”就是您正在观察的。一旦XmlNodeList被调用,.Net将不会指定或保证XmlNodeList的内容。 (实际上,返回的RemoveChildren()似乎使用lazy Evaluation

机制。一旦对节点列表进行计数或迭代(但不是在此之前),XPath查询将被评估一次,并且仅评估一次,并且结果已缓存并随后重用。)

此XPath查询返回的节点列表的文档限制与nodelist的常规文档相反,该文档指出:

对创建XmlNodeList集合的节点对象的子项的更改将立即反映在XmlNodeList属性和方法返回的节点中。

此注释似乎仅适用于XmlNodeList DOM对象的方法返回的XmlNodeList子列表。

© www.soinside.com 2019 - 2024. All rights reserved.