วิธีใช้ XPath กับ XDocument


109

มีคำถามที่คล้ายกัน แต่ดูเหมือนว่าวิธีแก้ปัญหาจะไม่ได้ผลในกรณีของฉัน: Weirdness with XDocument, XPath และ namespaces

นี่คือ XML ที่ฉันใช้งาน:

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

และด้านล่างนี้คือรหัสที่ฉันคิดว่ามันควรจะใช้งานได้ แต่มันไม่ ...

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

ใครมีความคิดบ้างไหม? ขอบคุณ.


1
ดูคำตอบอื่น ๆ ด้านล่างมันใช้ไม่ได้เนื่องจากการใช้งาน XPath 1.0 ไม่สามารถรับมือกับคำนำหน้าที่ว่างเปล่าได้
Paul Hatcher

1
ตามที่กล่าวไว้ที่นี่อย่าใช้คำนำหน้าว่างเมื่อเพิ่ม Namespace ใน [XmlNamespaceManager] ฉันแค่เพิ่มความคิดเห็นนี้ในกรณีที่ใครก็ตามต้องการดูตัวอย่างโค้ดขนาดเล็กพร้อมเอกสารที่มีแอตทริบิวต์ [xmlns] หลายแบบโดยมีและไม่มีส่วนต่อท้าย ดูที่นี่: stackoverflow.com/a/38272604/5838538
Jelgab

คำตอบ:


158

หากคุณมี XDocument การใช้ LINQ-to-XML จะง่ายกว่า:

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

หากคุณแน่ใจว่า XPath เป็นโซลูชันเดียวที่คุณต้องการ:

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
ฉันว่ามันยากที่จะบอกว่า linq ง่ายกว่า xpath ในกรณีส่วนใหญ่ ตัวอย่างเช่นในกรณีนี้การเทียบเท่า LINQ จะไม่เทียบเท่าจริงๆเนื่องจากจะได้รับโหนด "ชื่อ" ภายใต้โหนดอื่น ๆ ด้วย (ซึ่งยังไม่มีในขณะนี้ แต่สามารถเพิ่มได้โดยการเปลี่ยนแปลงรูปแบบของไฟล์ในภายหลัง) อย่างไรก็ตามโซลูชันของคุณเป็นวิธีที่เหมาะสม
Marco Mp

12
หมายเหตุ: การใช้ System.Xml.XPath; มีความสำคัญมากเนื่องจาก XPathSelectElement เป็นวิธีการขยาย อย่าทำอย่างที่ฉันทำและเพิกเฉยต่อส่วนนั้น)
Mark van Straten

7
XPath ยังคงมีประโยชน์ในการช่วยให้คุณสามารถกำหนดบริบทความสัมพันธ์กับลูกของคุณได้ เช่นถ้าคุณต้องการไปที่ / Banana / Banana / Banana แทนที่จะได้รับ Banana ทุกชิ้น
Sebastian Patten

2
"ว่างเปล่า" ทำให้เข้าใจผิดและสับสนเล็กน้อยที่นี่ คุณสามารถใช้อะไรก็ได้ยกเว้นกับ XPath, String.Empty (ตามที่ผู้ถามค้นพบ) "การสาธิต" จะเหมาะสมกว่าสำหรับตัวอย่าง
Tom Blodget

7

XPath 1.0 ซึ่งเป็นสิ่งที่ MS ใช้ไม่มีแนวคิดเกี่ยวกับเนมสเปซเริ่มต้น ลองสิ่งนี้:

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

9
คำตอบของคุณหมายความว่า XPath 2.0 ตรงกันข้ามกับ XPath 1.0 "* มี" ความคิด "ของเนมสเปซเริ่มต้นฉันไม่ทราบถึงคุณลักษณะ XPath ใหม่ดังกล่าว (เรากำลังพูดถึง XPath ที่นี่ไม่ใช่ XSLT หรือ XQuery) ดังนั้นคุณสามารถ โปรดระบุอย่างชัดเจนในคำตอบของคุณว่าคุณกำลังหมายถึงอะไร
Dimitre Novatchev

2
ฉันคิดว่าสิ่งที่เขาได้รับที่นี่คือถ้าคุณมีเอกสารที่กำหนดเนมสเปซ xpath ของคุณจะต้องมีองค์ประกอบที่มีคุณสมบัติเหมาะสมนั่นคือคุณไม่สามารถทำ xnm.AddNamespace (string.Empty, " demo.com/2011/demo-schema" ); แล้ว xdoc.XPathSelectElement ("/ Report / ReportInfo / Name", xnm) - ผลลัพธ์จะออกมาเป็นโมฆะเสมอ
Paul Hatcher

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.