Export (0) Print
Expand All

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 XContainer.Elements method and the Extensions.Elements method. You can combine these two axes to find all elements of a specified name at a given depth in the tree.

This example uses XContainer.Elements and 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<T> of XContainer. XElement derives from XContainer, so you can call the Extensions.Elements method on the results of a call to the 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 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>
Show:
© 2014 Microsoft