2011-01-14 23 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') 
+0

恐ろしい、完璧に働いた! – Jamie

+3

+1 remove_namespaces FTW! –

+1

ありがとうございました!!!これは魔法です! – Jirapong

1
適切 'http://www.idpf.org/2007/opf'名前空間URI用の接頭辞 opfを登録して

、および'URI'ためdcは、次のものが必要です。

/*/opf:metadata/dc:title 

注意をxmlnsxmlが他の名前空間URIにバインドすることはできませんプレフィックスを予約されています組み込みの'http://www.w3.org/2000/xmlns/'および'http://www.w3.org/XML/1998/namespace'よりも優れています。

+0

doc.xpath( '/ */opf:metadata/dc:title')#=> "評価":未定義の名前空間接頭辞 " – Jamie

+0

@Jamie:答えを実際に読んだことがありますか?最初の文章が始まる* "適切に登録されたプレフィックス" * ... –

+0

@Alejandroの謝罪opfの接頭辞なしでそれを行う方法は完全にはわかりません(@ mark-thomasの答えに記載されている方法を除いて)、それは1つのxpathクエリでそれを行うのがいいですね。 – Jamie

0

名前空間URIのハッシュを明示的に構築する代わりに、定義されているxml要素から名前空間定義を取得することができます。

あなたの例の使用:第二のxpathもしてきた可能性があること

# 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) 

注:

doc.at_xpath('//dc:title', metadata.namespaces).to_s 

しかし、あなたは近い祖先を持っているとき、なぜ根本から検索!また、名前空間定義要素とその子要素を名前空間の「スコープ」として考慮する必要があります。限られた範囲を検索することはあまり混乱を招くことはなく、微妙なバグを避けることができます。