如何从XmlNodeList中移除一个XmlNode

30

我需要根据条件删除一个XmlNode,应该如何做?

foreach (XmlNode drawNode in nodeList)
{
       //Based on a condition
       drawNode.RemoveAll();  //need to remove the entire node                      

}

那有什么问题吗? - Ghasem
需要查看原始的XML以及实际尝试删除/使用的元素/条件。 - vapcguy
6个回答

65

这应该可以为您解决问题:

for (int i = nodeList.Count - 1; i >= 0; i--)
{
    nodeList[i].ParentNode.RemoveChild(nodeList[i]);
}

如果使用常规的for循环,并以“反向”的方式循环,您可以在进行循环时删除项目。

更新:这是一个完整的示例,包括加载XML文件、定位节点、删除它们并保存文件:

XmlDocument doc = new XmlDocument();
doc.Load(fileName);
XmlNodeList nodes = doc.SelectNodes("some-xpath-query");
for (int i = nodes.Count - 1; i >= 0; i--)
{
    nodes[i].ParentNode.RemoveChild(nodes[i]);
}
doc.Save(fileName);

1
在这种特定情况下,它可以工作,因为代码不是从XmlNodeList集合中删除节点,而是从XmlDocument DOM中删除,但在许多其他情况下,在正向for循环中删除项目可能会产生意外结果(例如未被删除的项目)。我猜是本能反应; o) - Fredrik Mörk
似乎不能处理属性节点,对吗?(因为在这种情况下RemoveChild无效) - IgorK
1
@IgorK:不,属性的工作方式有些不同。请查看以下代码,这是一个重新编写的示例,用于从节点中删除属性:http://pastebin.com/gLVkKxa4 - Fredrik Mörk
1
@vapcguy 这里有两个重载方法,一个需要 XmlNamespacemanager,另一个不需要:https://learn.microsoft.com/en-us/dotnet/api/system.xml.xmlnode.selectnodes?view=netframework-4.7.2#System_Xml_XmlNode_SelectNodes_System_String_ - Fredrik Mörk
1
我认为这取决于你的查询:如果查询包含命名空间,则需要使用接受 XmlNamespaceManager 的重载版本,否则可以使用更简单的版本。 - Fredrik Mörk
显示剩余4条评论

4

如果您想从XML DOM中删除节点,那么这不是正确的方法。因为XMLNodeList只是节点列表。相反,您需要从父节点中删除该节点。像这样:

XmlNode parentNode = // some value
XmlNode drawNode = // some value
parentNode.ParentNode.RemoveChild(drawNode);

1
据我所知,C# 中不存在 XmlNode 的 "RemoveNode" 方法。 - Chris Bennet
1
确实,至少在4.0版本是这样的。我认为他的意思是: drawNode.ParentNode.RemoveChild(drawNode); 虽然有点丑陋,但它做到了我所期望的“删除”功能:彻底清除drawNode及其包含的所有内容。 - philw
如果drawNodeparentNode的子节点,你不需要使用.ParentNode。你可以直接使用parentNode.RemoveChild(drawNode); - vapcguy

4

您不能轻易地使用迭代器(foreach语句)来删除节点。据我所见,您可以执行以下操作:

1)在您的for-each循环中,保存应删除的所有元素的列表。然后,只需循环遍历这些元素并将其删除。

2)使用普通的for循环,并在删除一个项目后跟踪要访问的下一个元素。

编辑:使用for循环时,请按照Fredrik的建议向后循环。


1
为第一个答案点个赞;你描述的第二部分听起来有些复杂,通常更容易反向迭代列表,这样您就不必担心下一个索引。 - overslacked
我添加“..跟踪下一个要访问的元素是哪个..”是因为我不知道for循环将以哪种方式实现,如果节点按正确顺序排列等。 - Daniel Wedlund

2

看起来你只是尝试删除整个 XML 元素...

如果这是你的 XML...

<Xml1>
  <body>
    <Book>
      <Title name="Tom Sawyer" />
      <Author value="Mark Twain" />
    </Book>
    <Book>
      <Title name="A Tale of Two Cities" />
      <Author value="Charles Dickens" />
    </Book>
  </body>
</Xml1>

如果您想要删除一本书,您需要获取第一个<Book>节点。您可以使用以下代码实现:
XmlDocument doc = new XmlDocument();
doc.Load(fileName);

XmlNodeList nodes = doc.GetElementsByTagName("body");
XmlNode bodyNode = nodes[0];
XmlNode firstBook = bodyNode.ChildNodes[0];

一旦您获得了“第一本书”节点,您可以使用以下方法从body节点中删除它:
bodyNode.RemoveChild(firstBook);

这将自动影响/更新XML文档变量,因此doc现在只会有:

<Xml1>
  <body>
    <Book>
      <Title name="A Tale of Two Cities" />
      <Author value="Charles Dickens" />
    </Book>
  </body>
</Xml1>

如果您想获取并删除整个,您应该能够执行以下操作:
XmlNodeList xml1 = doc.GetElementsByTagName("Xml1");
XmlNode xmlNode = xml[0];
xmlNode.RemoveChild(bodyNode);

变量doc将被更新,不再包含body元素,然后可以重新保存到文件系统中:

doc.Save(fileName);

在此处,fileName 是您计算机上 XML 文档的完整路径。

最棒的是,我们没有使用 doc.SelectNodes(),因此我们不需要担心使用 XMLNamespaceManager


2
以下是否更简单一些:

这不是更简单吗:

XmlDocument doc = new XmlDocument(); 
doc.Load(fileName); 
XmlNodeList nodes = doc.SelectNodes("some-xpath-query"); 
while (nodes.FirstChild != null) {     
    nodes.RemoveChild(nodes.FirstChild); 
} 
doc.Save(fileName); 

doc.SelectNodes() 需要一个 XMLNamespaceManager。 - vapcguy

0
    XmlNodeList xnodeContact = xmldocContact.GetElementsByTagName("contact");
          foreach (ListViewItem item in listViewContacts.Items)
            {
                if (item.Checked)
                {
                    if (item.Index >= 0)
                        xnodeContact[0].ParentNode.RemoveChild(xnodeContact[0]);
                        listViewContacts.Items.Remove(item);
                    }
                }
            }
            xmldocContact.Save(appdataPath + "\\WhatAppcontactList.xml");
            Invalidate();

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接