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. |