Vergleich zwischen XPath und LINQ to XML

XPath und LINQ to XML haben hinsichtlich ihrer Funktionalität einige Gemeinsamkeiten. Beide können verwendet werden, um Elementauflistungen, Attributauflistungen, Knotenauflistungen oder die Werte von Elementen oder Attributen aus XML-Strukturen abzurufen. Aber es gibt auch einige Unterschiede.

Unterschiede zwischen XPath und LINQ to XML

XPath lässt keine Projektion neuer Typen zu Es können nur Auflistungen der Knoten aus der Struktur zurückgegeben werden. LINQ to XML kann dagegen eine Abfrage ausführen und ein Objektdiagramm oder eine XML-Struktur in einer neuen Form projizieren. LINQ to XML-Abfragen umfassen deutlich mehr Funktionen und sind viel leistungsstärker als XPath-Ausdrücke.

XPath-Ausdrücke existieren innerhalb einer Zeichenfolge isoliert. Der C#-Compiler kann nicht helfen, den XPath-Ausdruck beim Kompilieren zu analysieren. LINQ to XML-Abfragen werden dagegen vom C#-Compiler analysiert und kompiliert. Der Compiler kann eine Vielzahl von Abfragefehlern abfangen.

XPath-Ergebnisse sind nicht stark typisiert. In vielen Situationen ist das Ergebnis der Auswertung eines XPath-Ausdrucks ein Objekt, und es obliegt dem Entwickler, den richtigen Typ zu bestimmen und das Ergebnis nach Bedarf zu konvertieren. Im Gegensatz dazu sind die Projektionen aus einer LINQ to XML-Abfrage stark typisiert.

Reihenfolge der Ergebnisanzeige

Laut XPath 1.0-Empfehlung ist eine Auflistung, die das Ergebnis der Auswertung eines XPath-Ausdrucks ist, nicht geordnet.

Beim Durchlaufen einer Auflistung, die von einer LINQ to XML-XPath-Achsenmethode zurückgegeben wurde, werden die Knoten in der Auflistung jedoch in der Dokumentreihenfolge zurückgegeben. Dies ist auch beim Zugriff auf die XPath-Achsen der Fall, wo beim Ausdrücken von Prädikaten auf die umgekehrte Dokumentreihenfolge zurückgegriffen wird, wie z. B. preceding und preceding-sibling.

Im Gegensatz dazu geben die meisten LINQ to XML-Achsen Auflistungen in Dokumentreihenfolge zurück, doch zwei davon, Ancestors und AncestorsAndSelf, geben Auflistungen in umgekehrter Dokumentreihenfolge zurück. In der folgenden Tabelle werden die Achsen aufgeführt, und es wird jeweils die Auflistungsreihenfolge angegeben:

LINQ to XML-Achse Sortieren
XContainer.DescendantNodes Dokumentreihenfolge
XContainer.Descendants Dokumentreihenfolge
XContainer.Elements Dokumentreihenfolge
XContainer.Nodes Dokumentreihenfolge
XContainer.NodesAfterSelf Dokumentreihenfolge
XContainer.NodesBeforeSelf Dokumentreihenfolge
XElement.AncestorsAndSelf Umgekehrte Dokumentreihenfolge
XElement.Attributes Dokumentreihenfolge
XElement.DescendantNodesAndSelf Dokumentreihenfolge
XElement.DescendantsAndSelf Dokumentreihenfolge
XNode.Ancestors Umgekehrte Dokumentreihenfolge
XNode.ElementsAfterSelf Dokumentreihenfolge
XNode.ElementsBeforeSelf Dokumentreihenfolge
XNode.NodesAfterSelf Dokumentreihenfolge
XNode.NodesBeforeSelf Dokumentreihenfolge

Positionsprädikate

Innerhalb von XPath-Ausdrücken werden Positionsprädikate bei vielen Achsen in der Dokumentreihenfolge angegeben, aber bei den rückwärts gerichteten Achsen preceding, preceding-sibling, ancestor und ancestor-or-self wird die umgekehrte Dokumentreihenfolge verwendet. So gibt z. B. der XPath-Ausdruck preceding-sibling::*[1] das unmittelbar vorausgehende nebengeordnete Element zurück, auch wenn das endgültige Resultset in der Dokumentreihenfolge angegeben wird.

Dagegen werden alle Positionsprädikate in LINQ to XML stets in der Reihenfolge der Achse angegeben. So wird z. B. bei anElement.ElementsBeforeSelf().ToList()[0] statt des unmittelbar vorausgehenden nebengeordneten Elements das erste untergeordnete Element der Ebene oberhalb des abgefragten Elements zurückgegeben. Ein anderes Beispiel: anElement.Ancestors().ToList()[0] gibt das übergeordnete Element zurück.

Beachten Sie, dass bei der oben beschriebenen Herangehensweise die gesamte Auflistung materialisiert wird. Dies ist nicht die effizienteste Art, diese Abfrage zu schreiben. Die Abfrage in der dargestellten Form soll lediglich das Verhalten der Positionsprädikate zeigen. Dieselbe Abfrage könnte vernünftiger mit der First-Methode geschrieben werden: anElement.ElementsBeforeSelf().First().

Wenn Sie für die Suche nach dem unmittelbar vorausgehenden Element LINQ to XML verwenden möchten, müssten Sie den folgenden Ausdruck schreiben:

ElementsBeforeSelf().Last()

Leistungsunterschiede

XPath-Abfragen, die die XPath-Funktionalität in LINQ to XML verwenden, sind nicht so schnell, wie LINQ to XML-Abfragen.

Verfassen von Abfragen im Vergleich

Das Verfassen einer LINQ to XML-Abfrage weist Parallelen mit dem Verfassen eines XPath-Ausdrucks auf, beide haben aber eine sehr unterschiedliche Syntax.

Wenn Sie z. B. ein Element in einer Variable namens customers haben und in allen untergeordneten Elementen mit dem Namen CompanyName nach einem Element der zweiten Unterebene namens Customer suchen, würden Sie den folgenden XPath-Ausdruck schreiben:

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

Die entsprechende LINQ to XML-Abfrage würde wie folgt lauten:

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

Ähnliche Parallelen gibt es auch bei allen anderen XPath-Achsen.

XPath-Achse LINQ to XML-Achse
child (Standardachse) XContainer.Elements
parent (..) XObject.Parent
@ (Attributachse) XElement.Attribute

oder

XElement.Attributes
ancestor-Achse XNode.Ancestors
ancestor-or-self-Achse XElement.AncestorsAndSelf
descendant (//) XContainer.Descendants

oder

XContainer.DescendantNodes
descendant-or-self XElement.DescendantsAndSelf

oder

XElement.DescendantNodesAndSelf
following-sibling XNode.ElementsAfterSelf

oder

XNode.NodesAfterSelf
preceding-sibling XNode.ElementsBeforeSelf

oder

XNode.NodesBeforeSelf
following Keine direkte Entsprechung.
preceding Keine direkte Entsprechung.

Siehe auch

LINQ to XML für XPath-Benutzer (C#)