Jesper Tverskov, July 8, 2008

Read XML with LINQ to XML

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. LINQ to XML

2.1 read-xml-linq.aspx

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="read-xml-linq.aspx.cs" Inherits="read_xml_linq" %><?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 LINQ to XML</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-linq.aspx.cs  

using System;
using System.Xml.Linq;

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

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

    foreach (XElement product in xmlDoc.Root.Nodes())
    {
      counter++;

      tr += "<tr class='alt" + (counter % 2) + "'><td>" + product.Attribute("id").Value + "</td><td>" + product.Element("name").Value + "</td><td>" + product.Element("price").Value + "</td><td>" + product.Element("stock").Value + "</td><td>" + product.Element("country").Value + "</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>";
  }
}

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. LINQ to XML handles XML namespaces like a dream compared to XmlDocument (W3C DOM) and XPathDocument. Default namespace and namespaces using a prefix are handled exactly the same. We only care about the namespaces and simply ignore the prefixes for them.

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:

XDocument xmlDoc = XDocument.Load(Server.MapPath("products-ns.xml"));
XNamespace ns = "http://www.xmlplease.com";

foreach (XElement product in xmlDoc.Root.Nodes())
{
  counter++;
  tr += "<tr class='alt" + (counter % 2) + "'><td>" + product.Attribute("id").Value + "</td><td>" + product.Element(ns +"name").Value + "</td><td>" + product.Element(ns +"price").Value + "</td><td>" + product.Element(ns + "stock").Value + "</td><td>" + product.Element(ns + "country").Value + "</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