Поделиться через


Сравнение XPath и LINQ to XML

XPath и LINQ to XML имеют некоторые сходные функциональные возможности.И то и другое можно использовать, чтобы запрашивать XML-дерево для возвращения таких результатов, как коллекция элементов, коллекция атрибутов, коллекция узлов или значение элемента или атрибута.Однако между ними также есть некоторые различия.

Различия между XPath и LINQ to XML

XPath не поддерживает проекции новых типов.Может возвращать только коллекции узлов из дерева, тогда как LINQ to XML может выполнить запрос, проецировав граф объектов или XML-дерево в новой форме.Запросы LINQ to XML гораздо более эффективны и обладают большими возможностями, чем выражения XPath.

Выражение XPath представлено в изолированном виде, внутри строки.Компилятор C# или Visual Basic не может выполнить синтаксический анализ выражения XPath во время компиляции.В отличие от этого, компилятор C# или Visual Basic проводит синтаксический анализ и компилирует запросы LINQ to XML.Компилятор способен обнаруживать многие ошибки запроса.

Результаты XPath не являются строго типизированными.В некоторых ситуациях результатом вычисления выражения XPath является объект, а задача определения соответствующего типа и приведения результата в соответствии с необходимостью возлагается на разработчика.В отличие от этого, проекции на основе запроса LINQ to XML являются строго типизированными.

Упорядочение результатов

В документе XPath 1.0 Recommendation указано, что коллекция, которая является результатом вычисления выражения XPath, не упорядочена.

Однако при просмотре коллекции, возвращенной методом оси LINQ to XML XPath, можно отметить, что узлы в коллекции возвращены в том же порядке, что и в документе.И они располагаются так даже при доступе к осям XPath, где предикаты выражены в обратном порядке по отношению к документу, например preceding и preceding-sibling.

В отличие от этого, большинство осей LINQ to XML возвращают коллекции в порядке, соответствующем документу, однако две из них, Ancestors и AncestorsAndSelf, возвращают коллекции в порядке, обратном по отношению к документу.В следующей таблице перечисляются эти оси и указывается порядок коллекций для каждой из них.

Ось LINQ to XML

Упорядочение

XContainer.DescendantNodes

Порядок документа

XContainer.Descendants

Порядок документа

XContainer.Elements

Порядок документа

XContainer.Nodes

Порядок документа

XContainer.NodesAfterSelf

Порядок документа

XContainer.NodesBeforeSelf

Порядок документа

XElement.AncestorsAndSelf

Обратный порядок документа

XElement.Attributes

Порядок документа

XElement.DescendantNodesAndSelf

Порядок документа

XElement.DescendantsAndSelf

Порядок документа

XNode.Ancestors

Обратный порядок документа

XNode.ElementsAfterSelf

Порядок документа

XNode.ElementsBeforeSelf

Порядок документа

XNode.NodesAfterSelf

Порядок документа

XNode.NodesBeforeSelf

Порядок документа

Позиционные предикаты

В выражении XPath позиционные предикаты представляются с учетом порядка расположения в документе для многих осей, однако они располагаются в порядке, обратном по отношению к документу, для обратных осей, а именно preceding, preceding-sibling, ancestor и ancestor-or-self.Например, выражение XPath preceding-sibling::*[1] возвращает ближайший предшествующий одноуровневый элемент.Так происходит даже несмотря на то, что итоговый результирующий набор представляется в порядке документа.

В отличие от этого все позиционные предикаты в LINQ to XML всегда выражаются в порядке оси.Например, anElement.ElementsBeforeSelf().ToList()[0] возвращает первый дочерний элемент родителя запрашиваемого элемента, а не ближайший предшествующий одноуровневый элемент.Другой пример: anElement.Ancestors().ToList()[0] возвращает родительский элемент.

Отметим, что при описанном выше подходе материализуется вся коллекция.Это не самый эффективный способ написания такого запроса.Запрос был написан так в целях демонстрации поведения позиционных предикатов.Более подходящим способом написания этого же запроса является использование метода First следующим образом: anElement.ElementsBeforeSelf().First().

Если бы потребовалось найти ближайший предшествующий элемент в LINQ to XML, то было бы написано следующее выражение:

ElementsBeforeSelf().Last()

Различия в производительности

Запросы XPath, которые используют функциональность XPath в LINQ to XML, менее производительны, чем запросы LINQ to XML.

Сравнение композиций

Композиция запроса LINQ to XML немного напоминает композицию выражения XPath, хотя по синтаксису они совершенно различны.

Например, если в переменной с именем customers имеется элемент и требуется найти внучатый элемент с именем CompanyName во всех дочерних элементах с именем Customer, то нужно написать следующее выражение XPath:

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

Эквивалентное выражение LINQ to XML таково:

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

Существуют похожие аналоги для каждой оси XPath.

Ось XPath

Ось LINQ to XML

дочерняя (ось по умолчанию)

XContainer.Elements

родительская (..)

XObject.Parent

ось атрибутов (@)

XElement.Attribute

или

XElement.Attributes

ось ancestor

XNode.Ancestors

ось ancestor-or-self

XElement.AncestorsAndSelf

дочерняя ось (//)

XContainer.Descendants

или

XContainer.DescendantNodes

descendant-or-self

XElement.DescendantsAndSelf

или

XElement.DescendantNodesAndSelf

following-sibling

XNode.ElementsAfterSelf

или

XNode.NodesAfterSelf

preceding-sibling

XNode.ElementsBeforeSelf

или

XNode.NodesBeforeSelf

following

Непосредственного эквивалента нет.

preceding

Непосредственного эквивалента нет.

См. также

Основные понятия

LINQ to XML для пользователей XPath