Comparison of XPath and LINQ to XML

XPath and LINQ to XML are similar in some ways. 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 significant differences between the two options.

Differences between XPath and LINQ to XML

XPath doesn't 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 can do much more than XPath expressions.

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

XPath results aren't strongly typed. In a number of circumstances, the result of evaluating an XPath expression is an object, and it's 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's 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. However, two of them, Ancestors and AncestorsAndSelf, return collections in reverse document order. The following table enumerates the axes, and indicates the 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. The reverse axes 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().ElementAt(0) returns the first child element of the parent of the queried element, not the immediate preceding sibling. Another example: anElement.Ancestors().ElementAt(0) returns the parent element.

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

ElementsBeforeSelf().Last()
ElementsBeforeSelf().Last()

Performance differences

XPath queries that use the XPath functionality in LINQ to XML will be slower than LINQ to XML queries.

Comparison of composition

Composition of a LINQ to XML query is similar to composition of an XPath expression, but the syntax is very different.

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 this XPath expression:

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

The equivalent LINQ to XML query is:

customers.Elements("Customer").Elements("CompanyName")
customers.Elements("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.