4
        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>

执行第二个代码示例后的 ParentDoc.OuterXML

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

4 回答 4

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正在访问原始集合。

于 2012-06-28T06:45:28.667 回答
1

这是对 Anders G 发布的内容的清理,并提供了更多的解释。

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

在代码 1 中。
1. 创建一个新的节点集合
2. 选择节点到它
3. 附加到其他节点 => 从原始集合中删除,但不是新创建的。
4 您正在从新集合中删除要添加的节点。

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

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

希望我说清楚了

于 2012-06-28T06:59:48.000 回答
1

我遇到了同样的问题并观察到,空白节点似乎有一个附加到节点的值,而其他节点不是这种情况(至少在我的应用程序中)。此方法从 node.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;
    }
于 2012-09-18T11:11:13.447 回答
0

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

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

于 2012-06-28T06:56:44.200 回答