xpath - 使用HtmlUnit在XPath中选择默认 namespace

标签 xpath groovy namespaces xml-namespaces htmlunit

我想用HtmlUnit解析Feedburner供稿。
提要是以下内容:http://feeds.feedburner.com/alcoanewsreleases

我想从此提要中读取所有项目节点,因此通常//item XPath应该可以解决问题。不幸的是,在这种情况下不起作用。

常规代码段:

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 XPath
应该可以。不幸
在这种情况下不起作用。


在XPath中,这意味着“选择本地名称为item且没有名称空间的所有元素”。在RSS中,item元素必须位于名称空间中。因此,以上内容绝对不能与兼容的XML解析器和XPath引擎一起使用。

令人困惑的是,在XML中,<item>的意思是“一个名为item的元素位于默认名称空间中,即该文档中此位置范围内的任何默认名称空间;”而在XPath中,“ item”表示没有名称空间的元素。 (或者,您可以说这意味着默认名称空间中的一个元素,但是除非您有办法告诉XPath默认名称空间是什么,否则默认名称空间就没有名称空间。通常(总是?)在XPath 1.0中是无法实现的声明XPath表达式的默认名称空间。)

令初学者感到困惑的另一件事是,XPath处理器认为源XML文档中的名称空间前缀映射不重要。解析XML文档时,将建立一个数据结构,该数据结构会记住每个元素(和其他节点)的名称和名称空间。所使用的名称空间前缀(包括默认名称空间的空前缀)仅被视为语法上的便利。下面的更多内容...


有了Nokogiri,我就可以
XPath //xmlns:item可以和
返回提要中的所有节点。


不管是什么,它都不是XPath。也许它是对它的Nokogiri扩展(一种非常方便的扩展,但是其语法确实违反直觉)。


所以我想我可以提出我的问题
如:我如何从中选择一个节点
HtmlUnit的默认名称空间?


让我们将其表述为:如何使用HtmlUnit选择RSS项目元素?之所以这样说是因为RSS规范(实际上通常是任何符合XML的词汇规范)都不需要其元素位于默认名称空间中。在您收到的样本中,这确实是正确的,但是服务提供商可能会在明天更改此内容,并且仍然完全符合RSS。明天,服务提供者可以为该名称空间使用“ rss”名称空间前缀。或任何其他任意前缀。 RSS确实指定的是其元素将位于哪个名称空间:URI为http://purl.org/rss/1.0/的名称空间。

有点像在问:“我如何编写一个函数(使用Javascript,C,Java等),可以告诉我变量a的值?”通常,函数不知道在调用方中使用了什么变量名。它所知道的只是其参数的值。如果呼叫sqrt(4),将获得与a = 4; sqrt(a)rumpelstiltzkin = 4; sqrt(rumpelstiltzkin)相同的答案。显然,变量参数的名称对函数调用的结果没有直接影响。它只需要是拥有正确值的变量的名称。如果编译器抱怨是因为您编写了b = 4; return sqrt(b)而不是使用a,那么您会认为编译器很疯狂。只要使用有效的标识符,就不应该关心变量名。

同样,在处理RSS时,我们不必关心使用什么名称空间前缀,只要它是标识正确名称空间的前缀即可。它不能是前缀(标识默认名称空间)。

在XPath 2.0中,可以通配名称空间。如果您知道不需要歧义空间,这将非常方便。在这种情况下,您可以选择//*:item。但是,我不认为HTMLUnit支持XPath 2.0。同样在XPath 2.0环境(例如XSLT 2.0)中,您可以为XPath表达式指定默认的命名空间,但这在HTMLUnit中无济于事。

因此,您有两种选择:


使用忽略名称空间(例如//*[local-name() = 'item'])的XPath表达式。


要么


健壮的方法:为http://purl.org/rss/1.0/注册一个名称空间前缀,并在您的XPath表达式://rss:item中使用它。问题就变成了,如何在HTMLUnit中注册名称空间前缀并将其传递给XPath处理器?我快速浏览了一下文档,却没有找到执行此操作的任何工具。


警告:我还要补充一点,以上内容是关于符合标准的XPath处理器的。我不知道HTMLUnit使用什么XPath处理器。有一些XPath处理器忽略了规范,使每个人都感到困惑。

我看到here有人对HTMLUnit的默认名称空间中的元素使用了以下语法:

//:item


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


它不是有效的XPath,因此您不能指望它可以与其他程序一起使用。
它仅适用于声明RSS名称空间为默认名称空间的RSS feed。使用名称空间前缀的RSS feed将导致以上操作失败。
它将使您不了解XML命名空间的真正工作原理,并有助于保持那些不充分支持命名空间的工具的现状。


HTMLUnit主要是为HTML设计的,因此可以理解XML的不完整处理。但是声称支持XPath然后不提供声明名称空间前缀的方法是bug。 HTMLUnit使用的XPath包似乎是Xalan-J的一部分。该软件包具有ways to provide namespace mappings to XPath,但我不知道HTMLUnit是否公开了该功能。

关于xpath - 使用HtmlUnit在XPath中选择默认 namespace ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6111202/

相关文章:

xml - 选择第一个 child 是某个标签的 parent

c# - 如何使用 xml 将内容多行转换为 html

java - 我们可以将 Spring Cloud Contract 请求/响应属性设置为可选吗?

laravel - 我应该如何在 Laravel 包中输入提示 UserModel?

python - 选择其子/孙/..包含具有指定模式的元素的元素

Javascript/JSON 获取给定子节点的路径?

java - Groovy Array.addAll 方法从原始数组中删除元素

grails - 如何通过grails删除保存在文件夹中的文件?

namespaces - XSD 导入命名空间

c++ - 在 C++ 中获取命名空间名称的任何可移植技巧?