Partager via


Comparison of XPath and LINQ to XML

XPath and LINQ to XML offer some similar functionality. Both can be used to query an XML tree, returning such results as a collection of elements, a collection of attributes, a collection of nodes, or the value of an element or attribute. However, there are also some differences.

Differences Between XPath and LINQ to XML

XPath does not allow projection of new types. It can only return collections of nodes from the tree, whereas LINQ to XML can execute a query and project an object graph or an XML tree in a new shape. LINQ to XML queries encompass much more functionality and are much more powerful than XPath expressions.

XPath expressions exist in isolation within a string. The C# or Visual Basic compiler cannot help parse the XPath expression at compile time. By contrast, LINQ to XML queries are parsed and compiled by the C# or Visual Basic compiler. The compiler is able to catch many query errors.

XPath results are not strongly typed. In a number of circumstances, the result of evaluating an XPath expression is an object, and it is up to the developer to determine the proper type and cast the result as necessary. By contrast, the projections from a LINQ to XML query are strongly typed.

Result Ordering

The XPath 1.0 Recommendation states that a collection that is the result of evaluating an XPath expression is unordered.

However, when iterating through a collection returned by a LINQ to XML XPath axis method, the nodes in the collection are returned in document order. This is the case even when accessing the XPath axes where predicates are expressed in terms of reverse document order, such as preceding and preceding-sibling.

By contrast, most of the LINQ to XML axes return collections in document order, but two of them, Ancestors and AncestorsAndSelf, return collections in reverse document order. The following table enumerates the axes, and indicates collection order for each:

LINQ to XML axis

Ordering

XContainer.DescendantNodes

Document order

XContainer.Descendants

Document order

XContainer.Elements

Document order

XContainer.Nodes

Document order

XContainer.NodesAfterSelf

Document order

XContainer.NodesBeforeSelf

Document order

XElement.AncestorsAndSelf

Reverse document order

XElement.Attributes

Document order

XElement.DescendantNodesAndSelf

Document order

XElement.DescendantsAndSelf

Document order

XNode.Ancestors

Reverse document order

XNode.ElementsAfterSelf

Document order

XNode.ElementsBeforeSelf

Document order

XNode.NodesAfterSelf

Document order

XNode.NodesBeforeSelf

Document order

Positional Predicates

Within an XPath expression, positional predicates are expressed in terms of document order for many axes, but are expressed in reverse document order for reverse axes, which are preceding, preceding-sibling, ancestor, and ancestor-or-self. For example, the XPath expression preceding-sibling::*[1] returns the immediately preceding sibling. This is the case even though the final result set is presented in document order.

By contrast, all positional predicates in LINQ to XML are always expressed in terms of the order of the axis. For example, anElement.ElementsBeforeSelf().ToList()[0] returns the first child element of the parent of the queried element, not the immediate preceding sibling. Another example: anElement.Ancestors().ToList()[0] returns the parent element.

Note that the above approach materializes the entire collection. This is not the most efficient way to write that query. It was written in that way to demonstrate the behavior of positional predicates. A more appropriate way to write the same query is to use the First method, as follows: anElement.ElementsBeforeSelf().First().

If you wanted to find the immediately preceding element in LINQ to XML, you would write the following expression:

ElementsBeforeSelf().Last()

Performance Differences

XPath queries that use the XPath functionality in LINQ to XML will not perform as well as LINQ to XML queries.

Comparison of Composition

Composition of a LINQ to XML query is somewhat parallel to composition of an XPath expression, although very different in syntax.

For example, if you have an element in a variable named customers, and you want to find a grandchild element named CompanyName under all child elements named Customer, you would write an XPath expression as follows:

customers.XPathSelectElements("./Customer/CompanyName");
customers.XPathSelectElements("./Customer/CompanyName")

The equivalent LINQ to XML query is:

customers.Element("Customer").Elements("CompanyName");
customers.Element("Customer").Elements("CompanyName")

There are similar parallels for each of the XPath axes.

XPath axis

LINQ to XML axis

child (the default axis)

XContainer.Elements

Parent (..)

XObject.Parent

attribute axis (@)

XElement.Attribute

or

XElement.Attributes

ancestor axis

XNode.Ancestors

ancestor-or-self axis

XElement.AncestorsAndSelf

descendant axis (//)

XContainer.Descendants

or

XContainer.DescendantNodes

descendant-or-self

XElement.DescendantsAndSelf

or

XElement.DescendantNodesAndSelf

following-sibling

XNode.ElementsAfterSelf

or

XNode.NodesAfterSelf

preceding-sibling

XNode.ElementsBeforeSelf

or

XNode.NodesBeforeSelf

following

No direct equivalent.

preceding

No direct equivalent.

See Also

Concepts

LINQ to XML for XPath Users