Nokogiri/Xpath命名空间查询

42

我正在尝试使用xpath提取dc:title元素。我可以使用以下代码提取元数据。

doc = <<END
<?xml version="1.0" encoding="UTF-8"?>
<package xmlns="http://www.idpf.org/2007/opf" version="2.0">
  <metadata xmlns:dc="URI">
    <dc:title>title text</dc:title>
  </metadata>
</package>
END

doc = Nokogiri::XML(doc)

# Awesome this works!
puts '//xmlns:metadata'
puts doc.xpath('//xmlns:metadata')
# => <metadata xmlns:dc="URI"><dc:title>title text</dc:title></metadata>

如您所见,以上代码似乎可以正确运行。但我无法从此节点树中获取标题信息,以下所有方法均失败。

puts doc.xpath('//xmlns:metadata/title')
# => nil

puts doc.xpath('//xmlns:metadata/dc:title')
# => ERROR: `evaluate': Undefined namespace prefix

puts doc.xpath('//xmlns:dc:title')
# => ERROR: 'evaluate': Invalid expression: //xmlns:dc:title

请问如何在上述XML文档中使用命名空间?

3个回答

77

在解析时需要注册所有的命名空间。Nokogiri会自动在根节点上注册命名空间。任何没有在根节点上的命名空间都需要手动注册。以下代码应该可以正常工作:

puts doc.xpath('//dc:title', 'dc' => "URI")

或者,您可以彻底删除命名空间。只有在确定不会出现冲突的节点名称时才这样做。

doc.remove_namespaces!
puts doc.xpath('//title')

3
使用 remove_namespace! 是首先尝试的最明智的事情。但要注意:如果您修改了此 XML 并将其提交给外部 API,则该 API 将(通常)拒绝它而不带命名空间。 - Simon Lepkin

1

使用正确注册的前缀opf代表命名空间URI'http://www.idpf.org/2007/opf',以及dc代表'URI',您需要:

/*/opf:metadata/dc:title

注意xmlnsxml是保留前缀,不能绑定到除内置的'http://www.w3.org/2000/xmlns/''http://www.w3.org/XML/1998/namespace'之外的任何其他命名空间URI。


似乎没有起作用 doc.xpath('/*/opf:metadata/dc:title') # => "`evaluate': 未定义命名空间前缀" - Jamie
@Jamie:你真的读了这个答案吗?第一句话开始是“使用正确注册的前缀”... - user357812
@Alejandro 抱歉,我不是很理解,有没有一种方法可以在没有opf前缀的情况下完成它(除了@mark-thomas答案中描述的方法),这样做只需要一个xpath查询就可以了。 - Jamie
@Jamie:没问题。但是你需要理解XML命名空间很重要。这是一个XPath表达式。你需要知道你的XPath引擎用于注册命名空间的方式。从@Mark Thomas的回答中,似乎可以通过xpath()函数的第二个参数来实现... - user357812

0
作为构建命名空间URI哈希的替代方法,您可以从定义它们的XML元素中检索命名空间定义。
使用您的示例:
# First grab the metadata node, because that's where "dc" is defined.
metadata = doc.at_xpath('//xmlns:metadata')

# Pass metadata's namespaces as the resolver.
metadata.at_xpath('dc:title', metadata.namespaces)

请注意第二个XPath也可以是:
doc.at_xpath('//dc:title', metadata.namespaces).to_s

但是,当你有一个更近的祖先时,为什么要从根目录搜索呢?此外,您应该将定义命名空间的元素及其子元素视为命名空间的“范围”。在有限的范围内搜索会更清晰,避免出现微妙的错误。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接