XML Manipulation In C#

Introduction

XML stands for Extensible Markup Language file format, which is used to create common information formats and share both the format and the data on the World Wide Web, intranet, etc.

It has the advantages given below.
  1. Human and machine-readable format.
  2. It is platform independent.
  3. Its self-documenting format describes the structure and field names as well as specific values.
  4. XML is heavily used to store the data and share the data.
  5. XML data is stored in text format. This makes it easier to expand or upgrade to new operating systems, new applications, or new browsers, without losing data. 
  6. It strictly follows closing node, case-sensitive and node name.
For more details on XML, visit here.
 
In this article, we will discuss about XML manipulation in C#. We discuss the points given below.
  1. Add node/XML value to the existing XML.
  2. Edit/Update XML data.
  3. Remove the node from XML data.
  4. Select the node value from XML.
  5. XML Serialization.
Using code
 
We will use mostly XDocument and XMLDocument class to manipulate XML data.  The following is the LINQ to XML(XDocument) class hierarchy, which will help to understand it more.
 
Add node/xml value to existing XML
 
Below is the sample XML data, which we will use in our demonstration: 
  1. string tempXml = @"<Projects>  
  2. <Project ID='1' Name='project1' />  
  3. <Project ID='2' Name='project2' />  
  4. <Project ID='3' Name='project3' />  
  5. <Project ID='4' Name='project4' />  
  6. <Project ID='5' Name='project5' />  
  7. </Projects>";   
In the demonstration, we define how many different ways, where we can add the node, using XMLDocument and XDocument class. The output is shown in Figure 2.
 
Using XmlDocument
  1. // Option1: Using InsertAfter()
  2. // Adding Node to XML  
  3. XmlDocument doc3 = new XmlDocument();  
  4. doc3.LoadXml(tempXml);  
  5. XmlNode root1 = doc3.DocumentElement;  
  6. //Create a new attrtibute.  
  7. XmlElement elem = doc3.CreateElement("Project");  
  8. XmlAttribute attr = doc3.CreateAttribute("ID");  
  9. attr.Value = "6";  
  10. elem.Attributes.Append(attr);  
  11. //Create a new attrtibute.  
  12. XmlAttribute attr2 = doc3.CreateAttribute("Name");  
  13. attr2.Value = "Project6";  
  14. elem.Attributes.Append(attr2);  
  15. //Add the node to the document.  
  16. root1.InsertAfter(elem, root1.LastChild);  
  17. doc3.Save(Console.Out);  
  18. Console.WriteLine();  

  19. // Option2: Using AppendChild()
  20. XmlDocument doc4 = new XmlDocument();  
  21. doc4.LoadXml(tempXml);  
  22. XmlElement XEle = doc4.CreateElement("Project");  
  23. XEle.SetAttribute("Name""Project6");  
  24. XEle.SetAttribute("ID""6");  
  25. doc4.DocumentElement.AppendChild(XEle.Clone());  
  26. doc4.Save(Console.Out);  
  27. Console.WriteLine(); 

Figure 2 : Output after adding new node
 
Using XDocument
  1. // Option1: Using AddAfterSelf()
  2. XDocument xdoc = XDocument.Parse(tempXml);  
  3. var cust = xdoc.Descendants("Project")  
  4.                 .First(rec => rec.Attribute("ID").Value == "5");  
  5. cust.AddAfterSelf(new XElement("Project"new XAttribute("ID""6")));  
  6. xdoc.Save(Console.Out);  
  7. Console.WriteLine();  

  8. // Option2: Using Add() method 
  9. XDocument doc = XDocument.Parse(tempXml);  
  10. XElement root = new XElement("Project");  
  11. root.Add(new XAttribute("ID""6"));  
  12. root.Add(new XAttribute("Name""Project6"));  
  13. doc.Element("Projects").Add(root);  
  14. doc.Save(Console.Out);  
  15. Console.WriteLine();  
  16.   
  17. // // When it contains namespace http://stackoverflow.com/questions/2013165/add-an-element-to-xml-file  
  18. string tempXmlNamespace = @"<Projects xmlns='http://schemas.microsoft.com/developer/msbuild/2003'>  
  19.                     <Project ID='1' Name='project1' />  
  20.                     <Project ID='2' Name='project2' />  
  21.                     <Project ID='3' Name='project3' />  
  22.                     <Project ID='4' Name='project4' />  
  23.                     <Project ID='5' Name='project5' />  
  24.                     </Projects>";  
  25. XNamespace ns = "http://schemas.microsoft.com/developer/msbuild/2003";  
  26. XDocument xDoc = XDocument.Parse(tempXmlNamespace);  
  27.   
  28. var b = xDoc.Descendants(ns + "Project").Last();  
  29.   
  30. b.Parent.Add(  
  31.     new XElement(ns + "Project",  
  32.         new XAttribute("ID""6"), new XAttribute("Name""Project6")  
  33.     )  
  34. );  
  35.   
  36. xDoc.Save(Console.Out);  
  37. Console.WriteLine(); 
