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 まで含めて動きました。いやー便利便利。