The tribal knowledge in dealing with XmlDocument in C# is that it takes the reference to a tree and its branches too literally. When pruning or adding to the tree, one must always take from the branch (node) from which it comes to do any operation. Here are a few examples to work with the XmlDocument
Add Node With Attributes
string xml = @"<?xml version='1.0' encoding='utf-8'?>
<menu>
<sub name='A' value='p1.aspx'/>
<sub name='B' value='p2.aspx'/>
<sub name='C' value='p3.aspx'/>
</menu>";'
XmlDocument originalXml = new XmlDocument();
originalXml.LoadXml(xml);
XmlNode menu = originalXml.SelectSingleNode("menu");
XmlNode newSub = originalXml.CreateNode(XmlNodeType.Element, "sub", null);
XmlAttribute xa = originalXml.CreateAttribute("Name");
xa.Value = "D";
XmlAttribute xb = originalXml.CreateAttribute("value");
xb.Value = "p4.aspx";
newSub.Attributes.Append(xa);
newSub.Attributes.Append(xb);
menu.AppendChild(newSub);
Console.WriteLine(originalXml.OuterXml.ToString());
The above code we had a static set of Xml, and added a node with two attributes. Here is the output (pretty printed after the fact and not by the code)
<?xml version="1.0" encoding="utf-8"?>
<menu>
<sub name="A" value="p1.aspx" />
<sub name="B" value="p2.aspx" />
<sub name="C" value="p3.aspx" />
<sub Name="D" value="p4.aspx" />
</menu>
Remove Node
Using the above snippet to remove the “B” node we will search for it then remove it
XmlNode bNode = originalXml.SelectSingleNode("descendant::sub[@name='B']");
if (bNode != null)
menu.RemoveChild(bNode);
Console.WriteLine(originalXml.OuterXml.ToString());
Which produces this Output
<?xml version="1.0" encoding="utf-8"?>
<menu>
<sub name="A" value="p1.aspx" />
<sub name="C" value="p3.aspx" />
<sub Name="D" value="p4.aspx" />
</menu>
Replace Xml Snippet
In this example we will simulate a user making a changes to an xml node say within an editor. All we know is that it has been changed, but we don’t know what. It could be either additions or subtractions of attributes and nodes; regardless it needs to replace an original item.
string xmlInitial = @"<?xml version='1.0'?> <Rules> <OpenBalances function='ReOrderFifo'> <column name='SecurityID' used='True'/> <column name='COL2' used='False'>#@#</column> <column name='COL3' used='False'>#@#</column> </OpenBalances> <ClosedBalances/> </Rules>"; string xmlUser = @"<OpenBalances function='ReOrderFifo' iAmNew='true'> <column name='SecurityID' used='True'/> <column name='COL3' used='True'>New Item</column> <column name='COL5' used='True'>Other Item</column> </OpenBalances>"; XmlDocument originalXml = new XmlDocument(); string targetNode = "descendant::*[name(.) ='OpenBalances']"; originalXml.LoadXml( xmlInitial ); // Simulate the selection of the subnode // for the user to edit in the first nodes // Rules. XmlNode editNode = originalXml.SelectSingleNode(targetNode); // Get a fragment and slide the changed data into it. XmlDocumentFragment fragment = originalXml.CreateDocumentFragment(); fragment.InnerXml = xmlUser; // Replace the contents of the editNode with the user fragment. editNode.ParentNode.ReplaceChild(fragment, editNode); Console.WriteLine(originalXml.OuterXml);
Here is the resulting output
<?xml version="1.0"?> <Rules> <OpenBalances function="ReOrderFifo" iAmNew="true"> <column name="SecurityID" used="True" /> <column name="COL3" used="True">New Item</column> <column name="COL5" used="True">Other Item</column> </OpenBalances> <ClosedBalances /> </Rules>
#1 by vinh on March 17, 2009 - 2:39 am
Quote
thanks for your article.
#2 by ammu on January 5, 2010 - 3:04 am
Quote
how to add xmlnodes in loop?
#3 by campingmap on January 26, 2010 - 7:57 am
Quote
in what loop do you mean? I think the code in this example shows how to add a node, should not be any problem to add more than one
#4 by omegaman on January 26, 2010 - 6:58 pm
Quote
If one is adding nodes in a loop, I believe the standard way of creating Xml is what the person was requesting; to which the blog doesn’t show. BUt this is a specific case which could be extrapolated to a loop though.
#5 by Girish on June 14, 2010 - 1:27 pm
Quote
I have a xml like this
for this XDocument I want to add one child XElement() under
I want to write a generic method for this.
I can do the above like this
XDocument xdoc=new XDocument()
XElement xelem=new XElement(“Leaf1, new XAttribute(“name”,”ADO.NET”));
xdoc.Root.Element(“Parent”).ElementAt(1).Element(“Child”).ElementAt(0).Element(“Leaf”).ElementAt(1).Add(xelem);
But I dont want to do like this.
I want something like
xdoc.Root.Element.Add(xelem);
Is there anyway to do like this. Cause I will not be knowing the Level of ChildElements.
Thanks in advance
#6 by OmegaMan on June 14, 2010 - 3:19 pm
Quote
I am not seeing what your xElem is like. Could you post this question with xml snippets to MSDN’s Visual C# Language forum and give a link back here. Thanks
#7 by Abdul on December 21, 2010 - 9:02 pm
Quote
I must say the way you presented this solution is excellent……
Thank You.
Abdul.
#8 by BobT on January 27, 2011 - 10:05 am
Quote
VERY grateful for this!!
#9 by pham linh sơn on April 27, 2011 - 10:29 pm
Quote
thanks a lot. it realy helpful.
#10 by Markus on August 3, 2011 - 4:42 pm
Quote
Thanks much, code still comes in handy.
#11 by T1tu5 on October 27, 2011 - 9:25 am
Quote
It’s good work!
Loop:
XmlDocument originalXml = new XmlDocument();
originalXml.LoadXml(xml);
XmlNode menu = originalXml.SelectSingleNode(“menu”);
for (int i = 0; i < 100; i++)
{
XmlNode newSub = originalXml.CreateNode(XmlNodeType.Element, "sub", null);
XmlAttribute xa = originalXml.CreateAttribute("Name");
xa.Value = i.ToString();
XmlAttribute xb = originalXml.CreateAttribute("value");
xb.Value = "p" + i.ToString() + ".aspx";
newSub.Attributes.Append(xa);
newSub.Attributes.Append(xb);
menu.AppendChild(newSub);
}
originalXml.Save("test.xml");