1

Hpricot + Ruby XML の構文解析と論理選択。

目的: 著者ボブによって書かれたすべてのタイトルを見つけます。

私のXMLファイル:

<rss>
<channel>
<item>
<title>Book1</title>
<pubDate>march 1 2010</pubDate>
<author>Bob</author>
</item>

<item>
<title>book2</title>
<pubDate>october 4 2009</pubDate>
<author>Bill</author>
</item>

<item>
<title>book3</title>
<pubDate>June 5 2010</pubDate>
<author>Steve</author>
</item>
</channel>
</rss>

#my Hpricot, running this code returns no output, however the search pattern works on its own.
 (doc % :rss % :channel / :item).each do |item|

        a=item.search("author[text()*='Bob']")

        #puts "FOUND" if a.include?"Bob"
        puts item.at("title") if a.include?"Bob"

  end
4

2 に答える 2

3

Hpricotに設定されていない場合は、 Nokogiri で XPath を使用してこれを行う 1 つの方法を次に示します。

require 'nokogiri'
doc = Nokogiri::XML( my_rss_string )
bobs_titles = doc.xpath("//title[parent::item/author[text()='Bob']]")
p bobs_titles.map{ |node| node.text }
#=> ["Book1"]

編集: @theTinMan の XPath もうまく機能し、読みやすく、より高速になる可能性があります。

bobs_titles = doc.xpath("//author[text()='Bob']/../title")
于 2011-02-11T22:01:35.273 に答える
2

XPath の背後にあるアイデアの 1 つは、ディスク ディレクトリと同様に DOM をナビゲートできるようにすることです。

require 'hpricot'

xml = <<EOT
<rss>
    <channel>
        <item>
            <title>Book1</title>
            <pubDate>march 1 2010</pubDate>
            <author>Bob</author>
        </item>

        <item>
            <title>book2</title>
            <pubDate>october 4 2009</pubDate>
            <author>Bill</author>
        </item>

        <item>
            <title>book3</title>
            <pubDate>June 5 2010</pubDate>
            <author>Steve</author>
        </item>

        <item>
            <title>Book4</title>
            <pubDate>march 1 2010</pubDate>
            <author>Bob</author>
        </item>

    </channel>
</rss>
EOT

doc = Hpricot(xml)

titles = (doc / '//author[text()="Bob"]/../title' )
titles # => #<Hpricot::Elements[{elem <title> "Book1" </title>}, {elem <title> "Book4" </title>}]>

つまり、「ボブの本をすべて見つけてから、1 レベル上を調べて、タイトル タグを見つける」ということです。

すべてのオカレンスを取得することをテストするために、"Bob" による別の本を追加しました。

Bob の本を含むアイテムを取得するには、レベルを 1 つ上に戻します。

items = (doc / '//author[text()="Bob"]/..' )
puts items # => nil
# >> <item>
# >>             <title>Book1</title>
# >>             <pubdate>march 1 2010</pubdate>
# >>             <author>Bob</author>
# >>         </item>
# >> <item>
# >>             <title>Book4</title>
# >>             <pubdate>march 1 2010</pubdate>
# >>             <author>Bob</author>
# >>         </item>

私はまた、何をしているのかを理解しました(doc % :rss % :channel / :item)。これは、検索をネストして、折り返し括弧を除いたものと同等であり、Hpricot-ese ではこれらはすべて同じである必要があります。

(doc % :rss % :channel / :item).size # => 4
(((doc % :rss) % :channel) / :item).size # => 4
(doc / '//rss/channel/item').size # => 4
(doc / 'rss channel item').size # => 4

'//rss/channel/item'通常、XPath アクセサー'rss channel item'は CSS アクセサーとして表示されるため、メンテナンスと明確化のためにこれらの形式を使用することをお勧めします。

于 2011-02-12T00:18:49.997 に答える