Nokogiri / Xpath名称空间查询

时间:2011-01-14 11:52:11

标签: ruby xml xpath nokogiri

我正在尝试使用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 doc在xpath中使用命名空间。

3 个答案:

答案 0 :(得分:66)

解析时需要注册所有名称空间。 Nokogiri自动在根节点上注册名称空间。任何不在根节点上的命名空间,您必须自己注册。这应该有效:

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

或者,您可以完全删除命名空间。只有在您确定没有冲突的节点名称时才执行此操作。

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

答案 1 :(得分:1)

使用opf命名空间URI的正确注册前缀'http://www.idpf.org/2007/opf'dc的{​​{1}},您需要:

'URI'

注意/*/opf:metadata/dc:title xmlns是保留的前缀,无法绑定到除内置xml和{{}之外的任何其他命名空间URI 1}}。

答案 2 :(得分: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

但是,当你有一个更接近的祖先时,为什么要从根搜索?此外,您应该将namespace-defined元素及其子元素视为命名空间的“范围”。搜索有限的范围不那么容易混淆,并避免微妙的错误。