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