在 C# 中使用带有默认命名空间的 Xpath
我有一个带有默认命名空间的 XML 文档。 我正在使用 XPathNavigator 使用 Xpath 选择一组节点,如下所示:
XmlElement myXML = ...;
XPathNavigator navigator = myXML.CreateNavigator();
XPathNodeIterator result = navigator.Select("/outerelement/innerelement");
我没有收到任何结果:我假设这是因为我没有指定名称空间。 如何在我的选择中包含名称空间?
I've got an XML document with a default namespace. I'm using a XPathNavigator to select a set of nodes using Xpath as follows:
XmlElement myXML = ...;
XPathNavigator navigator = myXML.CreateNavigator();
XPathNodeIterator result = navigator.Select("/outerelement/innerelement");
I am not getting any results back: I'm assuming this is because I am not specifying the namespace. How can I include the namespace in my select?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(14)
首先 - 你不需要导航器; SelectNodes / SelectSingleNode 应该足够了。
但是,您可能需要一个名称空间管理器 - 例如:
First - you don't need a navigator; SelectNodes / SelectSingleNode should suffice.
You may, however, need a namespace-manager - for example:
您可能想尝试 XPath Visualizer 工具来帮助您完成任务。
XPathVisualizer 是免费的,易于使用。
重要提示:如果您使用的是 Windows 7/8,并且看不到“文件”、“编辑”和“帮助”菜单项,请按 ALT 键。
You might want to try an XPath Visualizer tool to help you through.
XPathVisualizer is free, easy to use.
IMPORTANT: If you are using Windows 7/8 and don't see File, Edit and Help Menu items, please press ALT key.
对于任何寻求快速破解解决方案的人来说,尤其是在您了解 XML 并且不需要担心名称空间等的情况下,您可以通过简单地绕过这个烦人的小“功能”将文件读取为字符串并替换攻击性属性:
我发现这比处理单个文件时需要默认名称空间前缀的所有其他无意义的操作更容易。 希望这可以帮助。
For anyone looking for a quick hack solution, especially in those cases where you know the XML and don't need to worry about namespaces and all that, you can get around this annoying little "feature" by simply reading the file to a string and replacing the offensive attribute:
I find this easier than all the other non-sense requiring a prefix for a default namespace when I'm dealing with a single file. Hope this helps.
在带有命名空间的 XML 上使用 .NET 中的 XPath(通过导航器或 SelectNodes/SelectSingleNode)时,您需要:
提供您自己的 XmlNamespaceManager
和为 XPath 表达式中命名空间中的所有元素添加前缀。
后者是(从下面链接的 MS 源代码解释):因为 XPath 1.0 忽略默认名称空间规范 (xmlns="some_namespace")。 因此,当您使用不带前缀的元素名称时,它假定命名空间为空。
这就是为什么 XPath 的 .NET 实现会忽略 XmlNamespaceManager 中带有前缀 String.Empty 的命名空间,并始终使用 null 命名空间。
请参阅 XmlNamespaceManager 和 UndefinedXsltContext 不'处理默认命名空间以获取更多信息。
我发现这个“功能”非常不方便,因为您无法通过简单地添加默认命名空间声明来使旧的 XPath 命名空间感知,但这就是它的工作原理。
When using XPath in .NET (via a navigator or SelectNodes/SelectSingleNode) on XML with namespaces you need to:
provide your own XmlNamespaceManager
and explicitly prefix all elements in XPath expression, which are in namespace.
The latter is (paraphrased from MS source linked below): because XPath 1.0 ignores default namespace specifications (xmlns="some_namespace"). So when you use element name without prefix it assumes null namespace.
That's why .NET implementation of XPath ignores namespace with prefix String.Empty in XmlNamespaceManager and allways uses null namespace.
See XmlNamespaceManager and UndefinedXsltContext don't handle default namespace for more information.
I find this "feature" very inconvenient because you cannot make old XPath namespace-aware by simply adding default namespace declaration, but that's how it works.
您可以使用 XPath 语句而不使用 XmlNamespaceManager,如下所示:
这是在定义了默认命名空间的 XML 中选择元素的简单方法。
重点是使用:
它将在不使用前缀的情况下找到具有默认名称空间的元素。
You can use XPath statement without using XmlNamespaceManager like this:
That is a simple way of selecting element within XML with default namespace definied.
The point is to use:
which will found element with default namespace without using prefixes.
我的回答扩展了布兰登之前的回答。 我使用他的示例创建了一个扩展方法,如下所示:
然后在我的 XML 解析代码中,我只添加一行:
我真的很喜欢这个方法,因为它在从源 XML 文件加载命名空间方面是完全动态的,而且它并没有完全忽视 XML 命名空间的概念,因此它可以与需要多个命名空间来消除冲突的 XML 一起使用。
My answer extends the previous answer by Brandon. I used his example to create an extension method as follows:
Then in my XML parsing code, I just add a single line:
I really like this method because it is completely dynamic in terms of loading the namespaces from the source XML file, and it doesn't completely disregard the concept of XML namespaces so this can be used with XML that requires multiple namespaces for deconfliction.
我遇到了类似的问题,默认命名空间为空。 在此示例 XML 中,我混合了带有命名空间前缀的元素和不带命名空间前缀的单个元素 (DataBlock):
我尝试使用在 XPath Visualizer 中工作的 XPath,但在我的代码中不起作用:
我将其范围缩小到XPath 的“DataBlock”元素,但除了简单地使用 DataBlock 元素的通配符之外无法使其工作:
经过多次绞尽脑汁和谷歌搜索(这让我来到这里),我决定直接在我的 XmlNamespaceManager 加载器中处理默认名称空间,方法是将其更改为:
所以现在“default”和“”指向相同的命名空间。 一旦我这样做了,XPath“/src:SRCExample/default:DataBlock/a:DocID/a:IdID”就按照我想要的方式返回了我的结果。 希望这有助于为其他人澄清这个问题。
I encountered a similar problem with a blank default namespace. In this example XML, I have a mix of elements with namespace prefixes, and a single element (DataBlock) without:
I attempted to use an XPath that worked in XPath Visualizer, but did not work in my code:
I narrowed it down to the "DataBlock" element of the XPath, but couldn't make it work except by simply wildcarding the DataBlock element:
After much headscratching and googling (which landed me here) I decided to tackle the default namespace directly in my XmlNamespaceManager loader by changing it to:
So now "default" and "" point to the same namespace. Once I did this, the XPath "/src:SRCExample/default:DataBlock/a:DocID/a:IdID" returned my results just like I wanted. Hopefully this helps to clarify the issue for others.
如果外部元素和内部元素的命名空间不同
In case the namespaces differ for outerelement and innerelement
就我而言,添加前缀是不切实际的。 太多的 xml 或 xpath 是在运行时确定的。 最终我在 XmlNode 上扩展了这些方法。 这尚未针对性能进行优化,并且可能无法处理所有情况,但到目前为止它对我有用。
然后在你的代码中使用类似的
希望这有帮助
In my case adding a prefix wasn't practical. Too much of the xml or xpath were determined at runtime. Eventually I extended the methds on XmlNode. This hasn't been optimised for performance and it probably doesn't handle every case but it's working for me so far.
Then in your code just use something like
Hope this helps
我使用了上面 SpikeDog 描述的虽然简单但有用的方法。 它运行得很好,直到我向它添加一个使用管道组合多个路径的 xpath 表达式。
所以我用正则表达式重写了它,并认为我会分享:
I used the hacky-but-useful approach described by SpikeDog above. It worked very well until I threw an xpath expression at it that used pipes to combine multiple paths.
So I rewrote it using regular expressions, and thought I'd share:
或者,如果有人像我一样应该使用 XPathDocument:
Or, if anyone should be using an XPathDocument, like me:
1] 如果您的 XML 文件在命名空间中没有任何前缀:
您有以下解决方法:
2] 如果您的 XML 文件在命名空间中具有前缀:
使用此方法:
当然,如果需要,您可以使用命名空间管理:
我认为这是使代码在大多数情况下工作的最简单方法。
我希望这有助于解决这个微软问题......
1] If you have a XML file without any prefix in the namespace:
you have this workaround:
2] If you have a XML file with a prefix in the namespace:
Use this:
Of course, you can use a namespace manage if needed:
I think that it's the easiest way to make the code working in the most cases.
I hope this help to solve this Microsoft issue…
这个问题至今仍困扰着我。 我现在已经做了一些测试,所以希望我能帮助你。
这是来自 Microsoft 的来源,是问题的关键
重要的一段在这里:
本质上,您必须记住 XPath 解析器使用命名空间 URI - 其设计是前缀可互换。 就是这样,在编程时,您可以分配我们想要的任何前缀 - 只要 URI 匹配即可。
为了清楚起见,通过示例:
示例 A:
它具有 NULL 默认 URI(
xmlns=
未定义)。 因此/data/nsa:a
返回“World”。示例 B:
此文档具有命名的默认前缀
https://standardns/
。 因此,使用/data/nsa:a
执行XPathNavigator.Execute
不会返回任何结果。 MS 认为data
的 XML namespace uri 应该为 NULL,而data
的命名空间 URI 实际上是“https://standardns/” 。 本质上,XPath 正在寻找/NULL:data/nsa:a
- 尽管这不起作用,因为您不能将 NULL URI 作为“NULL”作为前缀引用。 NULL 前缀是所有 XPath 中的默认前缀 - 因此出现了问题。我们如何解决这个问题?
这样,我们现在可以将 a 引用为
/DEFAULT:data/nsa:a
示例 C:
在此示例中,
data
位于空命名空间。a
位于默认命名空间“https://standardns/”中。 根据 Microsoft 的说法,/data/a
不应该工作,因为a
位于 NShttps://standardns/
和data 中
位于命名空间 NULL 中。 因此被隐藏(除非通过执行奇怪的“忽略名称空间”黑客)并且无法按原样选择。 这本质上是根本原因 - 您不应该能够选择两者都没有前缀的“a”和“data”,因为这会假设它们位于同一名称空间中,但事实并非如此!
我们如何解决这个问题?
这样,我们现在可以将 a 引用为
/data/DEFAULT:a
,因为 data 是从 NULL 命名空间中选择的,而 a 是从新前缀“DEFAULT”中选择的。 此示例中重要的是命名空间前缀不需要保持不变。 在代码中引用具有不同前缀的 URI 命名空间是完全可以接受的,就像您正在处理的文档中写入的内容一样。希望这可以帮助一些人!
This one still keeps bugging me. I've done some testing now, so hopefully I can help you with this.
This is the source from Microsoft, which is the key to the problem
The important paragraph is here:
In essence, you have to remember the XPath parser uses the Namespace URI - with the design that the prefix is interchangeable. This is so, when programming, you can assign whatever prefix we want - as long as the URI matches.
For clarity with examples:
Example A:
This has a NULL default URI (
xmlns=
is not defined). Because of this/data/nsa:a
returns "World".Example B:
This document has a named default prefix
https://standardns/
.XPathNavigator.Execute
with/data/nsa:a
therefore returns no results. MS considers that the XML namespace uri fordata
should be NULL, and the namespace URI fordata
is actually "https://standardns/". Essentially XPath is looking for/NULL:data/nsa:a
- although this won't work, as you can't refer to the NULL URI as "NULL" as a prefix. NULL prefix is the default in all XPath - hence the issue.How do we solve this?
In this way, we can now refer to a as
/DEFAULT:data/nsa:a
Example C:
In this example
data
is in the NULL namespace.a
is in the default namespace "https://standardns/"./data/a
should not work, according to Microsoft, becausea
is in the NShttps://standardns/
anddata
is in the namespace NULL.<a>
is therefore hidden (except by doing weird "ignore the namespace" hacks) and cannot be selected upon as-is. This is essentially the root cause - you should not be able to select "a" and "data" with no prefixes for both, as this would assume that they were in the same namespace, and they aren't!How do we solve this?
In this way, we can now refer to a as
/data/DEFAULT:a
as data is selected from the NULL namespace, and a is selected from the new prefix "DEFAULT". The important thing in this example is that the namespace prefix does not need to remain the same. It's perfectly acceptable to refer to a URI namespace with a different prefix in your code, as to what is written in the document you are processing.Hope this helps some people!
在这种情况下,问题的原因可能是名称空间解析,但您的 XPath 表达式本身也可能不正确。 您可能想先对其进行评估。
这是使用 XPathNavigator 的代码。
In this case, it is probably namespace resolution which is the cause of the problem, but it is also possible that your XPath expression is not correct in itself. You may want to evaluate it first.
Here is the code using an XPathNavigator.