làm thế nào để sử dụng XPath với XDocument?


109

Có một câu hỏi tương tự, nhưng có vẻ như giải pháp đã không hoạt động trong trường hợp của tôi: Sự kỳ lạ với XDocument, XPath và không gian tên

Đây là XML mà tôi đang làm việc với:

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

Và dưới đây là đoạn mã mà tôi nghĩ rằng nó sẽ hoạt động nhưng nó không ...

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

Có ai có ý tưởng nào? Cảm ơn.


1
Xem câu trả lời khác dưới đây, nó không làm việc như thực hiện XPath 1.0 không thể đối phó với một tiền tố rỗng
Paul Hatcher

1
Như đã nói ở đây, không sử dụng tiền tố trống khi thêm Không gian tên vào [XmlNamespaceManager]. Tôi chỉ thêm nhận xét này trong trường hợp ai đó muốn xem một ví dụ mã nhỏ với tài liệu có một số thuộc tính [xmlns], có và không có hậu tố. Xem tại đây: stackoverflow.com/a/38272604/5838538
Jelgab

Câu trả lời:


158

Nếu bạn có XDocument thì việc sử dụng LINQ-to-XML sẽ dễ dàng hơn:

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

Nếu bạn chắc chắn rằng XPath là giải pháp duy nhất bạn cần:

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
Tôi muốn nói rằng thật khó để nói linq dễ hơn xpath trong hầu hết các trường hợp. Ví dụ trong trường hợp này, tương đương LINQ không thực sự tương đương vì nó cũng có các nút "Tên" dưới các nút khác (hiện không có nhưng có thể được thêm vào bằng các thay đổi sau này đối với định dạng của tệp). Tuy nhiên giải pháp của bạn chắc chắn là giải pháp đúng.
Marco Mp

12
LƯU Ý: sử dụng System.Xml.XPath; khá quan trọng vì XPathSelectElement là một phương thức mở rộng. Đừng làm như tôi đã làm và bỏ qua phần đó;)
Mark van Straten

7
XPath vẫn hữu ích ở chỗ nó cho phép bạn ngữ cảnh hóa các mối quan hệ con của bạn. Ví dụ nếu bạn muốn để có được / Banana / Chuối / Banana thay vì nhận được mỗi Chuối
Sebastian Patten

2
"trống rỗng" là một chút sai lầm và khó hiểu ở đây. Bạn có thể sử dụng bất cứ thứ gì ngoại trừ XPath, String.Empty (như người hỏi đã phát hiện ra). "demo" sẽ phù hợp hơn với ví dụ.
Tom Blodget

7

XPath 1.0, là thứ mà MS triển khai, không có ý tưởng về một không gian tên mặc định. Vì vậy, hãy thử điều này:

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
Câu trả lời của bạn ngụ ý rằng XPath 2.0, trái ngược với XPath 1.0 "* có" ý tưởng "về không gian tên mặc định. Tôi không biết về tính năng XPath mới như vậy (chúng ta đang nói XPath ở đây, không phải XSLT hoặc XQuery). Do đó, bạn có thể , xin vui lòng, rõ ràng đề cập đến trong câu trả lời của bạn những gì bạn đang ngụ ý?
Dimitre Novatchev

2
Tôi nghĩ những gì anh ấy nhận được ở đây là nếu bạn có một tài liệu xác định không gian tên, xpath của bạn phải bao gồm các phần tử đủ điều kiện, tức là bạn không thể thực hiện xnm.AddNamespace (string.Empty, " demo.com/2011/demo-schema" ); và sau đó xdoc.XPathSelectElement ("/ Report / ReportInfo / Name", xnm) - kết quả luôn trả về giá trị rỗng
Paul Hatcher

3

bạn có thể sử dụng ví dụ từ Microsoft - dành cho bạn không có không gian tên:

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

Hãy làm nó


không hiệu quả với tôi
dùng1623521,
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.