Using LINQ to XML with XDocument, XElement, XAttribute and XNamespace

One of the interesting features of LINQ is LINQ to XML, if you compare the capabilies of system.xml.linq to system.xml

When creating a new XML document with LINQ to XML you will be using the system.xml.linq namespace, instead of the default system.xml namespace. The primary classes you will use to build a new XML document will be the XDocument, XElement and XAttribute classes.

Creating a new XML document can easily be done with LINQ to XML as following:

LINQ to XML create new document

As usual, when creating XML we start by creating the document which has 1 root node, which in our case is the XElement with name “Customers”. Within the rootnode Customers there will be childnodes “Customer”, which will also hold childnodes which contain information about the customer. LINQ to XML allows you to create an entire XML document by just adding elements within the constructor of the XDocument and XElement classes:

LINQ to XML XElement constructor

The XElement constructor allows you to add the name of the node and allows you define a params object[] as content, which basically means you can add a list of XElements as content without having to leave your sequence. For some people constructing an XML in a single continuous line of code might not be appealing, but for some it might. Note that in the params object[] constructor parameter I add XElements for the Customer, but for the Order Price and Order Data I add XAttribute elements instead of XElement. The runtime knows how to construct the XML document depending on the class you append, so you can add XElements and XAttributes through eachother and leave the XML construction to the runtime.

If you are not a fan of the params object[] constructor parameter, you could write the code like this aswell:

LINQ to XML

Now I think it’s pretty obvious at some times it might be very handy to use the params object[] constructor parameter to add content to an XElement. Otherwise you end up getting lengthy code for something that even looks less obvious to what sort of XML you are creating. The first way of creating XML parts can be a lot more obvious then the second way. This is a personal choise and opinion, but I like the params object[] parameter to add content to my XElement.

If you run this method, a new XML file Customers.Xml will be created in your output directory:

LINQ to XML

The Save method on the XDocument lets you easily save the file. And the XML file will look like this:

LINQ to XML XDocument and XElement

If you do not know how to work with Entity Framework ADO.NET Entity Data Model, you can find more information on my blog regarding this topic. The AdventureWorks database can be downloaded here:
http://msftdbprodsamples.codeplex.com/releases/view/59211 

I added an ADO.NET Entity Data Model on my AdventureWorks database to work with some real data in my database.

For working with some real data we want to create an XML document that returns a list of Customers with the Orders that customer made. This data is in the AdventureWorks database and I will retrieve it with LINQ to Entities, from which I will construct the XML then.

Retrieving the information and writing it to XML:

LINQ to XML

I first retrieve the needed information by LINQ to Entities which results in a List<Anonymous Type> (The LINQ query is not optimal. If you can get a better one, please tell me how to). Finally with the ForEach LINQ extension method on the result list and a lambda expression I manage to create a “Customer” XElement for each result we have in our list and by the params object[] constructor parameter I pass on child values for the Customer node.

The start of our XML would look like this after it has been saved:

LINQ to XML

Processing on the XML we saved before is just as easy:

LINQ to XML

You can invoke the static method Load on the XDocument class to load the XML again. We ask the document descendants of “Customer” and for each of the customer node we find we execute a lambda expression which writes the name of the customer and the total sum of all the orders of that customer to the output window. One of the interesting things to notice is that for the sum I use (double)o.Element(“Total”) and not o.Element(“Total”).Value. If the Total node would not exist for some reason, the .Value method on the node would fail due to a null reference exception. The casting before the node solves this issue, if the node is null, the cast to the double will result in 0.

Executing the console application:

LINQ to XML

One of the things you might want to pay attention to is the XML namespaces. Suppose we change our code the create the XML so that the XML belongs to a namespace:

LINQ to XML

We create a XNamespace and set the url of the namespace we want to use. To create our XElements now by doing new XElement(ns + “Nodename”), meaning we pass the namespace with each element we create to belong to this namespace. If you do not pass the namespace along, the node will be marked with xmlns=””, to mark that the node does not belong to the default namespace of the document. This is very important, because when querying on the xml document, you will not find the items in the namespace if you are not searching within that particular namespace!

If you now execute the code to process the xml, you won’t get any results back:

LINQ to XML

We are querying for XML nodes that do not belong within a namespace, while our XML has been changed and our complete XML belongs to a namespace now:

LINQ to XML

We will have to adapt our processing query to look for elements that also belong to the namespace “http://robbincremers.me/Customers&#8221;:

LINQ to XML

Executing the console application again now:

LINQ to XML

The processing code uses the ForEach extension method, but you can just as well write it by the comprehension query:

LINQ to XML

Any suggestions, remarks or improvements are always welcome.
If you found this information useful, make sure to support me by leaving a comment.

Cheers and have fun,

Robbin

About these ads