使用 HtmlUnit 在 XPath 中选择默认命名空间

2023-12-11

我想使用 HtmlUnit 解析 Feedburner 提要。 提要是这样的:http://feeds.feedburner.com/alcoanewsreleases

我想从这个提要中阅读全部内容item节点,所以通常//itemXPath 应该可以解决问题。不幸的是,这在这种情况下不起作用。

常规代码片段:

def page = webClient.getPage("http://feeds.feedburner.com/alcoanewsreleases")
def elements = page.getByXPath("//item")

XML 提要示例:

<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss1full.xsl"?>
<?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?>

<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns="http://purl.org/rss/1.0/" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0">

[...SNIP...]

<item rdf:about="http://www.alcoa.com/global/en/news/news_detail.asp?newsYear=2011&amp;pageID=20110518006002en">
    <title>Chris L. Ayers Named President, Alcoa Global Primary Products</title>
    <dc:date>2011-05-18</dc:date
    <link>http://feedproxy.google.com/~r/alcoanewsreleases/~3/PawvdhpJrkc/news_detail.asp</link>
    <description>NEW YORK--(BUSINESS WIRE)--Alcoa (NYSE:AA) announced today that Chris L. Ayers has been named President of Alcoa’s Global Primary Products (GPP) business, effective May 18, 2011. Ayers, previously Chief Operating Officer of GPP, succeeds John Thuestad, who will be handling special projects for the Company. Ayers joined Alcoa in February 2010 as Chief Operating Officer of Alcoa Cast, Forged and Extruded Products, a new position. He was elected a Vice President of Alcoa in April 2010 and Executive</description>
    <feedburner:origLink xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0">http://www.alcoa.com/global/en/news/news_detail.asp?newsYear=2010&amp;pageID=20100104006194en</feedburner:origLink>
</item>

[...SNIP...]

</rdf:RDF>

我怀疑这是命名空间的问题,因为该文档有 4 个命名空间。命名空间是

  • (这是默认值)xmlns="http://purl.org/rss/1.0/"
  • xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
  • xmlns:dc="http://purl.org/dc/elements/1.1/"
  • xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0"

我尝试将 Nokogiri 与此一起使用(我用于 ruby​​ 脚本的另一个 XML 解析器)。 有了 Nokogiri,我就可以使用 XPath//xmlns:item它可以工作并从提要中返回所有节点。

我已经尝试使用 HtmlUnit 使用相同的 XPath,但它不起作用。

所以我想我可以将我的问题表述为: 如何使用 HtmlUnit 从默认名称空间中选择节点?

有任何想法吗?


我想从这个提要中阅读全部内容item节点,所以通常//itemX路径 应该可以解决问题。很遗憾 在这种情况下这不起作用。

在 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

但我不建议这样做,原因有以下三个:

  1. 它不是有效的 XPath,因此您不能指望它能够与其他程序一起使用。

  2. 它仅适用于将 RSS 命名空间声明为默认命名空间的 RSS 提要。使用名称空间前缀的 RSS 提要将导致上述操作失败。

  3. 它会阻碍您了解 XML 名称空间的真正工作原理,并且有助于维持不能充分支持名称空间的工具的现状。

HTMLUnit 主要是为 HTML 设计的,因此对 XML 的不完整处理是可以理解的。但是声称支持 XPath 但却不提供声明命名空间前缀的方法是一种bug。 HTMLUnit 使用 XPath 包,该包似乎是 Xalan-J 的一部分。那个包有提供到 XPath 的名称空间映射的方法,但我不知道 HTMLUnit 是否公开了该功能。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用 HtmlUnit 在 XPath 中选择默认命名空间 的相关文章

随机推荐