如何在XDocument中使用XPath?

joj*_*ojo 108 .net c# xml xpath linq-to-xml

有一个类似的问题,但似乎解决方案在我的情况下没有用: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>
Run Code Online (Sandbox Code Playgroud)

以下是我认为它应该工作的代码,但它没有......

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);
Run Code Online (Sandbox Code Playgroud)

有没有人有任何想法?谢谢.

Ale*_*Aza 154

如果您有XDocument,则更容易使用LINQ-to-XML:

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

如果您确定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;
Run Code Online (Sandbox Code Playgroud)

  • 我想说在大多数情况下很难说linq比xpath更容易.例如,在这种情况下,LINQ等价物并不是真正等效的,因为它也会在其他节点下获得"名称"节点(现在不存在,但可以通过稍后更改文件格式来添加).但是你的解决方案肯定是正确的. (13认同)
  • 注意:使用System.Xml.XPath; 非常重要,因为XPathSelectElement是一个扩展方法.不要像我那样做,忽略那部分;) (12认同)
  • XPath仍然有用,因为它允许您对父子关系进行上下文关联.例如,如果你想去/ Banana/Banana/Banana而不是每个香蕉 (6认同)
  • "空"在这里有点误导和混乱.您可以使用除XPath,String.Empty之外的任何内容(如发现提问者)."demo"更适合这个例子. (2认同)

Ric*_*der 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);
Run Code Online (Sandbox Code Playgroud)

  • 你的回答暗示XPath 2.0,与XPath 1.0相比"*"有一个默认命名空间的想法.我不知道这样的新XPath功能(我们在这里谈论XPath,而不是XSLT或XQuery).因此,你能不能请在答案中明确提到你的暗示? (8认同)
  • 我认为他在这里得到的是,如果你有一个定义命名空间的文档,你的xpath必须包含限定元素,即你不能做xnm.AddNamespace(string.Empty,"http://demo.com/2011/演示模式"); 然后是xdoc.XPathSelectElement("/ Report/ReportInfo/Name",xnm) - 结果总是出来null (2认同)

Ber*_*ard 5

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

using System.Xml.Linq;
using System.Xml.XPath;
var e = xdoc.XPathSelectElement("./Report/ReportInfo/Name");     
Run Code Online (Sandbox Code Playgroud)

应该做