【问题标题】:how to programmatically add XmlNode to an XmlNodeList如何以编程方式将 XmlNode 添加到 XmlNodeList
【发布时间】:2013-11-06 09:23:56
【问题描述】:

我有一个产品的 XmlNodeList,其值被放入一个表中。现在我想在找到某个产品时向列表中添加一个新的 XmlNode,以便在同一个循环中,新产品被视为与文件中最初的项目相同。这样函数的结构不需要改变,只需添加一个额外的节点,接下来处理。 但是 XmlNode 是一个抽象类,我不知道如何以编程方式创建新节点。这可能吗?

XmlNodeList list = productsXml.SelectNodes("/portfolio/products/product");

for (int i = 0; i < list.Count; i++)
{
  XmlNode node = list[i];

  if (node.Attributes["name"].InnertText.StartsWith("PB_"))
  {
    XmlNode newNode = ????
    list.InsertAfter(???, node);
  }

  insertIntoTable(node);
}

【问题讨论】:

标签: c# .net xml


【解决方案1】:

XmlDocument 是其节点的工厂,因此您必须这样做:

XmlNode newNode = document.CreateNode(XmlNodeType.Element, "product", "");

或者它的快捷方式:

XmlNode newNode = document.CreateElement("product");

然后将新创建的节点添加到其父节点:

node.ParentNode.AppendChild(newNode);

如果必须处理添加的节点,则必须明确执行:节点列表是匹配搜索条件的节点的快照,则不会动态更新。只需调用insertIntoTable() 即可添加节点:

insertIntoTable(node.ParentNode.AppendChild(newNode));

如果您的代码有很大不同,您可能需要进行一些重构以使此过程成为一个两步批处理(首先搜索要添加的节点,然后将它们全部处理)。当然,您甚至可以采用完全不同的方法(例如,将节点从 XmlNodeList 复制到列表,然后将它们添加到两个列表中)。

假设这已经足够了(并且您不需要重构)让我们把所有东西放在一起:

foreach (var node in productsXml.SelectNodes("/portfolio/products/product"))
{
  if (node.Attributes["name"].InnertText.StartsWith("PB_"))
  {
    XmlNode newNode = document.CreateElement("product");
    insertIntoTable(node.ParentNode.AppendChild(newNode));
  }

  // Move this before previous IF in case it must be processed
  // before added node
  insertIntoTable(node);
}

重构

重构时间(如果你有一个 200 行的函数,你真的需要它,比我在这里展示的要多得多)。第一种方法,即使效率不高:

var list = productsXml
    .SelectNodes("/portfolio/products/product")
    .Cast<XmlNode>();
    .Where(x.Attributes["name"].InnertText.StartsWith("PB_"));

foreach (var node in list)
    node.ParentNode.AppendChild(document.CreateElement("product"));

foreach (var node in productsXml.SelectNodes("/portfolio/products/product"))
    insertIntoTable(node); // Or your real code

如果您不喜欢两次通过的方法,您可以像这样使用ToList()

var list = productsXml
    .SelectNodes("/portfolio/products/product")
    .Cast<XmlNode>()
    .ToList();

for (int i=0; i < list.Count; ++i)
{
    var node = list[i];

    if (node.Attributes["name"].InnertText.StartsWith("PB_"))
      list.Add(node.ParentNode.AppendChild(document.CreateElement("product"))));

    insertIntoTable(node);
}

请注意,在第二个示例中,必须使用 for 而不是 foreach,因为您在循环中更改了集合。请注意,您甚至可以保留原来的 XmlNodeList 对象...

【讨论】:

  • 这将如何导致新节点“下一个处理”?
  • @musefan 在该代码中他不需要处理自己添加的节点,因为他正在迭代列表以添加新节点。
  • 那么为什么 OP 显式声明“添加下一个处理的额外节点”,我同意不需要处理下一个节点,因为他们应该在添加之前控制它。也没有提到他们想要将节点添加到您建议的原始文档中......这可能只是问题写得不好,或者 OP 并不真正理解他们在问什么
  • @musefan 你可能是对的,我对他的要求几乎没有假设。如果这对他不起作用,我想他会澄清(或者可能不会......)
  • @ServéLaurijssen 我添加了关于重构的部分。它总是非常简单(参见最后两个示例)但是...IMO 如果您有一个包含 200 行代码的函数...您真的需要它以及更多比这更深...
【解决方案2】:

您不能直接创建 XmlNode,只能使用父 XmlDocument 的 Create* 方法之一创建子类型(例如元素)。例如。如果你想创建一个新元素:

XmlElement el = doc.CreateElement("elementName");
node.ParentNode.InsertAfter(el, node);

请注意,这不会将元素添加到 XmlNodeList 列表中,因此不会处理该节点。因此,在添加节点时,应立即对节点进行所有必要的处理。

【讨论】:

  • 不确定为什么这被否决了,它比其他答案更好,因为它实际上将节点插入到正确的位置
  • InsertAfter 抛出“引用节点不是该节点的子节点”,我会选择 node.ParentNode.AppendChild,因为它什么时候处理都没有关系,只要它是
  • @ServéLaurijssen:使用node.ParentNode.AppendChild 绝不会允许在您的 for 循环中处理该节点。你的意思是在其他地方处理它,比如在 for 循环之后?
  • 你是对的,现在也发现了,但是 InsertAfter 抛出异常
  • 看起来 XmlNodeList 不支持 InsertAfter,因此您必须使用 node.ParentNode.InsertAfter (编辑我的答案以反映这一点)。但是,这不会将该节点添加到 XmlNodeList 列表中,因此不会对其进行处理。也许您需要更改方法,以便循环遍历文档或子父项“产品”(取决于 SelectNodes 是否显着减少了节点数)。您的 Xml 文档样本可以很好地回答这个问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-02-25
  • 2011-08-22
  • 2013-12-30
  • 1970-01-01
  • 2013-03-09
  • 1970-01-01
相关资源
最近更新 更多