how to programmatically add XmlNode to an XmlNodeList

前端 未结 2 1184
后悔当初
后悔当初 2021-01-24 21:00

I have an XmlNodeList of products whose values are put into a table. Now I want to add a new XmlNode to the list when a certain product is found so that in the same loop the new

相关标签:
2条回答
  • 2021-01-24 21:30

    You can't create an XmlNode directly, but only the subtypes (e.g. elements) by using one of the Create* methods of the parent XmlDocument. E.g. if you want to create a new element:

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

    Please note that this will not add the element to the XmlNodeList list so the node won't be processed. All necessary processing of the node should therefore be done right when adding the node.

    0 讨论(0)
  • XmlDocument is the factory for its nodes so you have to do this:

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

    Or its shortcut:

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

    Then to add newly created node to its parent:

    node.ParentNode.AppendChild(newNode);
    

    If added node must be processed then you have to do it explicitly: node list is a snapshot of nodes that matched search condition then it won't be dynamically updated. Simply call insertIntoTable() for added node:

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

    If your code is much different you may need little bit of refactoring to make this process a two step batch (first search for nodes to add and then process them all). Of course you may even follow a completely different approach (for example copying nodes from XmlNodeList to a List and then adding them to both lists).

    Assuming this is enough (and you do not need refactoring) let's put everything together:

    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);
    }
    

    Refactoring

    Refactoring time (and if you have a 200 lines function you really need it, much more than what I present here). First approach even if not very efficient:

    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
    

    If you do not like a two passes approach you may use ToList() like this:

    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);
    }
    

    Please note that in second example the use of for instead of foreach is mandatory because you change the collection within the loop. Note that you may even keep your original XmlNodeList object in place...

    0 讨论(0)
提交回复
热议问题