Wie verwende ich XPath mit XDocument?

109

Es gibt eine ähnliche Frage, aber es scheint, dass die Lösung in meinem Fall nicht funktioniert hat: Verrücktheit mit XDocument, XPath und Namespaces

Hier ist das XML, mit dem ich arbeite:

<?xml version="1.0" encoding="utf-8"?>
<Report Id="ID1" Type="Demo Report" Created="2011-01-01T01:01:01+11:00" Culture="en" xmlns="http://demo.com/2011/demo-schema">
    <ReportInfo>
        <Name>Demo Report</Name>
        <CreatedBy>Unit Test</CreatedBy>
    </ReportInfo>
</Report>

Und unten ist der Code, von dem ich dachte, dass er funktionieren sollte, aber er hat nicht ...

XDocument xdoc = XDocument.Load(@"C:\SampleXML.xml");
XmlNamespaceManager xnm = new XmlNamespaceManager(new NameTable()); 
xnm.AddNamespace(String.Empty, "http://demo.com/2011/demo-schema");
Console.WriteLine(xdoc.XPathSelectElement("/Report/ReportInfo/Name", xnm) == null);

Hat jemand irgendwelche Ideen? Vielen Dank.

Jojo
quelle
1
Siehe die andere Antwort unten, es funktioniert nicht, da die XPath 1.0-Implementierung nicht mit einem leeren Präfix umgehen kann
Paul Hatcher
1
Wie hier erwähnt, verwenden Sie kein leeres Präfix, wenn Sie dem [XmlNamespaceManager] einen Namespace hinzufügen. Ich füge diesen Kommentar nur hinzu, falls jemand ein kleines Codebeispiel mit einem Dokument sehen möchte, das mehrere [xmlns] -Attribute mit und ohne Suffix hat. Siehe hier: stackoverflow.com/a/38272604/5838538
Jelgab

Antworten:

158

Wenn Sie über XDocument verfügen, ist die Verwendung von LINQ-to-XML einfacher:

var document = XDocument.Load(fileName);
var name = document.Descendants(XName.Get("Name", @"http://demo.com/2011/demo-schema")).First().Value;

Wenn Sie sicher sind, dass XPath die einzige Lösung ist, die Sie benötigen:

using System.Xml.XPath;

var document = XDocument.Load(fileName);
var namespaceManager = new XmlNamespaceManager(new NameTable());
namespaceManager.AddNamespace("empty", "http://demo.com/2011/demo-schema");
var name = document.XPathSelectElement("/empty:Report/empty:ReportInfo/empty:Name", namespaceManager).Value;
Alex Aza
quelle
13
Ich würde sagen, es ist schwer zu sagen, dass linq in den meisten Fällen einfacher als xpath ist. In diesem Fall ist das LINQ-Äquivalent beispielsweise nicht wirklich äquivalent, da es auch "Name" -Knoten unter anderen Knoten erhalten würde (die jetzt nicht vorhanden sind, aber durch spätere Änderungen am Format der Datei hinzugefügt werden könnten). Ihre Lösung ist jedoch sicherlich die richtige.
Marco Mp
12
HINWEIS: die Verwendung von System.Xml.XPath; ist ziemlich wichtig, da XPathSelectElement eine Erweiterungsmethode ist. Tu nicht so wie ich und ignoriere diesen Teil;)
Mark van Straten
7
XPath ist weiterhin hilfreich, da Sie damit Ihre Eltern-Kind-Beziehungen kontextualisieren können. ZB wenn Sie nach / Banana / Banana / Banana wollen, anstatt jede Banane zu bekommen
Sebastian Patten
2
"leer" ist hier etwas irreführend und verwirrend. Sie können alles verwenden, außer mit XPath String.Empty (wie der Fragesteller festgestellt hat). "Demo" wäre dem Beispiel besser geeignet.
Tom Blodget
7

XPath 1.0, das von MS implementiert wird, hat nicht die Idee eines Standard-Namespace. Versuchen Sie Folgendes:

XDocument xdoc = XDocument.Load(@"C:\SampleXML.xml");
XmlNamespaceManager xnm = new XmlNamespaceManager(new NameTable()); 
xnm.AddNamespace("x", "http://demo.com/2011/demo-schema");
Console.WriteLine(xdoc.XPathSelectElement("/x:Report/x:ReportInfo/x:Name", xnm) == null);
Richard Schneider
quelle
8
Ihre Antwort impliziert, dass XPath 2.0 im Gegensatz zu XPath 1.0 "*" eine Idee "für einen Standard-Namespace hat. Mir ist eine solche neue XPath-Funktion nicht bekannt (wir sprechen hier von XPath, nicht von XSLT oder XQuery) Bitte erwähnen Sie in Ihrer Antwort ausdrücklich, was Sie
damit meinen
2
Ich denke, was er hier vorhat, ist, dass wenn Sie ein Dokument haben, das einen Namespace definiert, Ihr xpath qualifizierte Elemente enthalten muss, dh Sie können xnm.AddNamespace (string.Empty, " demo.com/2011/demo-schema" nicht ausführen. ); und dann xdoc.XPathSelectElement ("/ Report / ReportInfo / Name", xnm) - das Ergebnis ist immer null
Paul Hatcher
3

Sie können das Beispiel von Microsoft verwenden - für Sie ohne Namespace:

using System.Xml.Linq;
using System.Xml.XPath;
var e = xdoc.XPathSelectElement("./Report/ReportInfo/Name");     

Sollte es tun

Bernhard
quelle
funktioniert bei mir nicht
user1623521