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
, ancestor
und 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. |