How to: Chain Axis Method Calls (LINQ to XML)

A common pattern that you will use in your code is to call an axis method, then call one of the extension method axes.

There are two axes with the name of Elements that return a collection of elements: the System.Xml.Linq.XContainer.Elements method and the System.Xml.Linq.Extensions.Elements method. You can combine these two axes to find all elements of a specified name at a given depth in the tree.

Example

This example uses System.Xml.Linq.XContainer.Elements and System.Xml.Linq.Extensions.Elements to find all Name elements in all Address elements in all PurchaseOrder elements.

This example uses the following XML document: Sample XML File: Multiple Purchase Orders (LINQ to XML).

XElement purchaseOrders = XElement.Load("PurchaseOrders.xml");
IEnumerable<XElement> names =
    from el in purchaseOrders
        .Elements("PurchaseOrder")
        .Elements("Address")
        .Elements("Name")
    select el;
foreach (XElement e in names)
    Console.WriteLine(e);

This example produces the following output:

<Name>Ellen Adams</Name>
<Name>Tai Yee</Name>
<Name>Cristian Osorio</Name>
<Name>Cristian Osorio</Name>
<Name>Jessica Arnold</Name>
<Name>Jessica Arnold</Name>

This works because one of the implementations of the Elements axis is as an extension method on IEnumerable of XContainer. XElement derives from XContainer, so you can call the System.Xml.Linq.Extensions.Elements method on the results of a call to the System.Xml.Linq.XContainer.Elements method.

Sometimes you want to retrieve all elements at a particular element depth when there might or might not be intervening ancestors. For example, in the following document, you might want to retrieve all the ConfigParameter elements that are children of the Customer element, but not the ConfigParameter that is a child of the Root element.

<Root>
  <ConfigParameter>RootConfigParameter</ConfigParameter>
  <Customer>
    <Name>Frank</Name>
    <Config>
      <ConfigParameter>FirstConfigParameter</ConfigParameter>
    </Config>
  </Customer>
  <Customer>
    <Name>Bob</Name>
    <!--This customer doesn't have a Config element-->
  </Customer>
  <Customer>
    <Name>Bill</Name>
    <Config>
      <ConfigParameter>SecondConfigParameter</ConfigParameter>
    </Config>
  </Customer>
</Root>

To do this, you can use the System.Xml.Linq.Extensions.Elements axis, as follows:

XElement root = XElement.Load("Irregular.xml");
IEnumerable<XElement> configParameters = 
    root.Elements("Customer").Elements("Config").
    Elements("ConfigParameter");
foreach (XElement cp in configParameters)
    Console.WriteLine(cp);

This example produces the following output:

<ConfigParameter>FirstConfigParameter</ConfigParameter>
<ConfigParameter>SecondConfigParameter</ConfigParameter>

The following example shows the same technique for XML that is in a namespace. For more information, see Working with XML Namespaces.

This example uses the following XML document: Sample XML File: Multiple Purchase Orders in a Namespace.

XNamespace aw = "http://www.adventure-works.com";
XElement purchaseOrders = XElement.Load("PurchaseOrdersInNamespace.xml");
IEnumerable<XElement> names =
    from el in purchaseOrders
        .Elements(aw + "PurchaseOrder")
        .Elements(aw + "Address")
        .Elements(aw + "Name")
    select el;
foreach (XElement e in names)
    Console.WriteLine(e);

This example produces the following output:

<aw:Name xmlns:aw="http://www.adventure-works.com">Ellen Adams</aw:Name>
<aw:Name xmlns:aw="http://www.adventure-works.com">Tai Yee</aw:Name>
<aw:Name xmlns:aw="http://www.adventure-works.com">Cristian Osorio</aw:Name>
<aw:Name xmlns:aw="http://www.adventure-works.com">Cristian Osorio</aw:Name>
<aw:Name xmlns:aw="http://www.adventure-works.com">Jessica Arnold</aw:Name>
<aw:Name xmlns:aw="http://www.adventure-works.com">Jessica Arnold</aw:Name>

See Also

Concepts

LINQ to XML Axes




Build Date:

2012-08-02
Show: