Wie verwende ich XPath mit XElement oder LINQ?

77

Betrachten Sie das folgende XML:

<response>
  <status_code>200</status_code>
  <status_txt>OK</status_txt>
  <data>
    <url>http://bit.ly/b47LVi</url>
    <hash>b47LVi</hash>
    <global_hash>9EJa3m</global_hash>
    <long_url>http://www.tumblr.com/docs/en/api#api_write</long_url>
    <new_hash>0</new_hash>
  </data>
</response>

Ich suche nach einem wirklich kurzen Weg, um nur den Wert des <hash>Elements zu ermitteln. Ich habe es versucht:

var hash = xml.Element("hash").Value;

Aber das funktioniert nicht. Ist es möglich, eine XPath-Abfrage an eine zu senden XElement? Ich kann es mit dem älteren System.XmlFramework machen und so etwas machen wie:

xml.Node("/response/data/hash").Value

Gibt es so etwas in einem LINQ-Namespace?


AKTUALISIEREN:

Nachdem ich noch ein bisschen herumgespielt hatte, fand ich einen Weg, das zu tun, was ich versuche:

var hash = xml.Descendants("hash").FirstOrDefault().Value;

Es würde mich immer noch interessieren, ob jemand eine bessere Lösung hat.

Paul Fryer
quelle
3
Verwenden Sie in diesem Fall nicht FirstOfDefault (), da Sie eine NullReferenceException erhalten, wenn "Hash" nicht gefunden wird. Verwenden Sie stattdessen First (), um eine aussagekräftigere Ausnahme zu erhalten.
Kaalus
3
Verwenden Sie First (), wenn Sie erwarten, dass "Hash" immer vorhanden ist. Andernfalls ist FirstOrDefault () in Ordnung, solange Sie vor dem Zugriff auf die Value-Eigenschaft auf null prüfen.
Ein

Antworten:

136

Um XPath mit LINQ to XML zu verwenden, fügen Sie eine using-Deklaration für hinzu System.Xml.XPath, um die Erweiterungsmethoden von System.Xml.XPath.Extensionsin den Geltungsbereich zu bringen.

In Ihrem Beispiel:

var value = (string)xml.XPathEvaluate("/response/data/hash");
Richard
quelle
1
OK, scheint der ursprünglichen Frage am nächsten zu sein
Henk Holterman
3
Eigentlich ist es (jetzt?) In System.Xml.XPath.
Dan Friedman
@ DanFriedman hat sich nicht bewegt. Hinweis Link ist zu Klassendokumenten, etwas früher gebe ich den Namespace (ohne Link).
Richard
Beachten Sie auch, dass Sie eine Assembly über NuGet für UWP-Apps hinzufügen müssen: link
Matt__C
1
Ich finde es einfacher, die Methode XPathSelectElement zu verwenden und ein XElement anstelle eines Objekts zurückzugewinnen.
user3042674
38

Andere haben vernünftigerweise vorgeschlagen, wie Sie "native" LINQ-zu-XML-Abfragen verwenden können, um das zu tun, was Sie wollen.

Um jedoch viele Alternativen bereitzustellen XPathSelectElement, sollten Sie XPath-Ausdrücke in Betracht ziehen XPathSelectElementsund XPathEvaluateanhand einer XNode(sie sind alle Erweiterungsmethoden aktiviert XNode) bewerten . Sie können auch CreateNavigatorein XPathNavigatorfür ein erstellen XNode.

Persönlich bin ich ein großer Fan der direkten Verwendung der LINQ to XML-API, da ich ein großer LINQ-Fan bin. Wenn Sie jedoch mit XPath besser vertraut sind, kann Ihnen das oben Genannte helfen.

Jon Skeet
quelle
14

Sehen Sie beim Umgang mit LINQ to XML, warum Sie LINQ nicht verwenden, um das eigentliche Objekt abzurufen.

Nachkommen finden jedes Element aus dem gesamten XML und listen alle Objekte auf, die dem angegebenen Namen entsprechen. In Ihrem Fall ist Hash also der Name, den es findet.

Also, anstatt es zu tun

var hash = xml.Descendants("hash").FirstOrDefault().Value;

Ich würde auseinander brechen wie:

var elements = xml.Descendants("hash");
var hash = elements.FirstOrDefault();

if(hash != null)
 hash.Value // as hash can be null when default. 

Auf diese Weise erhalten Sie möglicherweise auch Attribute, Knotenelemente usw.

Überprüfen Sie diesen Artikel, um eine klare Vorstellung davon zu bekommen, damit es hilft. http://www.codeproject.com/KB/linq/LINQtoXML.aspx Ich hoffe, dies wird Ihnen helfen.

Abhishek
quelle
2
@adhishek +1 für die Erklärung des Werts der Trennung des Elements in eine eigene Variable, damit Sie andere Dinge wie das Abrufen von Attributen usw. tun können.
Paul Fryer
1
Ein Grund für die Verwendung von XPath ist, dass Sie all die Dinge verlieren, die XPath tun kann und Linq nicht. Der erste offensichtliche Punkt ist die Ausführung einer Abfrage, die zur Laufzeit definiert wird (z. B. ein aus der Konfiguration gelesener Ausdruck oder was auch immer).
Marco Mp
8

Mit der Methode .Element () können Sie die Elemente zu einer XPath-ähnlichen Struktur verketten.

Für Ihr Beispiel:

XElement xml = XElement.Parse(@"...your xml...");
XElement hash = xml.Element("data").Element("hash");
Panpawel
quelle
1
Ich denke, dies ist die beste Antwort, da die Arbeit erledigt wird, während weiterhin LINQ to XML verwendet wird (was empfohlen wird), anstatt XPath mit LINQ to XML-Abfragen zu verwenden (was nicht empfohlen wird).
Girish Jain
2
Die Verwendung von XPath ist präziser, insbesondere wenn Sie Enkelkinder oder mehr suchen.
Ein Phu
Element () kann null zurückgeben, daher ist dies unsicher.
Simon Morgan
2

Ich habe versucht, ein LINQesq-Framework zum Generieren von xpath zu entwickeln. Sie können xpath mit c # Lambda-Ausdrücken beschreiben

var xpath = CreateXpath.Where(e => e.TargetElementName == "td" && e.Parent.Name == "tr");

var xpath = CreateXpath.Where(e => e.TargetElementName == "td").Select(e => e.Text);

Sie sind sich nicht sicher, ob dies in diesem Zusammenhang hilfreich ist. Eine Dokumentation finden Sie hier:

http://www.syntaxsuccess.com/viewarticle/how-to-create-xpath-using-linq

TGH
quelle