Edit/Update XML data
 
Sometimes, we need to change/update XML node value. For instance, we have a node for Project, whose ID is 2 and want to update the Project Name attribute. Following code sample implements the same:
 
Using XDocument
  1. // Option1: Using SetAttributeValue()
  2. XDocument xmlDoc = XDocument.Parse(tempXml);  
  3. // Update Element value  
  4. var items = from item in xmlDoc.Descendants("Project")  
  5.             where item.Attribute("ID").Value == "2"  
  6.             select item;  
  7.   
  8. foreach (XElement itemElement in items)  
  9. {  
  10.     itemElement.SetAttributeValue("Name""Project2_Update");  
  11. }  
  12.   
  13. xmlDoc.Save(Console.Out);  
  14. Console.WriteLine();  
  15.   
  16. // Option2: Using Attribute.Value()   
  17. var doc = XElement.Parse(tempXml);  
  18. var target = doc.Elements("Project")  
  19.         .Where(e => e.Attribute("ID").Value == "2")  
  20.         .Single();  
  21.   
  22. target.Attribute("Name").Value = "Project2_Update";  
  23. doc.Save(Console.Out);  
  24. Console.WriteLine();  
  25.   
  26. // Option3: Using ReplaceWith()   
  27. XDocument xmlDoc1 = XDocument.Parse(tempXml);  
  28. XElement xObj = xmlDoc1.Root.Descendants("Project").FirstOrDefault();  
  29. xObj.ReplaceWith(new XElement("Project"new XAttribute("ID""1"),  
  30.     new XAttribute("Name""Project1_Update")));  
  31.   
  32. xmlDoc1.Save(Console.Out);  
  33. Console.WriteLine(); 

Figure 3: Update XML Node value
 
Using XmlDocument
  1. int nodeId = 2;  
  2. XmlDocument xmlDoc2 = new XmlDocument();  
  3. xmlDoc2.LoadXml(tempXml);  
  4. //node["Node2"].InnerText = "Value2";  
  5. XmlNode node = xmlDoc2.SelectSingleNode("/Projects/Project[@ID=" + nodeId + "]");  
  6. node.Attributes["Name"].Value = "Project2_Update";  
  7.   
  8. xmlDoc1.Save(Console.Out);  
  9. Console.WriteLine(); 
Remove node from XML data
 
To remove the node from existing XML data, we will use XmlDocument and XDocument class. 
 
Using XmlDocument Class
  1. // Option1: Remove using SelectSingleNode()
  2. int nodeId = 1;  
  3. XmlDocument xmlDoc = new XmlDocument();  
  4. xmlDoc.LoadXml(tempXml);  
  5. XmlNode nodeToDelete = xmlDoc.SelectSingleNode("/Projects/Project[@ID=" + nodeId + "]");  
  6. if (nodeToDelete != null)  
  7. {  
  8.     nodeToDelete.ParentNode.RemoveChild(nodeToDelete);  
  9. }  
  10. //xmlDoc.Save("XMLFileName.xml");  
  11. xmlDoc.Save(Console.Out);  
  12. Console.WriteLine();  
  13.   
  14. // Option2: Remove XML node using Tag name  
  15. XmlDocument doc2 = new XmlDocument();  
  16. doc2.Load(@"D:\ConsoleApplication4\MyData.xml");  
  17. XmlNodeList nodes = doc2.GetElementsByTagName("Project");  
  18. XmlNode node = nodes[0]; // Getting first node  
  19. node.ParentNode.RemoveChild(node);  
  20. doc2.Save(Console.Out);  
  21. Console.WriteLine();  
  22.   
  23. // Option3: Remove one node/child element  
  24. XmlDocument doc1 = new XmlDocument();  
  25. doc1.LoadXml("<book genre='novel' ISBN='1-2-3'>" +  
  26.             "<title>XML Manipulation</title>" +  
  27.             "</book>");  
  28. XmlNode root = doc1.DocumentElement;  
  29. //Remove the title element.  
  30. root.RemoveChild(root.FirstChild);  
  31. doc1.Save(Console.Out);  
  32. Console.WriteLine(); 

