last modified July 5, 2023
C# XmlDocument tutorial shows how to work with XML in C# with XmlDocument.
Extensible Markup Language (XML) is a markup language that defines aset of rules for encoding documents in a format that is both human-readable andmachine-readable. XML is often used for application configuration, data storageand exchange.
XML is similar to HTML, but does not have predefined tags; we can design our owntags.
XmlDocument
The XmlDocument
represents an XML document. It can be use to load,modify, validate, an navigate XML documents.
The XmlDocument
class is an in-memory representation of an XMLdocument. It implements the W3C XML Document Object Model (DOM).
The Document Object Model (DOM) is a language-independentprogramming interface for HTML and XML documents. It represents a page. Throughthe DOM interface, the programs can change the document structure, style, andcontent. The DOM represents the document as nodes and objects.
The XmlElement
is a common node in the XmlDocument
.
XPath (XML Path Language) is a query language for selecting nodesfrom an XML document. It can be also used to compute values from the content ofan XML document.
In the examples, we with the following files:
words.xml
<?xml version="1.0" encoding="UTF-8"?><words> <word>falcon</word> <word>sky</word> <word>bottom</word> <word>cup</word> <word>book</word> <word>rock</word> <word>sand</word> <word>river</word></words>
This is the words.xml
file.
users.xml
<?xml version="1.0" encoding="UTF-8"?><users> <user id="1"> <name>John Doe</name> <occupation>gardener</occupation> </user> <user id="2"> <name>Jane Doe</name> <occupation>teacher</occupation> </user> <user id="3"> <name>Roger Roe</name> <occupation>driver</occupation> </user> <user id="4"> <name>Lucia Smith</name> <occupation>shopkeeper</occupation> </user></users>
This is the users.xml
file.
continents.xml
<?xml version="1.0" encoding="UTF-8"?><continents> <europe> <slovakia> <capital>Bratislava</capital> <population>421000</population> </slovakia> <hungary> <capital>Budapest</capital> <population>1759000</population> </hungary> <poland> <capital>Warsaw</capital> <population>1735000</population> </poland> </europe> <asia> <china> <capital>Beijing</capital> <population>21700000</population> </china> <vietnam> <capital>Hanoi</capital> <population>7500000</population> </vietnam> </asia></continents>
This is the continents.xml
file.
C# XmlDocument DocumentElement
The DocumentElement
returns the root XmlElement
forthe document.
Program.cs
using System.Xml;var xmlData = @"<?xml version=""1.0"" encoding=""UTF-8""?> <words> <word>falcon</word> <word>sky</word> <word>bottom</word> <word>cup</word> <word>book</word> <word>rock</word> <word>sand</word> <word>river</word> </words> ";var doc = new XmlDocument();doc.LoadXml(xmlData);Console.WriteLine(doc.DocumentElement?.Name);Console.WriteLine(doc.DocumentElement?.FirstChild?.InnerText);Console.WriteLine(doc.DocumentElement?.LastChild?.InnerText);Console.WriteLine(doc.DocumentElement?.OuterXml);Console.WriteLine(doc.DocumentElement?.InnerXml);
We load XML data into the XmlDocument
and get the root element ofthe document; we call properties of the root node.
var xmlData = @"<?xml version=""1.0"" encoding=""UTF-8""?> <words> <word>falcon</word> <word>sky</word> <word>bottom</word> <word>cup</word> <word>book</word> <word>rock</word> <word>sand</word> <word>river</word> </words> ";
We have XML data as a multi-line string.
var doc = new XmlDocument();doc.LoadXml(xmlData);
We create an XmlDocument
and load the XML data withLoadXml
method.
Console.WriteLine(doc.DocumentElement?.Name);
The Name
property returns the name of the node.
Console.WriteLine(doc.DocumentElement?.FirstChild?.InnerText);Console.WriteLine(doc.DocumentElement?.LastChild?.InnerText);
We get the first and last child of the root node with FirstChild
and LastChild
. The InnerText
propertyreturns the values of the node and all its child nodes.
Console.WriteLine(doc.DocumentElement?.OuterXml);
The OuterXml
property gets the markup containing this node and allits child nodes.
Console.WriteLine(doc.DocumentElement?.InnerXml);
The InnerXml
property gets or sets the markup representing only thechild nodes of this node.
$ dotnet run wordsfalconriver<words><word>falcon</word><word>sky</word><word>bottom</word><word>cup</word>...<word>falcon</word><word>sky</word><word>bottom</word><word>cup</word>...
C# XmlNode.RemoveChild
The XmlNode.RemoveChild
method removes the specified child node.
Program.cs
using System.Xml;var xmlFile = "/home/janbodnar/Documents/users.xml";var doc = new XmlDocument();doc.Load(xmlFile);XmlElement root = doc.DocumentElement;XmlNode userNode = root?.LastChild;if (userNode != null){ root.RemoveChild(userNode);}var xmlFile2 = "/home/janbodnar/Documents/users2.xml";doc.Save(xmlFile2);
In the example, we remove the last child in the document. Note that the methoddoes not modify the original file; it modifies the in-memory representation ofthe document and the modified document is saved into a new file.
C# XmlDocument.CreateElement
The XmlDocument.CreateElement
method creates an element with thespecified name.
Program.cs
using System.Xml;var xmlFile = "/home/janbodnar/Documents/words.xml";var doc = new XmlDocument();doc.Load(xmlFile);XmlElement root = doc.DocumentElement;XmlElement e1 = doc.CreateElement("word");e1.InnerText = "eagle";root?.InsertAfter(e1, root.LastChild);XmlElement e2 = doc.CreateElement("word");e2.InnerText = "cheetah";root?.InsertBefore(e2, root.FirstChild);var xmlFile2 = "/home/janbodnar/Documents/words2.xml";doc.Save(xmlFile2);
In the example, we create two new elements.
XmlElement e1 = doc.CreateElement("word");e1.InnerText = "eagle";
A new element named word
is created withCreateElement
. Its text is set with InnerText
property.
root?.InsertAfter(e1, root.LastChild);
The newly created element is inserted after the last child withInsertAfter
.
XmlElement e2 = doc.CreateElement("word");e2.InnerText = "cheetah";root?.InsertBefore(e2, root.FirstChild);
The second element is inserted before the first element withInsertBefore
.
C# XmlDocument create new document
In the following example, we create a new XML document.
Program.cs
using System.Xml;var users = new Dictionary<long, User>();users.Add(1, new User(1L, "John Doe", "gardener"));users.Add(2, new User(2L, "Jane Doe", "teacher"));users.Add(3, new User(3L, "Roger Roe", "driver"));users.Add(4, new User(4L, "Lucia Smith", "shopkeeper"));var doc = new XmlDocument();XmlDeclaration xmlDeclaration = doc.CreateXmlDeclaration("1.0", "UTF-8", string.Empty);doc.AppendChild(xmlDeclaration);XmlElement usersNode = doc.CreateElement("users");doc.AppendChild(usersNode);foreach (var (_, value) in users){ XmlElement userEl = doc.CreateElement("user"); usersNode.AppendChild(userEl); XmlAttribute e = doc.CreateAttribute("id"); e.Value = value.Id.ToString(); userEl.Attributes.Append(e); XmlElement e2 = doc.CreateElement("name"); e2.InnerText = value.Name; userEl.AppendChild(e2); XmlElement e3 = doc.CreateElement("occupation"); e3.InnerText = value.Occupation; userEl.AppendChild(e3);}doc.Save(Console.Out);internal record User(long Id, string Name, string Occupation);
A new XML document is created from a dictionary of user objects.
var users = new Dictionary<long, User>();users.Add(1, new User(1L, "John Doe", "gardener"));users.Add(2, new User(2L, "Jane Doe", "teacher"));users.Add(3, new User(3L, "Roger Roe", "driver"));users.Add(4, new User(4L, "Lucia Smith", "shopkeeper"));
We have a dictionary of users.
var doc = new XmlDocument();XmlDeclaration xmlDeclaration = doc.CreateXmlDeclaration("1.0", "UTF-8", string.Empty);
An XmlDocument
and a XmlDeclaration
are created.
doc.AppendChild(xmlDeclaration);
The XmlDeclaration
is appended to the document withAppendChild
. The declaration tag is the first tag in the document.
XmlElement usersNode = doc.CreateElement("users");doc.AppendChild(usersNode);
We create the root node of the document.
foreach (var (_, value) in users){ XmlElement userEl = doc.CreateElement("user"); usersNode.AppendChild(userEl); XmlAttribute e = doc.CreateAttribute("id"); e.Value = value.Id.ToString(); userEl.Attributes.Append(e); XmlElement e2 = doc.CreateElement("name"); e2.InnerText = value.Name; userEl.AppendChild(e2); XmlElement e3 = doc.CreateElement("occupation"); e3.InnerText = value.Occupation; userEl.AppendChild(e3);}
We go through the dictionary and create necessary elements and an attribute foreach user object.
doc.Save(Console.Out);
This time we output the XML data to the console.
$ dotnet run<?xml version="1.0" encoding="utf-8"?><users> <user id="1"> <name>John Doe</name> <occupation>gardener</occupation> </user> <user id="2"> <name>Jane Doe</name> <occupation>teacher</occupation> </user> <user id="3"> <name>Roger Roe</name> <occupation>driver</occupation> </user> <user id="4"> <name>Lucia Smith</name> <occupation>shopkeeper</occupation> </user></users>
C# XmlNode.ChildNodes
The XmlNode.ChildNodes
returns all the children of the given node.The property returns the XmlNodeList
, which represents an orderedcollection of nodes.
Program.cs
using System.Xml;var xmlFile = "/home/janbodnar/Documents/words.xml";var doc = new XmlDocument();doc.Load(xmlFile);XmlElement root = doc.DocumentElement;XmlNodeList childNodes = root?.ChildNodes;if (childNodes == null){ Console.WriteLine("no nodes found"); Environment.Exit(1);}foreach (XmlNode node in childNodes){ Console.WriteLine(node.InnerText);}
In the example, we get all the children of the root node and print their innertext content.
$ dotnet runfalconskybottomcupbookrocksandriver
C# XmlNodeList.Count
The XmlNodeList.Count
property gets the number of nodes in theXmlNodeList
.
Program.cs
using System.Xml;var xmlFile = "/home/janbodnar/Documents/words.xml"; var doc = new XmlDocument();doc.Load(xmlFile);XmlElement root = doc.DocumentElement;int? n = root?.ChildNodes.Count;Console.WriteLine($"There are {n} elements");
We get the number of elements inside the root node.
$ dotnet run There are 8 elements
C# XmlNode.SelectSingleNode
The XmlNode.SelectSingleNode
selects the first XmlNode that matchesthe XPath expression.
Program.cs
using System.Xml;var xmlFile = "/home/janbodnar/Documents/users.xml";var doc = new XmlDocument();doc.Load(xmlFile);int id = 2;XmlNode node = doc.SelectSingleNode($"/users/user[@id='{id}']");if (node == null){ Console.WriteLine("node not found"); Environment.Exit(1);}var name = node.ChildNodes[0]?.InnerText;var occupation = node.ChildNodes[1]?.InnerText;var uid = node.Attributes?["id"]?.Value;Console.WriteLine($"Id: {uid}");Console.WriteLine($"Name: {name}");Console.WriteLine($"Occupation: {occupation}");
From the words.xml
file, we select the word node with Id attribute6.
XmlNode node = doc.SelectSingleNode($"/users/user[@id='{id}']");
A single node is selected with SelectSingleNode
; the/users/user[@id='{id}']
is the query expression to get to thedesired node.
var name = node.ChildNodes[0]?.InnerText;var occupation = node.ChildNodes[1]?.InnerText;var uid = node.Attributes?["id"]?.Value;
We get the node's text and attribute.
$ dotnet runId: 2Name: Jane DoeOccupation: teacher
C# XmlNode.SelectNodes
The XmlNode.SelectNodes
selects a list of nodes matching the XPathexpression.
Program.cs
using System.Xml;var xmlFile = "/home/janbodnar/Documents/users.xml";var doc = new XmlDocument();doc.Load(xmlFile);XmlNodeList nodes = doc.SelectNodes("/users/user");var users = new List<User>();if (nodes == null){ Console.WriteLine("No users found"); Environment.Exit(1);}foreach (XmlNode node in nodes){ long id = long.Parse(node.Attributes?.GetNamedItem("id")?.Value!); string name = node.ChildNodes[0]?.InnerText; string occupation = node.ChildNodes[1]?.InnerText; var user = new User(id, name, occupation); users.Add(user);}users.ForEach(Console.WriteLine);record User(long Id, string Name, string Occupation);
In the example, we select all users from the users.xml
file.
XmlNodeList nodes = doc.SelectNodes("/users/user");
The /users/user
is the path to get all users. TheSelectNodes
method returns an XmlNodeList
.
foreach (XmlNode node in nodes){ long id = long.Parse(node.Attributes?.GetNamedItem("id")?.Value!); string name = node.ChildNodes[0]?.InnerText; string occupation = node.ChildNodes[1]?.InnerText; var user = new User(id, name, occupation); users.Add(user);}
We go through the XmlNodeList
and create a User
objectfrom the retrieved data.
$ dotnet runUser { Id = 1, Name = John Doe, Occupation = gardener }User { Id = 2, Name = Jane Doe, Occupation = teacher }User { Id = 3, Name = Roger Roe, Occupation = driver }User { Id = 4, Name = Lucia Smith, Occupation = shopkeeper }
C# XmlElement.GetElementsByTagName
The XmlElement.GetElementsByTagName
returns anXmlNodeList
containing a list of all descendant elements that matchthe specified tag name.
Program.cs
using System.Xml;var xmlFile = "/home/janbodnar/Documents/continents.xml";XmlDocument doc = new XmlDocument();doc.Load(xmlFile);XmlNodeList nodes = doc.GetElementsByTagName("capital");Console.WriteLine("All capitals:");foreach (XmlNode node in nodes){ var text = node.InnerText; Console.WriteLine(text);}
We go over the capital
tags in the continents.xml
file.
$ dotnet runAll capitals:BratislavaBudapestWarsawBeijingHanoi
C# XmlDocument.CreateNavigator
The XmlDocument.CreateNavigator
creates aXPathNavigator
object for navigating the document. TheXPathNodeIterator
provides an iterator over a selected set ofnodes.
Program.cs
using System.Xml;using System.Xml.XPath;var xmlFile = "/home/janbodnar/Documents/users.xml";var doc = new XmlDocument();doc.Load(xmlFile);XPathNavigator rootNav = doc.CreateNavigator();XPathNodeIterator it = rootNav?.Select("descendant::users/user");if (it == null){ Console.WriteLine("no users found"); Environment.Exit(1);}while (it.MoveNext()){ XPathNavigator nav = it.Current; var uId = nav?.GetAttribute("id", string.Empty); Console.WriteLine(uId); XPathNodeIterator nodeIt = nav?.SelectChildren(XPathNodeType.Element); if (nodeIt != null) { foreach (var e in nodeIt) { Console.WriteLine(e); } } Console.WriteLine("--------------------");}
We use the XPathNavigator
and the XPathNodeIterator
togo over users in the users.xml
file.
XPathNavigator rootNav = doc.CreateNavigator();XPathNodeIterator it = rootNav?.Select("descendant::users/user");...while (it.MoveNext())
First, we go over the user
tags.
XPathNavigator nav = it.Current;var uId = nav?.GetAttribute("id", string.Empty);Console.WriteLine(uId);XPathNodeIterator nodeIt = nav?.SelectChildren(XPathNodeType.Element);if (nodeIt != null){ foreach (var e in nodeIt) { Console.WriteLine(e); }}
Then we go over the elements of each user
tag.
$ dotnet run1John Doegardener--------------------2Jane Doeteacher--------------------3Roger Roedriver--------------------4Lucia Smithshopkeeper--------------------
C# XmlDocument recursive loop
In the following example, we recursively loop over the tags of theusers.xml
file.
Program.cs
using System.Xml;var xmlFile = "/home/janbodnar/Documents/users.xml";var doc = new XmlDocument();doc.Load(xmlFile);traverse(doc.DocumentElement);void traverse(XmlNode node){ if (node is XmlElement) { if (node.Name == "users") { Console.WriteLine(node.Name); } else if (node.Name == "user") { Console.WriteLine("--------------------"); Console.WriteLine(node.Name); } else { Console.WriteLine($" {node.Name}"); } if (node.HasChildNodes) { traverse(node.FirstChild); } if (node.NextSibling != null) { traverse(node.NextSibling); } } else if (node is XmlText) { var text = ((XmlText) node).Value; Console.WriteLine($" {text}"); }}
We parse the users.xml
with a recursive algorithm.
traverse(doc.DocumentElement);
We start by passing the root element to the traverse
method.
if (node is XmlElement){ ...}else if (node is XmlText){ var text = ((XmlText) node).Value; Console.WriteLine($" {text}");}
We check if the node is an XmlElement
or an XmlText
.In the latter case, we output the textual content of the node.
if (node.HasChildNodes){ traverse(node.FirstChild);}
If the node has children, we recursively call the traverse
methodpassing it its first child.
if (node.NextSibling != null){ traverse(node.NextSibling);}
We go recursively to the next sibling if there is any.
$ dotnet runusers--------------------user name John Doe occupation gardener--------------------user name Jane Doe occupation teacher--------------------user name Roger Roe occupation driver--------------------user name Lucia Smith occupation shopkeeper
In this article we have worked with XML data in C# usingXmlDocument
.
C# XmlDocument read currency rates
In the following example, we read data from European Central Bank.
Program.cs
using System.Xml;var xmlRes = "http://www.ecb.int/stats/eurofxref/eurofxref-daily.xml";var doc = new XmlDocument();doc.Load(xmlRes);XmlNodeList nodes = doc.DocumentElement?.ChildNodes[2]?.ChildNodes[0]?.ChildNodes;foreach (XmlNode xmlNode in nodes!){ if (xmlNode.Attributes == null) continue; var cur = xmlNode.Attributes["currency"]?.Value; var rate = xmlNode.Attributes["rate"]?.Value; Console.WriteLine($"{cur}: {rate}");}
We get the currency rates for Euro.
$ dotnet runUSD: 1.1904JPY: 130.20BGN: 1.9558CZK: 26.031DKK: 7.4369GBP: 0.86518HUF: 356.43PLN: 4.5246RON: 4.9203SEK: 10.1975CHF: 1.0998ISK: 151.90NOK: 10.0940HRK: 7.5673RUB: 91.9588...
C# XmlDocument validate
An XML document with a correct syntax is said to be well formed. Validation isthe process of checking an XML document to confirm that it is both well-formedand also valid. A valid document adheres the rules dictated by a particular DTDor XML schema.
XML Schema, or XML Schema Definition (XSD), is a formal description of thethe structure and the content of an XML document. It is used to validate theXML document.
users.xsd
<?xml version="1.0" encoding="UTF-8"?><xs:schema elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:element name="users" type="usersType"/> <xs:complexType name="userType"> <xs:sequence> <xs:element name="name" type="xs:string"/> <xs:element name="occupation" type="xs:string"/> </xs:sequence> <xs:attribute type="xs:string" name="id"/> </xs:complexType> <xs:complexType name="usersType"> <xs:sequence> <xs:element name="user" type="userType" maxOccurs="unbounded" minOccurs="0"/> </xs:sequence> </xs:complexType> </xs:schema>
We have the schema definition for the users.xml
file.
Program.cs
using System.Xml;using System.Xml.Schema;var xmlFile = "/home/janbodnar/Documents/users.xml";var xmlSchema = "/home/janbodnar/Documents/users.xsd";try{ var settings = new XmlReaderSettings(); settings.Schemas.Add(null, xmlSchema); settings.ValidationType = ValidationType.Schema; settings.ValidationEventHandler += ValidationEventHandler; XmlReader reader = XmlReader.Create(xmlFile, settings); var doc = new XmlDocument(); doc.Load(reader); Console.WriteLine("validation passed");}catch (Exception ex){ Console.WriteLine(ex.Message);}void ValidationEventHandler(object sender, ValidationEventArgs e){ Console.WriteLine($"Document validation error: {e.Message}"); Environment.Exit(1);}
We validate the users.xml
document against theusers.xsd
schema.
C# XmlDocument event
There are event handlers to react to nodes being changed, inserted, or removed.
Program.cs
using System.Xml;var xmlFile = "/home/janbodnar/Documents/words.xml";var doc = new XmlDocument();doc.Load(xmlFile);XmlElement root = doc.DocumentElement;doc.NodeChanged += MyNodeChangedEvent;doc.NodeInserted += MyNodeInsertedEvent;doc.NodeRemoved += MyNodeRemovedEvent;XmlNode node = root?.LastChild;root?.RemoveChild(node!);XmlElement e1 = doc.CreateElement("word");e1.InnerText = "eagle";root?.AppendChild(e1);XmlNode n1 = doc.SelectSingleNode("//words/word[text()='bottom']");Console.WriteLine(n1?.InnerText);if (n1 != null) n1.InnerText = "star";doc.Save("/home/janbodnar/Documents/words3.xml");void MyNodeChangedEvent(Object src, XmlNodeChangedEventArgs args){ Console.WriteLine($"Node Changed Event Fired for node {args.Node?.Name}"); Console.WriteLine(args.Node?.Value);}void MyNodeInsertedEvent(Object src, XmlNodeChangedEventArgs args){ Console.WriteLine($"Node Inserted Event Fired for node {args.Node?.Name}"); Console.WriteLine(args.Node?.Value);}void MyNodeRemovedEvent(Object src, XmlNodeChangedEventArgs args){ Console.WriteLine($"Node Removed Event Fired for node {args.Node?.Name}"); Console.WriteLine(args.Node?.Value);}
In the example, we create three event handlers.
doc.NodeChanged += MyNodeChangedEvent;doc.NodeInserted += MyNodeInsertedEvent;doc.NodeRemoved += MyNodeRemovedEvent;
We plug event handlers for nodes being changed, inserted, and removed.
XmlNode node = root?.LastChild;root?.RemoveChild(node!);
We remove the last child. This triggers the MyNodeRemovedEvent
.
XmlElement e1 = doc.CreateElement("word");e1.InnerText = "eagle";root?.AppendChild(e1);
We create a new node. This triggers the two pieces ofMyNodeInsertedEvent
: one for inserting text and one for insertingthe node.
XmlNode n1 = doc.SelectSingleNode("//words/word[text()='bottom']");Console.WriteLine(n1?.InnerText);if (n1 != null) n1.InnerText = "star";
We modify the content of a node. This triggers theMyNodeChangedEvent
.
$ dotnet run Node Removed Event Fired for node wordNode Inserted Event Fired for node #texteagleNode Inserted Event Fired for node wordbottomNode Changed Event Fired for node #textstar
Source
XmlDocument class - language reference
In this article we have worked with XML data in C# usingXmlDocument
.
Author
My name is Jan Bodnar and I am a passionate programmer with many years ofprogramming experience. I have been writing programming articles since 2007. Sofar, I have written over 1400 articles and 8 e-books. I have over eight years ofexperience in teaching programming.
List all C# tutorials.