Comparação de XPath e LINQ com XML
XPath e LINQ to XML são semelhantes em alguns aspetos. Ambos podem ser usados para consultar uma árvore XML, retornando resultados como uma coleção de elementos, uma coleção de atributos, uma coleção de nós ou o valor de um elemento ou atributo. No entanto, existem diferenças significativas entre as duas opções.
Diferenças entre XPath e LINQ to XML
XPath não permite projeção de novos tipos. Ele só pode retornar coleções de nós da árvore, enquanto o LINQ to XML pode executar uma consulta e projetar um gráfico de objeto ou uma árvore XML em uma nova forma. As consultas LINQ to XML podem fazer muito mais do que expressões XPath.
As expressões XPath existem isoladamente dentro de uma cadeia de caracteres. O compilador C# não pode ajudar a analisar a expressão XPath em tempo de compilação. Por outro lado, as consultas LINQ to XML são analisadas e compiladas pelo compilador C#. O compilador pode capturar muitos erros de consulta.
Os resultados do XPath não são fortemente digitados. Em várias circunstâncias, o resultado da avaliação de uma expressão XPath é um objeto, e cabe ao desenvolvedor determinar o tipo adequado e lançar o resultado conforme necessário. Por outro lado, as projeções de uma consulta LINQ to XML são fortemente tipadas.
Ordenação de resultados
A Recomendação XPath 1.0 afirma que uma coleção que é o resultado da avaliação de uma expressão XPath não está ordenada.
No entanto, ao iterar através de uma coleção retornada por um método de eixo LINQ to XML XPath, os nós na coleção são retornados na ordem do documento. Este é o caso mesmo ao acessar os eixos XPath onde os predicados são expressos em termos de ordem inversa do documento, como preceding
e preceding-sibling
.
Por outro lado, a maioria dos eixos LINQ to XML retorna coleções na ordem do documento. No entanto, dois deles, Ancestors e AncestorsAndSelf, devolvem coleções em ordem inversa de documentos. A tabela a seguir enumera os eixos e indica a ordem de coleta para cada um:
Eixo LINQ to XML | Ordenação |
---|---|
XContainer.DescendantNodes | Ordem de documentos |
XContainer.Descendentes | Ordem de documentos |
XContainer.Elements | Ordem de documentos |
XContainer.Nodes | Ordem de documentos |
XContainer.NodesAfterSelf | Ordem de documentos |
XContainer.NodesBeforeSelf | Ordem de documentos |
XElement.AncestorsAndSelf | Ordem inversa do documento |
XElement.Attributes | Ordem de documentos |
XElement.DescendantNodesAndSelf | Ordem de documentos |
XElement.DescendentesAndSelf | Ordem de documentos |
XNode.Ancestrais | Ordem inversa do documento |
XNode.ElementsAfterSelf | Ordem de documentos |
XNode.ElementsBeforeSelf | Ordem de documentos |
XNode.NodesAfterSelf | Ordem de documentos |
XNode.NodesBeforeSelf | Ordem de documentos |
Predicados posicionais
Dentro de uma expressão XPath, os predicados posicionais são expressos em termos de ordem do documento para muitos eixos, mas são expressos em ordem inversa do documento para eixos reversos. Os eixos inversos são: preceding
, preceding-sibling
, ancestor
, e ancestor-or-self
. Por exemplo, a expressão preceding-sibling::*[1]
XPath retorna o irmão imediatamente anterior. Este é o caso, embora o conjunto de resultados finais seja apresentado por ordem documental.
Por outro lado, todos os predicados posicionais em LINQ to XML são sempre expressos em termos da ordem do eixo. Por exemplo, anElement.ElementsBeforeSelf().ElementAt(0)
retorna o primeiro elemento filho do pai do elemento consultado, não o irmão imediatamente anterior. Outro exemplo: anElement.Ancestors().ElementAt(0)
retorna o elemento pai.
Se você quisesse encontrar o elemento imediatamente anterior em LINQ to XML, você escreveria a seguinte expressão:
ElementsBeforeSelf().Last()
ElementsBeforeSelf().Last()
Diferenças de desempenho
As consultas XPath que usam a funcionalidade XPath no LINQ to XML serão mais lentas do que as consultas LINQ to XML.
Comparação da composição
A composição de uma consulta LINQ to XML é semelhante à composição de uma expressão XPath, mas a sintaxe é muito diferente.
Por exemplo, se você tiver um elemento em uma variável chamada customers
, e quiser encontrar um elemento neto nomeado CompanyName
sob todos os elementos filho nomeados Customer
, você escreveria esta expressão XPath:
customers.XPathSelectElements("./Customer/CompanyName")
customers.XPathSelectElements("./Customer/CompanyName")
A consulta LINQ equivalente a XML é:
customers.Elements("Customer").Elements("CompanyName")
customers.Elements("Customer").Elements("CompanyName")
Existem paralelos semelhantes para cada um dos eixos XPath.
Eixo XPath | Eixo LINQ to XML |
---|---|
filho (o eixo padrão) | XContainer.Elements |
Pai (..) | XObject.Parent |
eixo do atributo (@) | XElement.Attribute ou XElement.Attributes |
eixo ancestral | XNode.Ancestors |
eixo ancestral-ou-si mesmo | XElement.AncestorsAndSelf |
eixo descendente (//) | XContainer.Descendants ou XContainer.DescendantNodes |
descendente-ou-si mesmo | XElement.DescendantsAndSelf ou XElement.DescendantNodesAndSelf |
irmão-seguinte | XNode.ElementsAfterSelf ou XNode.NodesAfterSelf |
irmão-anterior | XNode.ElementsBeforeSelf ou XNode.NodesBeforeSelf |
a seguir | Sem equivalente direto. |
Precedentes | Sem equivalente direto. |