Confronto tra XPath e LINQ to XML

XPath e LINQ to XML offrono alcune funzionalità analoghe.Entrambi possono essere utilizzati per eseguire query su una struttura ad 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.Esistono tuttavia alcune differenze.

Differenze tra XPath e LINQ to XML

XPath non consente la proiezione di nuovi tipi.È in grado di restituire solo raccolte di nodi dalla struttura ad albero, mentre tramite LINQ to XML è possibile eseguire una query e proiettare un oggetto grafico o una struttura ad albero XML in una nuova forma.Le query LINQ to XML includono molte più funzionalità e sono molto più potenti delle espressioni XPath.

Le espressioni XPath esistono in isolamento all'interno di una stringa.Il compilatore C# o Visual Basic 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# o Visual Basic.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.

Ordinazione di 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 scorre 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 le raccolte nell'ordine del documento, ma due di essi, Ancestors e AncestorsAndSelf, restituiscono le raccolte nell'ordine inverso del documento.Nella tabella seguente sono enumerati gli assi e viene indicato l'ordine delle raccolte per ognuno di essi:

Asse LINQ to XML

Ordinamento

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 inverso del documento per gli assi inversi, che 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().ToList()[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().ToList()[0] restituisce l'elemento padre.

Si noti che con l'approccio precedente viene materializzata l'intera raccolta.Non si tratta della modalità più efficiente per scrivere la query.È stata scritta in questo modo per illustrare il comportamento dei predicati di posizione.Per scrivere la stessa query in modo più appropriato, utilizzare il metodo First, come segue: anElement.ElementsBeforeSelf().First().

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

ElementsBeforeSelf().Last()

Differenze di prestazioni

Le query XPath che utilizzano la funzionalità XPath in LINQ to XML non vengono eseguite con le stesse prestazioni delle query LINQ to XML.

Confronto di composizione

La composizione di una query LINQ to XML è parallela 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 la seguente espressione XPath:

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

La query LINQ to XML equivalente è:

customers.Element("Customer").Elements("CompanyName");
customers.Element("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

oppure

XElement.Attributes

asse ancestor

XNode.Ancestors

asse ancestor-or-self

XElement.AncestorsAndSelf

asse descendant (//)

XContainer.Descendants

oppure

XContainer.DescendantNodes

descendant-or-self

XElement.DescendantsAndSelf

oppure

XElement.DescendantNodesAndSelf

following-sibling

XNode.ElementsAfterSelf

oppure

XNode.NodesAfterSelf

preceding-sibling

XNode.ElementsBeforeSelf

oppure

XNode.NodesBeforeSelf

following

Nessun equivalente diretto.

preceding

Nessun equivalente diretto.

Vedere anche

Concetti

LINQ to XML per utenti di XPath