Support for XPath and System.Xml.XPath
One last group of extension methods offered by LINQ to XML is
related to System.Xml.XPath integration. The
System.Xml.XPath.Extensions class provides a few extension methods
useful for managing XNode contents via XPath. The first
method is CreateNavigator, which returns an
XPathNavigator:
Internally, it creates an instance of an XNodeNavigator
class, which is derived from XPathNavigator and is
specifically defined to navigate X* class graphs. The main goal of this method
is to make possible the transformation of an XNode using
standard System.Xml.Xsl classes. XslCompiledTransform
can work with XPathNavigator derived classes as input.
Listing 6-39 provides sample code that transforms our customers list
using the XSLT we defined in
Listing 6-26.
Listing 6-39: XSLT
transformation using XslCompiledTransform and the CreateNavigator extension
method
XslCompiledTransform xslt = new XslCompiledTransform();
xslt.Load(@"..\..\customerFromSourceToDestination.xslt");
xslt.Transform(sourceXmlCustomers.CreateNavigator(), null, Console.Out);
Another interesting method is XPathEvaluate,
which evaluates an XPath rule against the current XNode,
returning its value by using the internal class XPathEvaluator.
The code in Listing 6-40 selects all
attributes of name “name” of all the customers located
in Italy.
Listing 6-40: Sample
usage of the XPathEvaluate extension method
XElement xmlCustomers = new XElement("customers",
from c in customers
select new XElement("customer",
new XAttribute("name", c.Name),
new XAttribute("city", c.City),
new XAttribute("country", c.Country)));
var result = (IEnumerable<Object>)xmlCustomers.XPathEvaluate(
"/customer[@country = 'Italy']/@name");
foreach (var item in result) {
Console.WriteLine(item);
}
Consider that, in the current beta version of LINQ to XML, the
XPathEvaluateMethod cannot determine the result of the XPath query.
Therefore, it always returns a value of type Object. It
is our responsibility to know and correctly cast the result type. The last two
methods to take care of are XPathSelectElement and
XPathSelectElements. The former returns the first element
corresponding to the XPath expression provided as an
argument, and the latter returns the full list of elements matching the
expression. Internally, they both use the XPathEvaluator
class. The following example selects all the customer elements
of customers located in Italy:
This method is sometimes useful for defining LINQ queries that work
on a subset of nodes of the source XML graph-in case we need to filter
customer elements by the country attribute
value. An example is shown in Listing 6-41.
Listing 6-41: Sample
LINQ query over the result of the XPathSelectElements extension method
var ordersOfItalianCustomersFromXml =
from c in xmlCustomers.XPathSelectElements(
"/customer[@country = 'Italy']")
let xName = (String)c.Element("name")
let xCity = (String)c.Attribute("city")
join o in orders
on xName equals o.Name
orderby xName
select new {
Name = xName,
City = xCity,
IdProduct = o.IdProduct,
Quantity = o.Quantity };
Remember that XPath rules are checked at run time, not at
compile time. Therefore, be careful when defining them within LINQ queries.
Consider also that like many other LINQ extension methods, the XPath methods we
have just evaluated also support deferred query evaluation. Once again, keep in
mind that every time we use queries defined using these methods, the result is
refreshed by rescanning the source XML graph, unless you copy it yourself by
using any of the extension methods provided by LINQ queries for doing that
(such as ToList, ToArray,
ToDictionary, or ToLookup).