Yapra の Feed::Custom で attribute を扱えるようにする

※ 取り込まれたのでもうこのパッチは不要です。

えー。github にアカウントは作るところまではいったのですが面倒になったのでとりあえずここに貼ります。

使い方はこんな感じ。

- module: Feed::Custom
  config:
    url: URL
    extract_xpath:
      capture: '//div[@class="FOO"]//ul'
      split: '/li'
      link:  # <- ココ
        first_node: '//a[@class="BAR"][1]'
        attr: :href
      # 従来の書き方
      title: '//a[@class="BAR"]/text()'

extract_xpath 内に書けるものは

capture
url の中で処理を開始したい node を特定する xpath
split
capture した elemens を each で回す際に分割で利用する xpath
これ以外
feed item 内に生成したい「要素」の名前を key に、「内容」となる HTML 文字列を取得したい node を特定する xpath を value にとる Hash

です。前回の話の中でチラッと言っていたのは、value は item の「内容」になるはずなのに「HTML 文字列」が取れてもあんまり嬉しくないなぁという話でした。HTML の「内容」は xpath で一発で取れるけど「属性値」も取りたいということです。

で、はたと思いついて、value をさらに first_node と attr を key に持つ Hash にしてみました。

コードはこんな感じ。ベッタベタです。いじったのは Feed::Custom ではなく MechanizeBase の方になります。

 @@ -11,7 +11,14 @@ class Yapra::Plugin::MechanizeBase < Yapra::Plugin::Base
   def extract_attribute_from element, item
     if plugin_config['extract_xpath']
       plugin_config['extract_xpath'].each do |k, v|
-        value = element.search(v).to_html.toutf8
+        value = nil
+        case v.class.to_s
+        when "String"
+          value = element.search(v).to_html.toutf8
+        when "Hash"
+          ele = element.at( v['first_node'] )
+          value = ( ele.nil? ) ? nil : ele.get_attribute( v['attr'] )
+        end
         set_attribute_to item, k, value
       end
     end

Hpricot には search() と at() があって、search() で返ってくるのは Hpricot::Elements, at() で返ってくるのは Hpricot::Elem1 でして、at() が呼べれば属性値は get_attribute() ですぐ取れます。(引数は、サンプルの YAML では symbol で書いてますが文字列でもいいです。)

最初このためにメソッドと同じ「at」を key として使おうと思ったのですが、attr と区別しにくいので first_node にしてみました。こういう要求は際限がなさそうだけど、この程度で収まるなら at() の挙動もはっきり分かるし、悪くないかな?2

あ、toutf8 を呼んでないな。んー。あれでもこれページを取得したときに toutf8 した方がいいような? 内容が短くなってからの方が判別難しくなっちゃいませんか?

cf.

p.s.

先日ぼやいていた YAML は grep まで含めて動きました。いやー便利便利。

  1. 複数見つかった場合は最初の一つ。要は search()[0] と同じと思って間違いない? 

  2. Hpricot はいろんな機能が楽に呼べるのでどういう風に YAML の形に落とし込めるように制限するかがなかなか難しいですね。 

More