【问题标题】:Select an XML node via XPath at an arbitrary depth通过 XPath 在任意深度选择 XML 节点
【发布时间】:2011-07-09 13:37:41
【问题描述】:

拥有一个 XML 文档,我想获取具有特定名称的第一个节点,无论它包含在哪个嵌套深度中。

我尝试了几件事但没有成功:

var node1 = doc.SelectSingleNode(@"//Shortcut");
var node2 = doc.SelectSingleNode(@"/*/Shortcut");
var node3 = doc.SelectSingleNode(@"//*/Shortcut");
var node4 = doc.SelectSingleNode(@"*/Shortcut");
...

每次调用都会产生一个NULL 节点。

我认为它应该是一些简单的 XPath 语法。你能帮帮我吗?

(如果这很重要:XML 文档是 WiX 项目的输入文件,因此可能涉及一些命名空间问题?!?)。

编辑

我还尝试了以下方法:

var nsm = new XmlNamespaceManager(doc.NameTable);
nsm.AddNamespace(string.Empty, @"http://schemas.microsoft.com/wix/2006/wi");
nsm.AddNamespace(@"ns", @"http://schemas.microsoft.com/wix/2006/wi");

与:

var node1 = doc.SelectSingleNode(@"//Shortcut", nsm);
var node2 = doc.SelectSingleNode(@"/*/Shortcut", nsm);
var node3 = doc.SelectSingleNode(@"//*/Shortcut", nsm);
var node4 = doc.SelectSingleNode(@"*/Shortcut", nsm);
...

导致相同的结果。

编辑 2 - 解决方案

我找到了解决办法:

var nsm = new XmlNamespaceManager(doc.NameTable);
nsm.AddNamespace(string.Empty, @"http://schemas.microsoft.com/wix/2006/wi");
nsm.AddNamespace(@"ns", @"http://schemas.microsoft.com/wix/2006/wi");

然后

var node1 = doc.SelectSingleNode(@"//ns:Shortcut", nsm);

这成功了。

【问题讨论】:

  • 好问题,+1。请参阅我的答案以获得更通用和灵活的解决方案。

标签: c# xml xpath wix


【解决方案1】:

XPath 表达式准确地选择了想要的节点(除此之外什么都没有)是

(//x:Shortcut)[1]

所以,使用:

doc.SelectNodes("(//x:Shortcut)[1]", someNamespaceManager)

在哪里

前缀"x"绑定到命名空间"http://schemas.microsoft.com/wix/2006/wi"

someNamespaceManager

这比建议的解决方案(使用SelectSingleNode())有一个优势,因为它可以很容易地调整以选择 XML 文档中的第 N 个想要的节点

例如:

   (//x:Shortcut)[3]

选择第三个(按文档顺序)x:Shortcut 元素,并且

   (//x:Shortcut)[last()]

选择 XML 文档中的最后一个(按文档顺序)x:Shortcut 元素。

【讨论】:

  • 非常感谢@Dimitre 的精彩回答!
  • 我确实了解 XPath 表达式的改进,但我不明白您为什么建议使用 SelectNodes 而不是 SelectSingleNode。显然,通过编写路径表达式来选择具有位置谓词的单个节点,您也可以将其传递给 SelectSingleNode。
  • @Martin Honnen:SelectSingleNode() 帮助 OP 从//someName 中选择第一个节点——它总是只选择第一个节点。我想告诉他他不需要SelectSingleNode() 的这个特性,因为他可以在XPath 表达式本身中准确地指定他需要哪个或哪些节点。然后,他将没有(有义务)使用SelectSingleNode()。我并不是说他不能使用SelectSingleNode()——只是他现在可以不使用它了。
【解决方案2】:

为什么不用XDocument

XDocument doc = XDocument.Load("test.xml");
doc.Descendants("Shortcut").First();

IMO XDocument 比 XPath 更快、更易读。

【讨论】:

  • 谢谢。 XDocument 是什么班级?来自自定义类?
  • @Uwe Keim,我添加了参考链接。
  • @Uwe Keim:它是 Linq-to-XML 的一部分,首次在 .NET 3.0(VS 2008)中引入
【解决方案3】:

我终于自己找到了解决办法:

var nsm = new XmlNamespaceManager(doc.NameTable);
nsm.AddNamespace(string.Empty, @"http://schemas.microsoft.com/wix/2006/wi");
nsm.AddNamespace(@"ns", @"http://schemas.microsoft.com/wix/2006/wi");

然后

var node1 = doc.SelectSingleNode(@"//ns:Shortcut", nsm);

这成功了。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-03-15
    • 1970-01-01
    • 1970-01-01
    • 2013-04-07
    • 1970-01-01
    • 1970-01-01
    • 2013-06-23
    • 1970-01-01
    相关资源
    最近更新 更多