Condividi tramite


Confronto tra XPath e LINQ to XML

In un certo senso, XPath e LINQ to XML sono simili. Entrambi possono essere usati per eseguire query su un albero XML, restituendo risultati quali una raccolta di elementi, una raccolta di attributi, una raccolta di nodi o il valore di un elemento o di un attributo. Tuttavia, esistono numerose differenze tra queste due opzioni.

Differenze tra XPath e LINQ to XML

XPath non consente la proiezione di nuovi tipi. Può restituire solo raccolte di nodi dall'albero, mentre tramite LINQ to XML può eseguire una query e proiettare un oggetto grafico o un albero XML in una nuova forma. Le query LINQ to XML possono fare molto di più rispetto alle espressioni XPath.

Le espressioni XPath esistono in isolamento all'interno di una stringa. Il compilatore C# non consente di analizzare l'espressione XPath in fase di compilazione. Al contrario, le query LINQ to XML vengono analizzate e compilate tramite il compilatore C#. Il compilatore è in grado di intercettare molti errori di query.

I risultati di XPath non sono fortemente tipizzati. In diverse circostanze il risultato della valutazione di un'espressione XPath è un oggetto e spetta allo sviluppatore determinare il tipo appropriato ed eseguire il cast del risultato secondo necessità. Al contrario, le proiezioni di una query LINQ to XML sono fortemente tipizzate.

Ordinamento dei risultati

Nella raccomandazione XPath 1.0 si afferma che una raccolta corrispondente al risultato della valutazione di un'espressione XPath non è ordinata.

Tuttavia, quando si esegue l'iterazione di una raccolta restituita da un metodo dell'asse XPath LINQ to XML, i nodi della raccolta vengono restituiti nell'ordine del documento. Ciò è vero anche quando si accede a assi XPath in cui i predicati sono espressi in termini di ordine inverso del documento, ad esempio preceding e preceding-sibling.

Al contrario, la maggior parte degli assi LINQ to XML restituisce raccolte in ordine di documento. Tuttavia, due di esse, Ancestors e AncestorsAndSelf, restituiscono raccolte in ordine di documento inverso. Nella tabella seguente sono enumerati gli assi e viene indicato l'ordine delle raccolte per ognuno di essi:

Asse LINQ to XML Creazione dell'ordine
XContainer.DescendantNodes Ordine del documento
XContainer.Descendants Ordine del documento
XContainer.Elements Ordine del documento
XContainer.Nodes Ordine del documento
XContainer.NodesAfterSelf Ordine del documento
XContainer.NodesBeforeSelf Ordine del documento
XElement.AncestorsAndSelf Ordine inverso del documento
XElement.Attributes Ordine del documento
XElement.DescendantNodesAndSelf Ordine del documento
XElement.DescendantsAndSelf Ordine del documento
XNode.Ancestors Ordine inverso del documento
XNode.ElementsAfterSelf Ordine del documento
XNode.ElementsBeforeSelf Ordine del documento
XNode.NodesAfterSelf Ordine del documento
XNode.NodesBeforeSelf Ordine del documento

Predicati di posizione

All'interno di un'espressione XPath, i predicati di posizione vengono espressi in termini di ordine del documento per molti assi, mentre sono espressi in ordine di documento inverso per gli assi inversi. Gli assi inversi sono: preceding, preceding-sibling, ancestor e ancestor-or-self. Ad esempio, l'espressione XPath preceding-sibling::*[1] restituisce l'elemento di pari livello immediatamente precedente. Ciò è vero anche se il set di risultati finale è presentato nell'ordine del documento.

Al contrario, tutti i predicati di posizione di LINQ to XML sono sempre espressi in termini di ordine dell'asse. Ad esempio, anElement.ElementsBeforeSelf().ElementAt(0) restituisce il primo elemento figlio del padre dell'elemento sottoposto a query, non l'elemento di pari livello immediatamente precedente. Un altro esempio: anElement.Ancestors().ElementAt(0) restituisce l'elemento padre.

Se si vuole trovare l'elemento immediatamente precedente in LINQ to XML, scrivere l'espressione seguente:

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

Differenze di prestazioni

Le query XPath che usano la funzionalità XPath in LINQ to XML saranno più lente delle query LINQ to XML.

Confronto di composizione

La composizione di una query LINQ to XML è simile a quella di un'espressione XPath, anche se molto diversa nella sintassi.

Se ad esempio una variabile denominata customers contiene un elemento e si desidera trovare un elemento nipote denominato CompanyName sotto tutti gli elementi figlio denominati Customer, è necessario scrivere questa espressione XPath:

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

L'equivalente di una query LINQ to XML è:

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

Esistono paralleli analoghi per ogni asse XPath.

Asse XPath Asse LINQ to XML
child (asse predefinito) XContainer.Elements
Parent (..) XObject.Parent
attribute (@) XElement.Attribute

or

XElement.Attributes
asse ancestor XNode.Ancestors
asse ancestor-or-self XElement.AncestorsAndSelf
asse descendant (//) 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 Nessun equivalente diretto.
preceding Nessun equivalente diretto.