bagaimana cara menggunakan XPath dengan XDocument?

109

Ada pertanyaan serupa, tetapi tampaknya solusi tersebut tidak berhasil dalam kasus saya: Keanehan dengan XDocument, XPath, dan namespace

Berikut adalah XML yang saya kerjakan:

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

Dan di bawah ini adalah kode yang menurut saya seharusnya berfungsi tetapi ternyata tidak ...

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

Apakah ada yang punya ide? Terima kasih.

jojo
sumber
1
Lihat jawaban lain di bawah, ini tidak berfungsi karena implementasi XPath 1.0 tidak dapat mengatasi awalan kosong
Paul Hatcher
1
Seperti yang dikatakan orang lain di sini, jangan gunakan awalan kosong saat menambahkan Namespace ke [XmlNamespaceManager]. Saya hanya menambahkan komentar ini jika ada yang ingin melihat contoh kode kecil dengan dokumen yang memiliki beberapa atribut [xmlns], dengan dan tanpa sufiks. Lihat di sini: stackoverflow.com/a/38272604/5838538
Jelgab

Jawaban:

158

Jika Anda memiliki XDocument, lebih mudah menggunakan LINQ-to-XML:

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

Jika Anda yakin bahwa XPath adalah satu-satunya solusi yang Anda butuhkan:

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
sumber
13
Saya akan mengatakan sulit untuk mengatakan linq menjadi lebih mudah daripada xpath dalam banyak kasus. Misalnya dalam kasus ini padanan LINQ tidak benar-benar setara karena ia juga akan mendapatkan node "Nama" di bawah node lain (yang tidak ada di sana sekarang tetapi dapat ditambahkan dengan perubahan nanti pada format file). Namun solusi Anda pasti yang tepat.
Marco Mp
12
CATATAN: menggunakan System.Xml.XPath; cukup penting karena XPathSelectElement adalah metode ekstensi. Jangan lakukan seperti yang saya lakukan dan abaikan bagian itu;)
Mark van Straten
7
XPath masih membantu karena memungkinkan Anda untuk mengontekstualisasikan hubungan orang tua anak Anda. Misalnya jika Anda ingin mendapatkan / Banana / Banana / Banana alih-alih mendapatkan setiap Pisang
Sebastian Patten
2
"kosong" agak menyesatkan dan membingungkan di sini. Anda dapat menggunakan apa saja kecuali, dengan XPath, String.Empty (seperti yang ditemukan oleh penanya). "demo" akan lebih sesuai dengan contoh.
Tom Blodget
7

XPath 1.0, yang diimplementasikan MS, tidak memiliki gagasan tentang namespace default. Jadi coba ini:

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
sumber
8
Jawaban Anda menyiratkan bahwa XPath 2.0, berbeda dengan XPath 1.0 "* memiliki" ide "tentang namespace default. Saya tidak mengetahui fitur XPath baru tersebut (di sini kita membicarakan XPath, bukan XSLT atau XQuery). Oleh karena itu, bisakah Anda , tolong, sebutkan secara eksplisit dalam jawaban Anda apa yang Anda maksudkan?
Dimitre Novatchev
2
Saya pikir apa yang dia maksudkan di sini adalah jika Anda memiliki dokumen yang mendefinisikan namespace, xpath Anda harus menyertakan elemen yang memenuhi syarat, yaitu Anda tidak dapat melakukan xnm.AddNamespace (string.Empty, " demo.com/2011/demo-schema" ); dan kemudian xdoc.XPathSelectElement ("/ Report / ReportInfo / Name", xnm) - hasilnya selalu null
Paul Hatcher
3

Anda dapat menggunakan contoh dari Microsoft - untuk Anda tanpa namespace:

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

harus melakukannya

Bernhard
sumber
tidak bekerja untuk saya
pengguna1623521