Сравнение 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 |
---|---|
дочерняя (ось по умолчанию) |
|
родительская (..) |
|
ось атрибутов (@) |
или |
ось ancestor |
|
ось ancestor-or-self |
|
дочерняя ось (//) |
или |
descendant-or-self |
или |
following-sibling |
или |
preceding-sibling |
или |
following |
Непосредственного эквивалента нет. |
preceding |
Непосредственного эквивалента нет. |