LINQ to XML

Welcome to this installment of the .NET Nuts & Bolts column. The prior .NET Nuts & Bolts article provided an Introduction to Language Integrated Query (LINQ). This article will build on the LINQ introduction and focus on LINQ to XML for unified data access of XML-based data. You'll begin with a look at challenges with the traditional Document Object Model (DOM) means of accessing and traversing XML, and then jump in to the benefits of LINQ to XML and how it tames XML in a unified manner. This will be part two of a few articles that cover LINQ in some detail.

Challenges with Traditional XML

Extensible Markup Language (XML) has been around longer than the original public release of the Microsoft .NET Framework 1.0. The Document Object Model (DOM) has long been used to manage in-memory representations of XML documents along with XPath and XQuery. Anyone who has had the experience of using it to create a large or complex XML representation of data can commiserate with the overly complex nature of creating and appending combinations of elements and attributes to an XML document over and over again. Just as complex is searching or querying an XML document for a particular element or attribute value. In my opinion, it has always been much more complex than it really needs to be. The following sample code demonstrates a creation of a simple XML document using DOM:

XmlDocument document = new XmlDocument();
XmlElement customer  = document.CreateElement("Customer");
XmlElement firstName = document.CreateElement("FirstName");
XmlElement lastName  = document.CreateElement("LastName");
firstName.InnerText  = "Mark";
lastName.InnerText   = "Strawmyer";
customer.AppendChild(firstName);
customer.AppendChild(lastName);
document.AppendChild(customer);

The preceding code is a very simple example, and it also produces only a very simple XML document. Anything with a large number of nodes requires an awful lot of object creation and repetitive code structure. Searching the XML for elements such as FirstName is an additional set of code.

Introducing LINQ to XML

LINQ and its ability to provide a unified data access model is just the solution to eliminate many challenges with traditional XML. LINQ to XML uses LINQ extension methods to read, create, search, and generally deal with XML in a simplified manner.

LINQ to XML Helper Objects

The previous pattern involved in creating XML is to create a node, set a value, and append the child. This involves multiple lines of code. LINQ to XML introduces a number of helper objects in the System.Xml.Linq namespace designed to allow developers to build and manage XML contents through parameter arrays and other functions that allow for an XML statement to be created in a single line of code. The following list of helper objects have been made available:

  • XDocument: Represents an XML document instance
  • XNamespace: Incorporates prefixes by allowing for XNamespace and a string to be used for a name
  • XComment: Inserts a comment
  • XElement: Represents an XML element that can be used as the container of any XML fragment
  • XAttribute: Represents an XML attribute

The following sample demonstrates a sample of XML functional construction. Notice how it can be generated in a single line of code by using nested constructors as opposed to the traditional DOM approach that involves creating a number of objects on multiple lines of code.

XDocument customer =
   new XDocument(
      new XElement("Customer",
         new XElement("FirstName", "Mark"),
         new XElement("LastName", "Strawmyer")));

Test Driving LINQ to XML through Examples

Now that you've covered the background, you can explore a couple of examples of LINQ to XML. The examples will demonstrate the use of the helper objects along with an example of querying a sample XML document.

Creating XML from a Database

