REXML::StreamParser の使い方
REXML Parser について簡単に調べてみます。
lib/rss/rexmlparser.rb にて REXML は下記のように使われています。
REXML::Document.parse_stream(@rss, @listener)
これはストリーム型と呼ばれるパース方法で、パース後に tree が作られるのではなく、逐次 Listener へ解析結果が通知されるような形となります(SAX 型もたぶん一緒)。
よって調べるべきは Listener の方で、Listener では REXML::StreamListener を include していますので、これを調べれば使い方はある程度わかりそうです。
ということで下記サイトで調べてみました(須藤功平さんに感謝)。
http://pub.cozmixng.org/~kou/rexml-doc-ja/
目立つところでは REXML::StreamListener クラスは tag_start や tag_end といった通知系メソッドが定義されています。これらはサイトに記載がありますように、前者は要素(タグ)が現れたときに呼ばれ、後者は終了要素(タグ)が現れると呼ばれます。これがストリーム方式と言われている部分です。
# それ以外にもメソッドがありますが、何となくどんなことをしているのか判別できればよいためここではこれ以上深入りはしません。
では、試しに使ってみたいと思います。ネタは例によってこのサイトの RSS データにします。Listener を作って、それを REXML::Document.parse_stream に渡すだけです。tag_start, tag_end をオーバーライドして rss, channel, item 要素だった場合に Print するようにしてみました。
#!ruby require 'rexml/document' require 'rexml/streamlistener' require 'rss' url = "http://d.hatena.ne.jp/bazz/rss2" rss_cont = open(url) { |u| u.read } class RSSListener include REXML::StreamListener def tag_start(tag, attrs) case tag when "rss" s = "" when "channel" s = " " when "item" s = " " else return end print s + tag + "\n" end def tag_end(tag) case tag when "rss" s = "" when "channel" s = " " when "item" s = " " else return end print s + "/" + tag + "\n" end end listener = RSSListener.new REXML::Document.parse_stream(rss_cont, listener)
結果は以下のようになります。
rss channel item /item item /item item /item item /item item /item item /item item /item item /item /channel /rss
私でも、ものの数分でできてしまいました。Ruby 恐るべし。。。
では、REXML::StreamParser の使い方がわかったところで今日はおしまいにします。
RSS Lib でも、REXML::StreamParser を継承することで、rss 要素が始まったときや、channel 要素が始まったときなどに何らかの処理をすることで RSS 解析結果を蓄積していると考えられます。
参考サイト
REXML API ドキュメントの日本語版
http://pub.cozmixng.org/~kou/rexml-doc-ja/