2011-01-14 91 views
32

我正在尝试使用xpath提取dc:title元素。我可以使用以下代码提取元数据。Nokogiri/Xpath名称空间查询

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文档在xpath中使用名称空间。

回答

60

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

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

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

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

有了正确注册前缀为opf命名空间'http://www.idpf.org/2007/opf' URI,并为dc'URI',您需要:

/*/opf:metadata/dc:title 

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

+0

似乎没有工作doc.xpath('/ */opf:元数据/ dc:标题')#=>“评估”:未定义的命名空间前缀“ – Jamie 2011-01-14 12:30:28

+0

@Jamie:你真的读过答案吗?第一句话开始*“有正确注册的前缀”* ... – 2011-01-14 12:39:49

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 

但是,为什么从根本上搜索,当你有一个更近的祖先?此外,您应该将名称空间定义元素及其子项作为名称空间的“范围”。搜索一个有限的范围不那么容易混淆,并且避免了细微的错误。