come usare XPath con XDocument?


109

C'è una domanda simile, ma sembra che la soluzione non abbia funzionato nel mio caso: Stranezze con XDocument, XPath e spazi dei nomi

Ecco l'XML con cui sto lavorando:

<?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>

E sotto c'è il codice che pensavo avrebbe dovuto funzionare ma non ha funzionato ...

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);

Qualcuno ha qualche idea? Grazie.


1
Vedi l'altra risposta di seguito, non funziona poiché l'implementazione di XPath 1.0 non può far fronte a un prefisso vuoto
Paul Hatcher

1
Come altri hanno detto qui, non utilizzare un prefisso vuoto quando si aggiunge uno spazio dei nomi a [XmlNamespaceManager]. Sto solo aggiungendo questo commento nel caso qualcuno voglia vedere un piccolo esempio di codice con un documento che ha diversi attributi [xmlns], con e senza suffisso. Vedi qui: stackoverflow.com/a/38272604/5838538
Jelgab

Risposte:


158

Se hai XDocument è più facile usare LINQ-to-XML:

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

Se sei sicuro che XPath sia l'unica soluzione di cui hai bisogno:

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;

13
Direi che è difficile dire che linq sia più facile di xpath nella maggior parte dei casi. Ad esempio in questo caso l'equivalente LINQ non è realmente equivalente in quanto otterrebbe anche nodi "Nome" sotto altri nodi (che ora non ci sono ma potrebbero essere aggiunti da modifiche successive al formato del file). Comunque la tua soluzione è sicuramente quella giusta.
Marco Mp

12
NOTA: l'utilizzo di System.Xml.XPath; è piuttosto importante perché XPathSelectElement è un metodo di estensione. Non fare come ho fatto io e ignora quella parte;)
Mark van Straten

7
XPath è ancora utile in quanto ti consente di contestualizzare le relazioni genitore-figlio. Ad esempio, se volevi arrivare a / Banana / Banana / Banana invece di prendere tutte le banane
Sebastian Patten

2
"vuoto" è un po 'fuorviante e confuso qui. Puoi usare qualsiasi cosa tranne, con XPath, String.Empty (come ha scoperto il richiedente). "demo" sarebbe più appropriato per l'esempio.
Tom Blodget,

7

XPath 1.0, che è ciò che MS implementa, non ha l'idea di uno spazio dei nomi predefinito. Quindi prova questo:

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);

8
La tua risposta implica che XPath 2.0, al contrario di XPath 1.0 "* ha" un'idea "di uno spazio dei nomi predefinito. Non sono a conoscenza di questa nuova funzionalità XPath (stiamo parlando di XPath qui, non XSLT o XQuery). Pertanto, potresti , per favore, menziona esplicitamente nella tua risposta cosa stai insinuando?
Dimitre Novatchev

2
Penso che quello che sta ottenendo qui è che se hai un documento che definisce uno spazio dei nomi, il tuo xpath deve includere elementi qualificati, cioè non puoi fare xnm.AddNamespace (string.Empty, " demo.com/2011/demo-schema" ); e quindi xdoc.XPathSelectElement ("/ Report / ReportInfo / Name", xnm) - il risultato è sempre nullo
Paul Hatcher

3

puoi usare l'esempio di Microsoft - per te senza spazio dei nomi:

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

dovrebbe farlo


non funziona per me
user1623521
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.