Figure 4: Output after delete node
 
Using XDocument Class
  1. // Using XML Linq  
  2. XDocument xdoc1 = XDocument.Parse(tempXml);  
  3. var elementsToRemove = from elemet in xdoc1.Elements("Projects").Elements("Project")  
  4.                         where elemet.Attribute("Name").Value == "project1"  
  5.                         select elemet;  
  6. foreach (var e in elementsToRemove)  
  7. {  
  8.     e.Remove();  
  9. }              
  10.   
  11. // Using Lambda expression  
  12. XDocument doc = XDocument.Load(@"D:\ConsoleApplication4\MyData.xml");  
  13. doc.Descendants("Project").Where(rec => rec.Attribute("Name").Value == "project2").Remove();  
  14. //doc.Save(@"D:\ConsoleApplication4\MyData_Update.xml");  
  15. doc.Save(Console.Out);  
  16. Console.WriteLine();  
  17.   
  18. // Using XPathSelectElement() method  
  19. XDocument xdoc = XDocument.Parse(tempXml);  
  20. xdoc.XPathSelectElement("Projects/Project[@Name = 'project1']").Remove();  
  21. xdoc.Save(Console.Out);  
  22. Console.WriteLine();  
  23.   
  24. // Remove specific node or remove all  
  25. XElement root2 = XElement.Parse(@"<Root>    
  26.                     <Child1>    
  27.                         <GrandChild1/>    
  28.                         <GrandChild2/>    
  29.                     </Child1>    
  30.                     <Child2>    
  31.                         <GrandChild3/>    
  32.                         <GrandChild4/>  
  33.                     </Child2>   
  34.                 </Root>");  
  35.   
  36. // Remove specific node   
  37. root2.Element("Child1").Element("GrandChild1").Remove();  
  38. root2.Element("Child2").Elements().Remove();  // Remove all elements  
  39. root2.Save(Console.Out);  
  40. Console.WriteLine(); 
Select node value from XML
 
When we use XML data, we want to fetch the data which is based on the node value. We need the project name whose ID is 2. We can use XMLDocument class or XDocument(System.XML.Linq namespace).
  1. XmlDocument xmldoc = new XmlDocument();  
  2. xmldoc.LoadXml(tempXml);  
  3.   
  4. int nodeId = 2;  
  5. XmlNode nodeObj = xmldoc.SelectSingleNode("/Projects/Project[@ID=" + nodeId + "]");  
  6. //string id = nodeObj["Project"].InnerText; // For inner text  
  7. string pName = nodeObj.Attributes["Name"].Value;  
  8.   
  9. // Select Node based on XPath  
  10. XmlNodeList xnList = xmldoc.SelectNodes("/Projects/Project");  
  11. foreach (XmlNode xn in xnList)  
  12. {  
  13.     string projectName = xn.Attributes["Name"].Value;  
  14. }  
  15.   
  16. // Select nodes by TagName  
  17. XmlNodeList nodeList = xmldoc.GetElementsByTagName("Project");  
  18. foreach (XmlNode node in nodeList)  
  19. {  
  20.     var ID = node.Attributes["ID"].Value;  
  21.     var Name = node.Attributes["Name"].Value;  
  22. }  
Using XDocument 
  1. string tempXmlData = @"<Projects>  
  2.                     <Project ID='1' Name='project1' />  
  3.                     <Project ID='2' Name='Not' />  
  4.                     <Project ID='3' Name='project3' />  
  5.                     <Project ID='4' Name='Test' />  
  6.                     <Project ID='5' Name='project5' />  
  7.                     </Projects>";  
  8.   
  9. XDocument doc = XDocument.Parse(tempXmlData);  
  10. IEnumerable<Project> result = from rec in doc.Descendants("Project")  
  11.                                 where rec.Attribute("Name").Value.Contains("project")  
  12.                                 select new Project()  
  13.                                 {  
  14.                                     ID = (int)rec.Attribute("ID"),  
  15.                                     Name = (string)rec.Attribute("Name")  
  16.                                 };  
  17. foreach (Project p in result)  
  18. {  
  19.     Console.WriteLine("ID:" + p.ID + ", Name: " + p.Name);  

Figure 5: Result after apply filter 
 
We can generate XML data from C# objects. For instance, we have a list of projects and we want it in XML format. The code sample is given below.
  1. // Generate XML data from C# objects  
  2. List<Project> projects = new List<Project>()  
  3. {  
  4.     new Project{ID = 1, Name="Project1"},  
  5.     new Project{ID = 2, Name="Project2"},  
  6.     new Project{ID = 3, Name="Project3"},  
  7.     new Project{ID = 4, Name="Project4"},  
  8.     new Project{ID = 5, Name="Project5"}  
  9. };  
  10.   
  11. string tempStr = SerializeObject<List<Project>>(projects);  
  12. List<Project> tempProjects = DeserializeObject<List<Project>>(tempStr);  
  13.   
  14. XDocument xDocument = new XDocument(  
  15.     new XDeclaration("1.0""utf-8""yes"),  
  16.     new XComment("LINQ To XML Demo"),  
  17.     new XElement("Projects",  
  18.     from project in projects  
  19.     select new XElement("Project"new XAttribute("ID", project.ID),  
  20.                                     new XAttribute("Name", project.Name))));  
  21.   
  22. xDocument.Save(Console.Out);  
  23. Console.WriteLine(); 
Figure 6: After convert object to XML
 
XML Serialization/Deserialization
 
Serialization/Deserialization is a cool and important feature of an application. It is required when your want to communicate/send data to other applications. Serialization is a process to convert an object to other formats like XML or binary. Deserialization is just reverse process of Serialization means to convert byte array or XML data to the objects.
 
The following points needs to remember when there is a class for serialization.
  • XML serialization only serializes public fields and properties.
  • XML serialization does not include any type information.
  • We need to have a default/ non-parameterized constructor in order to serialize an object.
  • ReadOnly properties are not serialized.
Below are some important attributes while Serialization happens.
  • XmlRoot Represents XML document's root Element 
  • XmlElement Field will be serialized as an XML element 
  • XmlAttribute Field will be serialized as an XML attribute
  • XmlIgnore Field/property will be ignored during serialization 
Let's design Project entity for serialization.
  1. [XmlRoot("Projects")]  
  2. public class Project  
  3. {  
  4.     [XmlAttributeAttribute("ID")]  
  5.     public int ID { getset; }  
  6.   
  7.     [XmlAttributeAttribute("Name")]  
  8.     public string Name { getset; }  

After designing an entity, we have DeserializationObject() method, which takes XML data parameter and returns object. Likewise, we have a method SerializeObject() which takes an object as a parameter and returns the data as XML format. 
  1. public static T DeserializeObject<T>(string xml)  
  2. {  
  3.     var serializer = new XmlSerializer(typeof(T));  
  4.     using (var tr = new StringReader(xml))  
  5.     {  
  6.         return (T)serializer.Deserialize(tr);  
  7.     }  
  8. }  
  9.   
  10. public static string SerializeObject<T>(T obj)  
  11. {  
  12.     var serializer = new XmlSerializer(typeof(T));  
  13.   
  14.     XmlWriterSettings settings = new XmlWriterSettings();  
  15.     settings.Encoding = new UnicodeEncoding(truetrue);  
  16.     settings.Indent = true;  
  17.     //settings.OmitXmlDeclaration = true;  
  18.   
  19.     XmlSerializerNamespaces ns = new XmlSerializerNamespaces();  
  20.     ns.Add("""");  
  21.   
  22.     using (StringWriter textWriter = new StringWriter())  
  23.     {  
  24.         using (XmlWriter xmlWriter = XmlWriter.Create(textWriter, settings))  
  25.         {  
  26.             serializer.Serialize(xmlWriter, obj, ns);  
  27.         }  
  28.   
  29.         return textWriter.ToString(); //This is the output as a string  
  30.     }  


  31. string tempStr = SerializeObject<List<Project>>(projects);
    List<Project> tempProjects = DeserializeObject<List<Project>>(tempStr);
Figure 7: Result after Serialization

XmlDocument vs XDocument

We mostly used XmlDocument or XDocument class to manipulate XML data. However, there are some differences between them:
  • XDocument(System.Xml.Linq) is from the LINQ to XML API and XmlDocument(System.Xml.XmlDocument) is the standard DOM-style API for XML.
  • If you're using .NET version 3.0 or lower, you have to use XmlDocument, the classic DOM API. On the other hand, if you are using .NET version 3.5 onwards, you need to use XDocument.
  • Performance wise XDocument is faster than XmlDocument because it (XDocument) is newly developed to get better usability with LINQ. It's (XDocument) much simpler to create documents and process them.
Conclusion

We learned how to use LINQ to XML to manipulate XML by loading external XML files and reading the data within, as well as the writing data to external XML files. We also discussed how to use XmlDocument and XDocument, as XDocument has more features. We need to use this if you are using .NET framework 3.5 onwards.

Hope this helps.