Jesper Tverskov, July 8, 2008

Read XML with XmlDocument (W3C DOM)

In ASP.NET we have four main APIs for reading XML. We can use the new LINQ to XML, the XmlReader, the XPathDocument and the XmlDocument classes. In this tutorial we look at XmlDocument. The idea is only to show a basic example for comparison.

1. Read products.xml

I use the following XML document, products.xml, in many of my XML tutorials. How could it be transformed into an XHTML table using XmlDocument? To make the example more interesting, we use CSS for colors, etc.

The idea is only to show a basic example of how to use XmlDocument. There are many more properties and methods and ways of achieving the same result than indicated below. You must look up the proper documentation for all the details.

2. XmlDocument (W3C DOM)

2.1 read-xml-w3cdom.aspx

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="read-xml-w3cdom.aspx.cs" Inherits="read_xml_w3cdom" %><?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
    <title>Read XML with XmlDocument (W3C DOM)</title>
    <style type="text/css">table, td, th{border:1px solid silver; border-collapse:collapse}th{background-color:mistyrose}tr.alt1{background-color: ivory}tr.alt0{background-color: azure}</style>
  </head>
  <body>
    <h1>Using XmlDocument</h1>
    <div id="div1" runat="server" />
  </body>
</html>

2.2 read-xml-w3cdom.aspx.cs  

using System;
using System.Xml;

public partial class read_xml_w3cdom : System.Web.UI.Page
{
  int counter;
  string tr;

  protected void Page_Load(object sender, EventArgs e)
  {
    XmlDocument xmldoc = new XmlDocument();
    xmldoc.Load(Server.MapPath("products.xml"));

    XmlNodeList xmlnodeList = xmldoc.DocumentElement.SelectNodes("product");

    foreach (XmlNode product in xmlnodeList)
    {
      counter++;
      tr += "<tr class='alt" + (counter % 2) + "'><td>" + product.SelectSingleNode("@id").InnerXml.ToString() + "</td><td>" + product.SelectSingleNode("name").InnerXml.ToString() + "</td><td>" + product.SelectSingleNode("price").InnerXml.ToString() + "</td><td>" + product.SelectSingleNode("stock").InnerXml.ToString() + "</td><td>" + product.SelectSingleNode("country").InnerXml.ToString() + "</td></tr>";
    }
    string th= "<th>id</th><th>name</th><th>price</th><th>stock</th><th>country</th>";
    div1.InnerHtml = "<table cellspacing='0' cellpadding='5'>" + th + tr + "</table>";
  }
}

Above we use XmlNodeList but we could also have used XPathNavigator as in the tutorial for XPathDocument. That would have made the code examples for XmlDocument and XPathDocument almost identical except that we use XPathDocument() to load XML when XPathDocument is used and load() to load XML when XmlDocument is used.

If we want to read back and forth on the loaded XML document in memory we should always use the faster XPathDocument or LINQ to XML. XmlDocument (W3C DOM) is only relevant for editing but only if LINQ to XML is not available.

3. Read XML in a namespace

To get to XML in a namespace in a loaded XML hierarchy, we must also declare the same namespace in the code. In XPathDocument and in XmlDocument (W3C DOM) we need to use the XmlNamespaceManager. In XPath 1.0 we can only get to a namespace using a prefix. For that reason we need to make up some "dummy" prefix if we want to get to XML in a default namespace. Below we have chosen "ns".

The markup in products-ns.xml uses the following default namespace: xmlns="http://www.xmlplease.com''. To get to it we need to modify the code from our previous example like this:

XmlDocument xmldoc = new XmlDocument();
xmldoc.Load(Server.MapPath("products-ns.xml"));

XmlNamespaceManager nsMgr = new XmlNamespaceManager(xmldoc.NameTable);
nsMgr.AddNamespace("ns", "http://www.xmlplease.com");
// we always need a prefix even for a default namespace

XmlNodeList xmlnodeList = xmldoc.DocumentElement.SelectNodes("ns:product", nsMgr);

foreach (XmlNode product in xmlnodeList)
{
  counter++;
  tr += "<tr class='alt" + (counter % 2) + "'><td>" + product.SelectSingleNode("@id").InnerXml.ToString() + "</td><td>" + product.SelectSingleNode("ns:name", nsMgr).InnerXml.ToString() + "</td><td>" + product.SelectSingleNode("ns:price", nsMgr).InnerXml.ToString() + "</td><td>" + product.SelectSingleNode("ns:stock", nsMgr).InnerXml.ToString() + "</td><td>" + product.SelectSingleNode("ns:country", nsMgr).InnerXml.ToString() + "</td></tr>";
}

Note that an attribute does not inherit the namespace of its parent element. That is: an attribute without a proper namespace prefix is never in a namespace. That is: attributes in elements in a default namespace are not in a namespace! See my article: Attributes and XML namespaces.

Updated 2008-07-12