Blocks4.NET .net components for .net developers
Interested in getting reliable email hosting or server web hosting for your business? Check up out today!

Querying XML documents with LINQ to XML

August 6, 2007 15:20 by blocks4

Language-Integrated Query (LINQ) is a new approach that unifies the way data can be retrieved in .NET. There already has been a lot of talking about the power of LINQ and if you had the chance to test its capabilities you can surely confirm that. To resume in a few words what particular feature nominates LINQ as an efficient and elegant approach for data accessing, I want to mention that almost any data structure (arrays, relational data, collections and XML) can become a data source using LINQ.

While .NET includes a library to manage XML (System.XML), LINQ to XML extends this namespace bringing the standard query operators and integrating them with XML documents (System.XML.Linq). We can load an XML document into memory and then use LINQ syntax to query it. For a developer accustomed with the SQL queries, LINQ syntax may seem like an up-side down language, but the elements of this syntax have a very comprehensive logic and the query develops naturally.

Now let’s talk about a few basic examples using LINQ to XML. The sample XML document used can be found here and it is a slightly modified version of the document used by Microsoft in many examples related to XML handling. For testing these operations I have created a new Console Application in Visual Studio 2008 Beta 2 (it is a quick way of seeing the results) so make sure you properly include the XML test file in a similar project.

For loading the XML document into memory we can use the Load method of the XDocument class. I chose to use this one because my first example involves the root element <catalog>. If otherwise you want to go straight to a particular element in the document, you can use the Load method of the XElement class. Let’s say we want to display all the main elements contained by <catalog>, so all the <book> elements:

XDocument xmlFile = XDocument.Load("books.xml");

var query = from c in xmlFile.Elements("catalog").Elements("book")

select c;

foreach (XElement book in query)

{

Console.WriteLine(book.Value.ToString());

}

The output will be constituted of all the information included in a node of type <book>, without the display of any child tags. On the other hand, if we exclude the Value property when writing to the console, the result will contain all the <book> nodes and their child nodes structure, exactly the way we see it in the XML document.

Next, let’s say we want to find out which books are currently available. For this we need to search some attribute values, more exactly, the checked-out attribute of the <book> element.

var query = from c in xmlFile.Elements("book")

where (string)c.Attribute("checked-out").Value == "false"            

select c;

foreach (var book in query)

{

Console.WriteLine("\”{0}\” is available", book.Element("title").Value);

}

For navigating through nested elements we can use the Descendants method. In addition to this method, if that particular node has some attributes that you might need in your query, use the Attributes method, and, in this case, notice that the members of the query object are of XAttribute type. Here is how we find out how many books include in their description the key word “.NET”.

var query = from c in xmlFile.Descendants("description")

where c.Value.Contains(".NET")

select c;

Console.WriteLine("We found {0} book(s) on .NET", query.Count());

We can take a step further and try to find out what is the total value of all the books written by every author. Here is the code snippet and I’ll explain on it what syntax elements are used:

var query = from c in xmlConfigFile.Descendants("book")

group new

{             

Author = (string)c.Element("author"), BookValue = (double)c.Element("value")      

}      

by (string)c.Element("author")      

into groupedData

select new

{

AuthorName = groupedData.Key, BooksTotalValue = groupedData.Sum(rec => rec.BookValue)

}; 

foreach (var v in query)

{

Console.WriteLine("Author: {0}; Value of all this author's books: {1}", v.AuthorName, v.BooksTotalValue);

}

So, first of all, we want to select information from all the <book> elements in the XML document. This information is then grouped in a new object, or record if you like, (there are some syntax elements here related to LINQ to Objects) and we’ll retain for this the author attribute and the value of the book (this approach is even more useful if you’d like your new record to store an information related to more than one attribute, like having multiple values and you are interested in a value obtained by summing those numbers). The grouping is made by author’s name and the new entity  will be called groupedData. From this data we then select a new record which will have a property called AuthorName and who’s value is the key by which the grouping was made, and another attribute called BooksTotalValue which will hold the summing of all the books from that author.

I’d like to emphasize here the use of a lambda expression when calling the Sum method for our grouped data. For a better understanding of that expression we can consider an analogy with the C# 2.0 anonymous methods. Syntactically, a lambda expression is written as a parameter list followed by a “=>” token and then followed by a statement block to execute when the expression is invoked (in our case, it will just return a double value). Follow this link for a deeper analysis of lambda expressions: http://weblogs.asp.net/scottgu/archive/2007/04/08/new-orcas-language-feature-lambda-expressions.aspx

I hope that these short examples offer a clear view on some LINQ on XML capabilities and that you will have now the curiosity to further explore the ways in which you can read data from an XML document, and, even more, to create, modify or transform XML files using the power of LINQ.

 


Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Related posts

Comments

Add comment


(Will show your Gravatar icon)  

  Country flag