Nokogiri/Xpath namespace query
我正在尝试使用xpath提取
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | 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> |
如您所见,以上内容似乎正常工作。 但是,我似乎无法从该节点树中获取标题信息,以下所有操作均失败。
1 2 3 4 5 6 7 8 | 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中使用名称空间。
解析时需要注册所有名称空间。 Nokogiri自动在根节点上注册名称空间。任何不在根节点上的名称空间都必须自己注册。这应该工作:
1 | puts doc.xpath('//dc:title', 'dc' =>"URI") |
或者,您可以完全删除名称空间。仅当您确定不会有冲突的节点名称时,才执行此操作。
1 2 | doc.remove_namespaces! puts doc.xpath('//title') |
对于
1 | /*/opf:metadata/dc:title |
注意:
作为显式构造名称空间URI的哈希的替代方法,您可以从定义它们的xml元素中检索名称空间定义。
使用您的示例:
1 2 3 4 5 | # 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也可以是:
1 | doc.at_xpath('//dc:title', metadata.namespaces).to_s |
但是,当您的祖先较近时,为什么要从根开始搜索呢?另外,您应将定义命名空间的元素及其子元素视为命名空间的"作用域"。搜索有限范围的文件不会造成混乱,并且避免了细微的错误。