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


Сравнительные характеристики XPath и LINQ to XML

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

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

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

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

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

Порядок результатов

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

Однако при просмотре коллекции, возвращенной методом оси XPath LINQ to XML, можно отметить, что узлы в коллекции возвращены в том же порядке, что и в документе. И они располагаются так даже при доступе к осям 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().ElementAt(0) возвращает первый дочерний элемент родителя запрашиваемого элемента, а не ближайший предшествующий одноуровневый элемент. Другой пример: anElement.Ancestors().ElementAt(0) возвращает родительский элемент.

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

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

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

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

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

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

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

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

Эквивалентный запрос LINQ to XML:

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

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

Ось XPath Ось LINQ to XML
дочерняя (ось по умолчанию) XContainer.Elements
родительская (...) XObject.Parent
ось атрибутов (@) XElement.Attribute

or

XElement.Attributes
ось ancestor XNode.Ancestors
ось ancestor-or-self XElement.AncestorsAndSelf
дочерняя ось (//) 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 Непосредственного эквивалента нет.
preceding Непосредственного эквивалента нет.