2

我有一个 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);
}
4

2 回答 2

14

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对象保留在原处...

于 2013-11-06T09:27:53.360 回答
2

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

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

请注意,这不会将元素添加到 XmlNodeList 列表中,因此不会处理该节点。因此,在添加节点时应正确完成节点的所有必要处理。

于 2013-11-06T09:28:19.143 回答