Node.SelectNodes(/ *)和Node.childNodes有什么区别?

时间:2012-06-28 05:30:48

标签: c# xml xpath

        string XML1 = "<Root><InsertHere></InsertHere></Root>";
        string XML2 = "<Root><child1><childnodes>data</childnodes><childnodes>data1</childnodes></child1><child2><childnodes>data</childnodes><childnodes>data1</childnodes></child2></Root>";

在下面提到的两个代码示例中.childNodes的使用不会从XML2复制所有子节点。仅复制<child1>

        string strXpath = "/Root/InsertHere";

        XmlDocument xdxmlChildDoc = new XmlDocument();
        XmlDocument ParentDoc = new XmlDocument();
        ParentDoc.LoadXml(XML1);
        xdxmlChildDoc.LoadXml(XML2);

        XmlNode xnNewNode = ParentDoc.ImportNode(xdxmlChildDoc.DocumentElement.SelectSingleNode("/Root"), true);

        if (xnNewNode != null)
        {
            XmlNodeList xnChildNodes = xnNewNode.SelectNodes("/*");
            if (xnChildNodes != null)
            {
                foreach (XmlNode xnNode in xnChildNodes)
                {
                    if (xnNode != null)
                    {
                        ParentDoc.DocumentElement.SelectSingleNode(strXpath).AppendChild(xnNode);
                    }
                }
            }
        }

码2:

    if (xnNewNode != null)
    {
        XmlNodeList xnChildNodes = xnNewNode.ChildNodes;
        if (xnChildNodes != null)
        {
            foreach (XmlNode xnNode in xnChildNodes)
            {
                if (xnNode != null)
                {
                    ParentDoc.DocumentElement.SelectSingleNode(strXpath).AppendChild(xnNode);
                }
            }
        }
    }
执行第一个代码示例后,

ParentDoc.OuterXML:

<Root>
    <InsertHere>
        <child1>
            <childnodes>data</childnodes>
            <childnodes>data1</childnodes>
        </child1>
        <child2>
            <childnodes>data</childnodes>
            <childnodes>data1</childnodes>
        </child2>
    </InsertHere>
</Root>
执行Code

的第二个示例后,

ParentDoc.OuterXML

<Root>
    <InsertHere>
        <child1>
            <childnodes>data</childnodes>
            <childnodes>data1</childnodes>
        </child1>
    </InsertHere>
</Root>

4 个答案:

答案 0 :(得分:3)

我已经对代码进行了一些调试,它表明xnNewNode.ChildNodes最初也会返回2个子节点。在循环中进行一次迭代后,第一个子项将从ChildNodes中删除,因此循环过早结束。

如果要使用ChildNodes属性,一种解决方法是将子节点引用“转移”到数组或列表,如下所示:

var xnChildNodes = xnNewNode.ChildNodes.Cast<XmlNode>().ToArray();

<强>更新

正如Tomer W在他的回答中指出的那样,当使用XmlNode.AppendChild时,插入的节点也会从其原始位置移除。如MSDN文档中所述:

If the newChild is already in the tree, it is removed from 
its original position and added to its target position.

使用SelectNodes您已经创建了一个新的节点集合,但是ChildNodes您正在访问原始集合。

答案 1 :(得分:1)

这是Anders G发布的内容的清除,更多的解释。

我很惊讶foreach在这种情况下没有失败(抛出异常),但是地狱。

在code1。
1.创建新的节点集合
2.选择节点
3.追加到其他节点=&gt;从原始集合中删除,但不删除新创建的集合 4您要从新集合中删除要添加的节点。

Code2中的

1.引用ORIGINAL节点集合
{child1,child2}
2.将第一节点附加到另一个集合=&gt;将其从原始集合中删除
{}的child2 3.现在当foreach在索引1时,它看到它通过了集合的结尾。并退出。

在更改受迭代影响的集合时会发生很多这种情况 但大多数时候,IEnumerator会在发生这种情况时抛出异常。

希望我一切都清楚

答案 2 :(得分:1)

我遇到了同样的问题并观察到,空白节点似乎有一个附加到节点的值,而其他节点则不然(至少在我的应用程序中)。这个方法从节点中删除了空白节点。 ChildNodes列表:

private List<XmlNode> findChildnodes(XmlNode node)
    {
        List<XmlNode> result = new List<XmlNode>();
        foreach (XmlNode childnode in node.ChildNodes) 
        {
            if(childnode.Value == null)
            {
                result.Add(childnode);
            }
        }
        return result;
    }

答案 3 :(得分:0)

在回答您的问题时,Node.childNodes全部的子节点,而Node.SelectNodes(/*)是与/*匹配的所有子节点。只有XML元素匹配/*,因此将排除任何属性,CDATA节点,文本节点等。

然而,问题出现的原因是您在迭代节点时更改节点集合。你不能这样做。 select nodes方法返回节点的引用列表。这就是为什么有效。