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 

但是,爲什麼從根本上搜索,當你有一個更近的祖先?此外,您應該將名稱空間定義元素及其子項作爲名稱空間的「範圍」。搜索一個有限的範圍不那麼容易混淆,並且避免了細微的錯誤。