For this example, I downloaded the Northwind sample database and loaded it in my SQL Server so that I could retrieve and test data from it. I added a LINQ to SQL data class (which you'll look at closer in the next article) connected to the Northwind database. The following example code uses LINQ syntax to query data from the database and then uses LINQ to XML helper objects to generate and save a new XML document. As you can see, you don't have to use LINQ to XML to use the helper objects.

NorthwindDataContext db = new NorthwindDataContext();

XElement xe = new XElement("customers",
   from c in db.Customers
   where c.CompanyName.StartsWith("Split")
   select
      new XElement("customer",
         new XAttribute("Company", c.CompanyName),
         new XAttribute("Name", c.ContactName),
         new XAttribute("Title", c.ContactTitle),
         new XAttribute("City", c.City)));

xe.Save("customers.xml");

The following XML snippet represents the output from the preceding example based on the contents of the Northwind database sample:

<?xml version="1.0" encoding="utf-8" ?>
<customers>
   <customer Company="Split Rail Beer & Ale"
             Name="Art Braunschweiger"
             Title="Sales Manager"
             City="Lander" />
</customers>

Querying XML by Using LINQ to XML

In this example, you'll load an example XML data file that contains information on real estate listings. In this case, I have an XML file from what used to be expo.live.com that will be used. I've abbreviated the sample file to a single entry so that it fits into the article text and saved it in a file called exporss.xml.

<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0"
     xmlns:classifieds="http://expo.live.com/ns/2006/1.0"
     xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#">
   <channel>
      <title>Expo RSS Feed</title>
      <link>http://expo.live.com/</link>
      <description>Expo RSS feed</description>
      <language>en-US</language>
      <pubDate>Wed, 25 Jul 2007 15:46:25 GMT</pubDate>
      <classifieds:totalListings>2384</classifieds:totalListings>
      <item>
         <title>
            Home for Rent early August: 4 bedrooms—2.5 baths
         </title>
         <link>
            http://expo.live.com/ViewListing.aspx?lid=5870094
         </link>
         <description>
            Light and bright home that says "Welcome Home".
         </description>
         <pubDate>Wed, 25 Jul 2007 05:20:00 GMT</pubDate>
         <classifieds:listingid>5870094</classifieds:listingid>
         <classifieds:expirationDate>
            Wed, 19 Sep 2007 05:15:00 GMT
         </classifieds:expirationDate>
         <classifieds:currency>USD</classifieds:currency>
         <classifieds:price>2200.00</classifieds:price>
         <classifieds:category classifieds:id="18"
            classifieds:name="Houses"
            classifieds:transactionType="For Rent">
         </classifieds:category>
         <classifieds:postedBy>Joannede</classifieds:postedBy>
         <classifieds:location>
            <classifieds:address></classifieds:address>
            <classifieds:city>Redmond</classifieds:city>
            <classifieds:state>WA</classifieds:state>
            <classifieds:country>US</classifieds:country>
            <classifieds:postcode>98052</classifieds:postcode>
            <classifieds:latitude>
               47.6870625585192
             </classifieds:latitude>
            <classifieds:longitude>
               -122.118400170762
         </classifieds:longitude>
         </classifieds:location>
         <geo:lat>47.6870625585192</geo:lat>
         <geo:long>-122.118400170762</geo:long>
         <classifieds:details>
            <classifieds:NUMBER_BEDROOMS>
               4
            </classifieds:NUMBER_BEDROOMS>
            <classifieds:NUMBER_BATHROOMS>
               2.5
             </classifieds:NUMBER_BATHROOMS>
            <classifieds:YEAR_BUILT></classifieds:YEAR_BUILT>
            <classifieds:LOT_SIZE>2500</classifieds:LOT_SIZE>
         </classifieds:details>
      </item>
   </channel>
</rss>

LINQ to XML

The following sample code demonstrates a static method that will load up a copy of the sample XML, query it for houses in the given range, and then return a string based on what is found.

static string QueryXML(int lowPrice, int hiPrice)
{
   XNamespace classifieds = "http://expo.live.com/ns/2006/1.0";
   XNamespace geo = "http://www.w3.org/2003/01/geo/wgs84_pos#";

   XElement expoData = XElement.Load(@"exporss.xml");

   var houses = from item in
      expoData.Elements("channel").Elements("item")
      let price = (double)item.Element(classifieds + "price")
      where price > lowPrice && price < hiPrice
      orderby price
      select item;

   string strOut = "";

   foreach (var house in houses)
   {
      strOut += String.Format("\r\nPrice = {0} {1}",
         (string)house.Element(classifieds + "price"),
         (string)house.Element("description"));

   }

   return strOut;
}

Summary

You now have seen LINQ to XML and the simplicity that it can bring to working with XML. Additionally, you saw a mechanism for querying with LINQ to XML that has been shown in benchmark studies from Microsoft to outperform DOM. Hopefully, it also provided you with additional appreciation for the unified access that LINQ can provide to various data sources.

Future Columns

The topic of the next column is likely to be LINQ to SQL. If you have something else in particular that you would like to see explained here, you could reach me at mark.strawmyer@crowehorwath.com.



About the Author

Mark Strawmyer

Mark Strawmyer is a Senior Architect of .NET applications for large and mid-size organizations. He specializes in architecture, design and development of Microsoft-based solutions. Mark was honored to be named a Microsoft MVP for application development with C# for the fifth year in a row. You can reach Mark at mark.strawmyer@crowehorwath.com.

Comments

  • There are no comments yet. Be the first to comment!

Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • You may already know about some of the benefits of Bluemix, IBM's open platform for developing and deploying mobile and web applications. Check out this webcast that focuses on building an Android application using the MobileData service, with a walk-through of the real process and workflow used to build and link the MobileData service within your application. Join IBM's subject matter experts as they show you the way to build a base application that will jumpstart you into building your own more complex app …

  • Agile methodologies give development and test teams the ability to build software at a faster rate than ever before. Combining DevOps with hybrid cloud architectures give teams not just the principles, but also the technology necessary to achieve their goals. By combining hybrid cloud and DevOps: IT departments maintain control, visibility, and security Dev/test teams remain agile and collaborative Organizational barriers are broken down Innovation and automation can thrive Download this white paper to …

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds