Vergleich zwischen XPath und LINQ to XML

XPath und LINQ to XML ähneln sich in gewisser Weise. Beide können verwendet werden, um Elementauflistungen, Attributauflistungen, Knotenauflistungen oder die Werte von Elementen oder Attributen aus XML-Strukturen abzurufen. Es bestehen allerdings erhebliche Unterschiede zwischen den beiden Optionen.

Unterschiede zwischen XPath und LINQ to XML

XPath lässt keine Projektion neuer Typen zu. Es können nur Sammlungen 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 können wesentlich mehr als XPath-Ausdrücke leisten.

XPath-Ausdrücke existieren innerhalb einer Zeichenfolge isoliert. Der C#-Compiler kann beim Parsen des XPath-Ausdrucks zur Kompilierzeit nicht helfen. LINQ to XML-Abfragen werden dagegen vom C#-Compiler analysiert und kompiliert. Der Compiler kann viele Abfragefehler abfangen.

XPath-Ergebnisse sind nicht stark typisiert. In einer Reihe von Fällen ist das Ergebnis der Auswertung eines XPath-Ausdrucks ein Objekt, und es ist dann Aufgabe des Entwicklers, den richtigen Typ zu bestimmen und das Ergebnis bei Bedarf umzuwandeln. Im Gegensatz dazu sind die Projektionen aus einer LINQ to XML-Abfrage stark typisiert.

Ereignisreihenfolge

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

Beim Durchlaufen einer Sammlung, die von einer LINQ to XML-XPath-Achsenmethode zurückgegeben wurde, werden die Knoten in der Sammlung 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. Zwei davon (Ancestors und AncestorsAndSelf) geben Auflistungen jedoch in umgekehrter Dokumentreihenfolge zurück. Die folgende Tabelle enthält eine Enumeration der Achsen und gibt die Auflistungsreihenfolge für jede Achse an:

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 wird die umgekehrte Dokumentreihenfolge verwendet. Die umgekehrten Achsen sind preceding, preceding-sibling, ancestorund ancestor-or-self. 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().ElementAt(0) statt des unmittelbar vorausgehenden nebengeordneten Elements das erste untergeordnete Element der Ebene oberhalb des abgefragten Elements zurückgegeben. Ein anderes Beispiel: anElement.Ancestors().ElementAt(0) gibt das übergeordnete Element zurück.

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()
ElementsBeforeSelf().Last()

Leistungsunterschiede

XPath-Abfragen, die die XPath-Funktionalität in LINQ to XML verwenden, sind langsamer als LINQ to XML-Abfragen.

Vergleich der Zusammensetzung

Die Zusammensetzung einer LINQ to XML-Abfrage ähnelt der Zusammensetzung eines XPath-Ausdrucks, wobei sich die Syntax jedoch umfassend unterscheidet.

Wenn Sie beispielsweise ein Element in einer Variablen mit dem Namen customers haben und ein zwei Ebenen untergeordnetes Element mit dem Namen CompanyName unter allen untergeordneten Elementen mit dem Namen Customer finden möchten, schreiben Sie diesen XPath-Ausdruck:

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

Die entsprechende LINQ to XML-Abfrage lautet wie folgt:

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