Сравнительные характеристики 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 | Непосредственного эквивалента нет. |