Let's start with following sample contractors.xml file and let me show you how
to quickly add, update & delete example!
<?xml version="1.0" encoding="utf-8"?>
<contractors>
<contractor title=".NET developer">
<name>Jay</name>
<email>abc@xyz.com</email>
<rate>25$</rate>
<country>India</country>
</contractor>
<contractor title="Windows 8 developer">
<name>Hrishikesh</name>
<email>def@xyz.com</email>
<rate>25$</rate>
<country>India</country>
</contractor>
<contractor title="Hadoop developer">
<name>Kapil</name>
<email>ghi@xyz.com</email>
<rate>35$</rate>
<country>India</country>
</contractor>
</contractors>
Listing 1.0 – Sample contractors.xml file
Add node
Following piece of code will add new node in our sample xml file.
//Add node
XmlDocument doc = new XmlDocument();
doc.Load("contractors.xml");
XmlNode currNode;
XmlDocumentFragment docFrag = doc.CreateDocumentFragment();
docFrag.InnerXml = @"<contractor title='.iOS developer'>
<name>Mahek</name>
<email>jkl@xyz.com</email>
<rate>45$</rate>
<country>USA</country>
</contractor>";
currNode = doc.DocumentElement;
currNode.InsertAfter(docFrag, currNode.LastChild);
doc.Save(contractorFileName);
Listing 1.1 – Adding node in contractors.xml
As per Listing 1.1, first we loaded xml file in XmlDocument to fire our XPath queries.
Then we created document fragment and set it's InnerXml to new node value
and finally we inserted it after current node.
Update node
Following piece of code will updated existing node for contractor Mahek.
//Update node
XmlDocument doc = new XmlDocument();
doc.Load(contractorFileName);
//Select the cd node with the matching title
XmlNode oldCd;
XmlElement root = doc.DocumentElement;
oldCd = root.SelectSingleNode("/contractors/contractor[@name='Mahek']");
XmlElement newCd = doc.CreateElement("contractor");
newCd.SetAttribute("title", "Android developer");
newCd.InnerXml = @"<name>Mahek</name>
<email>jkl@xyz.com</email>
<rate>45$</rate>
<country>USA</country>
";
root.ReplaceChild(newCd, oldCd);
doc.Save(contractorFileName);
Listing 1.2 – Updating node in contractors.xml
As you can see in Listing 1.2, first we select the node to be updated with SelectSingleNode
method and we change it's InnerXml. Later we use ReplaceChild method to replace
old node value with the new one.
Delete node
Following piece of code will delete existing node for contractor Kapil.
XmlDocument doc = new XmlDocument();
doc.Load(contractorFileName);
XmlNode cd;
XmlElement root = doc.DocumentElement;
cd = root.SelectSingleNode("/contractors/contractor[name='Kapil']");
root.RemoveChild(cd);
doc.Save(contractorFileName);
Listing 1.3 – Deleting node in contractors.xml
In Listing 1.3, the code is pretty much the same as update node but we use RemoveChild
method to delete the node.
Let's see examples of querying XML for following few scenarios.
1. Query top 2 records only
XmlDocument doc = new XmlDocument();
doc.Load(contractorFileName);
XmlNodeList xnList = doc.SelectNodes("/contractors/contractor[position() <= 2]");
foreach (XmlNode xn in xnList)
{
Console.WriteLine(xn.InnerText);
}
Listing 1.4 – Querying xml using position function
2. Select record based on multiple criteria
XmlDocument doc = new XmlDocument();
doc.Load(contractorFileName);
XmlNodeList xnList = doc.SelectNodes("/contractors/contractor[@title='.NET developer' and @rate='25$']");
foreach (XmlNode xn in xnList)
{
Console.WriteLine(xn.InnerText);
}
Listing 1.5 – Querying xml involving multiple select criteria
3. Sort xml on name element as sort key
XmlDocument doc = new XmlDocument();
doc.Load(contractorFileName);
XPathNavigator navigator = doc.CreateNavigator();
XPathExpression selectExpression = navigator.Compile("/contractors/contractor");
selectExpression.AddSort("name", XmlSortOrder.Ascending, XmlCaseOrder.None, "", XmlDataType.Text );
XPathNodeIterator nodeIterator = navigator.Select(selectExpression);
while (nodeIterator.MoveNext())
{
XmlElement xnm = (XmlElement)((IHasXmlNode)nodeIterator.Current).GetNode();
Console.WriteLine(xnm["name"].InnerText);
}
Listing 1.6 – Sorting xml using XPathExpression
In Listing 1.6, we created XPathNavigator object and compiled our selectExpression.
The XPathExpression has AddSort method where you can give attribute or element
name to specify it as a sort key. Finally we iterate on XPathNodeIterator object
and the output will show you name sorted alphabetically.
So far so good as we are playing with simple xml file. Let's have another sample
drinks.xml as following:
<?xml version="1.0" encoding="utf-8" ?>
<drinks>
<drink>
<corona brand="Maxican">
<price>$3.50</price>
<alcohol>4%</alcohol>
</corona>
<kingfisher brand="Indian">
<price>$1.50</price>
<alcohol>8%</alcohol>
</kingfisher>
<knockout brand="Indian">
<price>$0.50</price>
<alcohol>6%</alcohol>
</knockout>
</drink>
</drinks>
Listing 1.7 – Sample drinks.xml file
As you see in Listing 1.7, there are different nodes under drink tag. So if you would
like to obtain price for each drink, you would write something like following:
drinks/drink/corona/price
drinks/drink/kingfisher/price
drinks/drink/knockout/price
So you see the query differs for each node. But you can write a single query to obtain
the same using // sequence.
drinks/drink//price
That way, our complete code would be as following:
XmlDocument doc = new XmlDocument();
doc.Load(drinksFileName);
XmlNodeList xnList = doc.SelectNodes("drinks/drink//price");
foreach (XmlNode xn in xnList)
{
Console.WriteLine(xn.InnerText);
}
Listing 1.8 – Select price of all drinks using // sequence
Amazon response xml
The other day I was playing with Amazon product advertising API. I came across scenario
where I need to deal with namespace in xml document. Following is the portion
of the XML that I was getting in response.
<?xml version="1.0"?>
<ItemSearchResponse xmlns="http://webservices.amazon.com/AWSECommerceService/2011-08-01">
<OperationRequest>
<RequestId>195e50a2-d4b2-4389-9ff5-66bdf8e87892</RequestId>
<Arguments>
<Argument Name="Operation" Value="ItemSearch"></Argument>
<Argument Name="Service" Value="AWSECommerceService"></Argument>
<Argument Name="AssociateTag" Value="mj"></Argument>
<Argument Name="BrowseNode" Value="962454"></Argument>
<Argument Name="Timestamp" Value="2013-11-02T15:39:14Z"></Argument>
<Argument Name="ResponseGroup" Value="ItemAttributes"></Argument>
<Argument Name="SearchIndex" Value="Music"></Argument>
</Arguments>
<RequestProcessingTime>0.1213320000000000</RequestProcessingTime>
</OperationRequest>
</ItemSearchResponse>
Listing 1.9 – Sample amazonresponse.xml file
So here we will select Name attribute value from all Argument tag. To do so, the
code would go something like following:
XmlDocument doc = new XmlDocument();
XmlNamespaceManager mgr = new XmlNamespaceManager(doc.NameTable);
mgr.AddNamespace("aws", "http://webservices.amazon.com/AWSECommerceService/2011-08-01");
doc.Load(amazonFileName);
XmlNodeList xnList = doc.SelectNodes("aws:ItemSearchResponse/aws:OperationRequest/aws:Arguments/aws:Argument/@Name", mgr);
foreach (XmlNode xn in xnList)
{
Console.WriteLine(xn.Value);
}
Listing 1.10 – Query using xml namespace manager
Here as per Listing 1.10, the XmlNamespaceManager object is designed to serve as
a collection of namespace definitions. It is used by the .NET Framework XML processors
to resolve and manage the scope of namespaces used in XML documents. Note that
while accessing elements, we also need to precede each node with the namespace
that we added in namespace manager.
Additional xpath query examples can be found on our XPath Examples for Node, Attribute, and Substring Queries page.
Source Code
You can grab the source code here.