Linq and XML
Monday, 06 December 2010
Article Index
Linq and XML
Subtrees

Banner

Subtrees

Now what about querying sub-trees?

This is very easy and almost doesn’t need any thought. All you have to do is find the node that is the root of the sub-tree and use its Descendants method.

For example:

var q=root.Element("Name").Descendants();

This returns all of the child nodes below the Name XElement in the tree, i.e. First and Second in our earlier example.

Notice that Descendants is “recursive” in the sense that it returns all of the child nodes of the first node specified, then the child nodes of each of those and so on. The order in which the child nodes are returned is described as “document” order, i.e. the order in which the tags appear when the XML is listed down a page.

Notice that if you use a Linq query to return an element you automatically get its “deep” value – i.e. all of the child nodes it contains.

In this sense the query:

var q2 = from E in root.Elements()
  where E.Name == "Name"
   select E;

returns a sub-tree starting at the XElement “Name”. It is slightly different to the previous example because it includes the “Name” node and not just the sub-tree below it.

You can also chain Axis methods just as you can chain standard Linq methods.

For example:

var q=root.Element("Name").Attributes();

finds the first element that matches “Name” and then returns a sequence of its attributes, if any.

Some things are much easier to do with axis methods which are designed to work with a tree structure and some are easier using standard Linq queries which are designed to work with flat collections.

Sometimes a combination of the two works even better. For example consider:

var q = from E in root.Elements()
where (E.Element("First")!=null)
 select E;

This selects all of the elements that have at least one “First” child element. Again as a deep value is returned, you actually get the subtree below any node that has a “First” child node.

Once you start to follow the relentless logic of IEnumerable and its Linq methods it becomes almost fun to try and work out the most “interesting” way of obtaining a result.

Not necessarily good programming practice but a good way to master the techniques.

Select and the projection

The Select part of a Linq expression normally works as a projection operator that “reduces” the size of the data structure returned by a query.

For example, it can be use to select which “columns” are returned from a SQL query which otherwise would return a complete record.

For example, the query

var q = from E in root.Elements()
  where E.Name == "Name"
   select E;

returns a deep copy in the sense that the XElement corresponding to Name brings with it an entire subtree.

Suppose you want a “shallow” copy, i.e. just the node and its text value. In this case we can project the XElement to a string that contains all of the XText in the subtree:

var q = from E in root.Elements()
where E.Name == "Name"
  select E.Value;

However, projection can also be used to create a larger or completely different type using the data returned by the query.

For example, you could perform a Linq to SQL query to return some values and then package them up into an XML tree. To understand how this works all you really have to do is focus on the role of the “range” variable. It is set to each of the objects that match the selection criterion and eventually this can be used to construct any other data type.

For example, suppose you wanted to reconfigure the XML tree that stored the first and second names in our example into a different XML tree. You could do the job using a slightly more advanced select projection:

var q = from E in root.Elements()
where E.Name == "Name"
  select new XElement("NameRecord",
    new XElement("Name1",
              E.Element("First").Value),
    new XElement("Name2",
              E.Element("Second").Value)
);

In this case we take each of the selected elements and build a new XML tree using their values and it is a collection of these new XML trees that are returned.

While this isn’t a particularly useful transformation it gives you the basic idea, i.e. use the result of the query to build new types, and you can generalise it to other situations. In more complex transformations it can even be useful to work out intermediate results to be used later within the select clause.

To create a variable within a Linq expression you simply use the let keyword. For example the previous query can be re-written:

var q = from E in root.Elements()
where E.Name == "Name"
  let z1=E.Element("First")
  let z2=E.Element("Second")
 select
  new XElement("NameRecord",
  new XElement("Name1",z1.Value),
  new XElement("Name2",z2.Value));

In this case the let keywords create two new variables z1 and z2 which are used to hold the child elements that match the two sub-queries. Notice that the result is exactly the same if you don’t use the temporary variables.

Notice that you can even use the select to modify the existing XML tree using SetValue and so on but – be warned a tree is a complicated structure and you need to be sure that what you are trying to do can be done in every case.

In most cases it is much better to use the functional approach to build a new tree as part of the select clause. Notice that this is made even more powerful by the simple fact that the constructors can accept IEnumeration sequences and will automatically iterate through all of the objects thus adding them to the new tree.

For example, consider:

var q = from E in root.Elements()
where E.Name == "Name"
  select
   new XElement("NameRecord",
                  root.Attributes(),
   new XElement("Name1",
   E.Element("First").Value),
   new XElement("Name2",
            E.Element("Second").Value));

Notice that the use of root.Attributes adds all of the attributes in the collection to the new XElement corresponding to the tag <NameRecord>.

Linq, and Linq to XML in particular, provides so many ways of doing things that it can leave you feeling slightly queasy about the whole thing and it is certain that you can write code that is deep and impenetrable – don’t.

 

If you would like to be informed about new articles on I Programmer you can either follow us on Twitter, on Facebook , on Digg or you can subscribe to our weekly newsletter.

 

Banner


XML in C# - Using XElement

.NET has some really easy-to-use facilities for creating and editing XML. Many of these facilities were introduced to make Linq to XML work better, but you can make use of them in more general situati [ ... ]



What's The Matter With Pointers?

Back in the days when C was the language of choice, pointers meant programming and vice versa. Now in the more sophisticated and abstract days of C#, and even C++, raw pointers are a facility that is  [ ... ]


Other Articles

<ASIN: 0596002521>

<ASIN:193435645X>

<ASIN:0470191376>

Last Updated ( Monday, 06 December 2010 )
 
 

   
RSS feed of all content
I Programmer - full contents
Copyright © 2014 i-programmer.info. All Rights Reserved.
Joomla! is Free Software released under the GNU/GPL License.