我想从这个提要中阅读全部内容item节点,所以通常//item
X路径
应该可以解决问题。很遗憾
在这种情况下这不起作用。
在 XPath 中,这意味着“选择本地名称为的所有元素item
不在命名空间中”。在 RSS 中,item
元素必须位于命名空间中。因此,上述内容永远不应该与符合标准的 XML 解析器和 XPath 引擎一起使用。
令人困惑的是,在 XML 中,<item>
意思是“一个名为 item 的元素,位于default命名空间,即文档中此位置范围内的任何默认命名空间;”而在 XPath 中,“item”表示no命名空间。 (或者,您可以说,它意味着默认命名空间中的一个元素,但是除非您有办法告诉 XPath 默认命名空间是什么,否则默认命名空间就是无命名空间。通常(总是?)在 XPath 1.0 中没有办法声明 XPath 表达式的默认命名空间。)
对于初学者来说,另一个令人困惑的事情是,XPath 处理器认为源 XML 文档中的名称空间前缀映射并不重要。解析 XML 文档时,会构建一个数据结构,该结构会记住每个元素(以及其他节点)的名称和命名空间。命名空间prefixes使用,包括默认命名空间的空前缀,被认为仅仅是语法上的方便。下面详细介绍这一点...
有了 Nokogiri,我就可以
X路径//xmlns:item
哪个有效并且
返回提要中的所有节点。
不管那是什么,它都不是 XPath。也许它是 Nokogiri 的扩展(一种非常方便的扩展,但它的语法确实违反直觉)。
所以我想我可以表达我的问题
如:如何从
HtmlUnit 的默认命名空间?
让我们将其表达为:如何使用 HtmlUnit 选择 RSS 项目元素?我这样说是因为 RSS 规范(实际上通常是任何符合 XML 词汇规范的规范)不需要它的元素将位于默认名称空间中。您收到的示例中恰好是这样,但服务提供商明天可能会更改这一点,但仍然完全符合 RSS。明天,服务提供商可以为该命名空间使用“rss”命名空间前缀;或任何其他任意前缀。什么RSSdoes指定其元素所在的命名空间:URI 为的命名空间http://purl.org/rss/1.0/
.
这有点像问,“我如何编写一个函数(用 Javascript、C、Java 等)来告诉我变量的值a
?” 通常,函数不知道调用者中使用了什么变量名。它只知道values其论点。如果你打电话sqrt(4)
,你会得到与以下相同的答案a = 4; sqrt(a)
or rumpelstiltzkin = 4; sqrt(rumpelstiltzkin)
。显然,变量参数的名称对函数调用的结果没有直接影响。它只需要是保存正确值的变量的名称。如果编译器因为你写了而抱怨b = 4; return sqrt(b)
而不是使用a
,你会认为编译器疯了。只要您使用有效的标识符,它就不应该关心变量名称。
同样,在处理 RSS 时,我们不应该关心使用什么名称空间前缀,只要它是标识正确名称空间的前缀即可。它可以没有前缀(标识默认名称空间)。
在 XPath 2.0 中,您可以使用通配符命名空间。如果您知道不需要命名空间来消除歧义,那么这将非常方便。在这种情况下您可以选择//*:item
。但是,我不认为 HTMLUnit 支持 XPath 2.0。此外,在 XSLT 2.0 等 XPath 2.0 环境中,您可以为 XPath 表达式指定默认名称空间,但这在 HTMLUnit 中没有帮助。
所以你有几个选择:
- 使用忽略命名空间的 XPath 表达式,例如
//*[local-name() = 'item']
.
or
- 稳健的方法:注册命名空间前缀
http://purl.org/rss/1.0/
并在您的 XPath 表达式中使用它://rss:item
。那么问题就变成了,如何在 HTMLUnit 中注册名称空间前缀并将其传递给 XPath 处理器?我快速浏览了文档,但没有找到任何执行此操作的工具。
Caveat:我应该补充一点,以上内容是关于符合 XPath 处理器的。我不知道 HTMLUnit 使用什么 XPath 处理器。有些 XPath 处理器忽略了规范,让每个人都更加困惑。
I saw here有人对 HTMLUnit 中默认命名空间中的元素使用了以下语法:
//:item
但我不建议这样做,原因有以下三个:
它不是有效的 XPath,因此您不能指望它能够与其他程序一起使用。
它仅适用于将 RSS 命名空间声明为默认命名空间的 RSS 提要。使用名称空间前缀的 RSS 提要将导致上述操作失败。
它会阻碍您了解 XML 名称空间的真正工作原理,并且有助于维持不能充分支持名称空间的工具的现状。
HTMLUnit 主要是为 HTML 设计的,因此对 XML 的不完整处理是可以理解的。但是声称支持 XPath 但却不提供声明命名空间前缀的方法是一种bug。 HTMLUnit 使用 XPath 包,该包似乎是 Xalan-J 的一部分。那个包有提供到 XPath 的名称空间映射的方法,但我不知道 HTMLUnit 是否公开了该功能。