如何在XDocument中使用XPath?


109

还有一个类似的问题,但是在我看来,该解决方案没有解决:XDocument,XPath和名称空间的怪异之处

这是我正在使用的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 2013年

1
就像其他人在这里说的那样,在[XmlNamespaceManager]中添加命名空间时,请勿使用空前缀。我只是添加此注释,以防任何人想看到一个带有包含几个[xmlns]属性(带有或不带有后缀)的文档的小代码示例。看到这里:stackoverflow.com/a/38272604/5838538
Jelgab '16

Answers:


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 2014年

7
XPath仍然很有帮助,因为它允许您将父子关系上下文化。例如,如果您想去/ Banana / Banana / Banana而不是去每个香蕉
塞巴斯蒂安·帕滕2014年

2
“空”在这里有点误导和混淆。您可以使用XPath的String.Empty以外的任何东西(如查询者所发现的那样)。“演示”将更适合该示例。
汤姆·布洛杰特

7

MS实现的XPath 1.0没有默认名称空间的想法。所以试试这个:

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
您的答案暗示,与XPath 1.0相比,XPath 2.0“ *”有一个默认名称空间的想法。我不知道这种新的XPath功能(我们在这里谈论的是XPath,不是XSLT或XQuery)。因此,您可以,请在您的答案中明确提及您的
含意

2
我认为他在这里得到的是,如果您有一个定义名称空间的文档,则您的xpath必须包含合格的元素,即您不能执行xnm.AddNamespace(string.Empty,“ demo.com/2011/demo-schema”); 然后xdoc.XPathSelectElement(“ / Report / ReportInfo / Name”,xnm)-结果始终为空
Paul Hatcher 2013年

3

您可以使用Microsoft的示例-对于没有命名空间的示例:

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

应该做


不适用于我
user1623521
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.