C# XmlDocument
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 a set of rules for encoding documents in a format that is both human-readable and machine-readable. XML is often used for application configuration, data storage and exchange.
XML is similar to HTML, but does not have predefined tags; we can design our own tags.
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 XML
document. It implements the W3C XML Document Object Model (DOM).
The Document Object Model (DOM) is a language-independent programming interface for HTML and XML documents. It represents a page. Through the DOM interface, the programs can change the document structure, style, and content. 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 nodes from an XML document. It can be also used to compute values from the content of an XML document.
In the examples, we with the following files:
<?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.
<?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.
<?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
for
the document.
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 of
the 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 with
LoadXml
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
property
returns 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 all
its child nodes.
Console.WriteLine(doc.DocumentElement?.InnerXml);
The InnerXml
property gets or sets the markup representing only the
child nodes of this node.
$ dotnet run words falcon river <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.
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 method does not modify the original file; it modifies the in-memory representation of the document and the modified document is saved into a new file.
C# XmlDocument.CreateElement
The XmlDocument.CreateElement
method creates an element with the
specified name.
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 with
CreateElement
. Its text is set with InnerText
property.
root?.InsertAfter(e1, root.LastChild);
The newly created element is inserted after the last child with
InsertAfter
.
XmlElement e2 = doc.CreateElement("word"); e2.InnerText = "cheetah"; root?.InsertBefore(e2, root.FirstChild);
The second element is inserted before the first element with
InsertBefore
.
C# XmlDocument create new document
In the following example, we create a new XML document.
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 with
AppendChild
. 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 for each 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 ordered
collection of nodes.
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 inner text content.
$ dotnet run falcon sky bottom cup book rock sand river
C# XmlNodeList.Count
The XmlNodeList.Count
property gets the number of nodes in the
XmlNodeList
.
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 matches
the XPath expression.
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 attribute
6.
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 the
desired 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 run Id: 2 Name: Jane Doe Occupation: teacher
C# XmlNode.SelectNodes
The XmlNode.SelectNodes
selects a list of nodes matching the XPath
expression.
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. The
SelectNodes
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
object
from the retrieved data.
$ dotnet run User { 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 an
XmlNodeList
containing a list of all descendant elements that match
the specified tag name.
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 run All capitals: Bratislava Budapest Warsaw Beijing Hanoi
C# XmlDocument.CreateNavigator
The XmlDocument.CreateNavigator
creates a
XPathNavigator
object for navigating the document. The
XPathNodeIterator
provides an iterator over a selected set of
nodes.
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
to
go 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 run 1 John Doe gardener -------------------- 2 Jane Doe teacher -------------------- 3 Roger Roe driver -------------------- 4 Lucia Smith shopkeeper --------------------
C# XmlDocument recursive loop
In the following example, we recursively loop over the tags of the
users.xml
file.
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
method
passing it its first child.
if (node.NextSibling != null) { traverse(node.NextSibling); }
We go recursively to the next sibling if there is any.
$ dotnet run users -------------------- 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# using
XmlDocument
.
C# XmlDocument read currency rates
In the following example, we read data from European Central Bank.
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 run USD: 1.1904 JPY: 130.20 BGN: 1.9558 CZK: 26.031 DKK: 7.4369 GBP: 0.86518 HUF: 356.43 PLN: 4.5246 RON: 4.9203 SEK: 10.1975 CHF: 1.0998 ISK: 151.90 NOK: 10.0940 HRK: 7.5673 RUB: 91.9588 ...
C# XmlDocument validate
An XML document with a correct syntax is said to be well formed. Validation is the process of checking an XML document to confirm that it is both well-formed and also valid. A valid document adheres the rules dictated by a particular DTD or XML schema.
XML Schema, or XML Schema Definition (XSD), is a formal description of the the structure and the content of an XML document. It is used to validate the XML document.
<?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.
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 the
users.xsd
schema.
C# XmlDocument event
There are event handlers to react to nodes being changed, inserted, or removed.
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 of
MyNodeInsertedEvent
: one for inserting text and one for inserting
the 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 the
MyNodeChangedEvent
.
$ dotnet run Node Removed Event Fired for node word Node Inserted Event Fired for node #text eagle Node Inserted Event Fired for node word bottom Node Changed Event Fired for node #text star
Source
XmlDocument class - language reference
In this article we have worked with XML data in C# using
XmlDocument
.
Author
List all C# tutorials.