Ruby 1.9.2 リファレンスマニュアル > ライブラリ一覧 > library rss
library rss
要約
RSS を扱うためのライブラリです。
参考
- http://www.cozmixng.org/~rwiki/?cmd=view;name=RSS+Parser
- RSS 0.91 http://backend.userland.com/rss091
- RSS 1.0 http://purl.org/rss/1.0/spec
- RSS 2.0 http://www.rssboard.org/rss-specification
注意
RSS ParserはRSS 0.9x/1.0/2.0をサポートしていますが,RSS 0.90 はサポートしてません.ごめんなさい.
RSS のモジュールはそれぞれ、
- Dublin Core モジュール http://web.resource.org/rss/1.0/modules/dc/
- Syndication モジュール http://web.resource.org/rss/1.0/modules/syndication/
- Content モジュール http://web.resource.org/rss/1.0/modules/content/
- Trackback モジュール http://madskills.com/public/xml/rss/module/trackback/
- Image モジュール http://web.resource.org/rss/1.0/modules/image/
をサポートしています。 ただし,Content モジュールは content:encoded しかサポートしていません.
パース
RSS をパースしたい場合は RSS::Parser クラスを使います。 RSS::Parser.parse は String の RSSを パースします(使用するXMLパー サによっては File や IO オブジェクトなどでもパース可能です)。
をそれぞれ返します。パースした String が well formed な XML で無い場合は, 例外 RSS::NotWellFormedError が発生します。well formed な XML だが,RSS 0.9x/1.0/2.0 のいずれでもない場合は,nil が返りま す.
例えば、RSS 1.0 をバリデーション付きでパースするには以下のよ うにします。ここで、変数 rss_source には RSS 1.0 形式の文 字列が格納されているものとします。
require 'rss' rss = RSS::Parser.parse(rss_source, true)
RSS::Parser.parse の第二引数は省略すると true が指定されたもの とみなされるので、これは以下のようにも書けます。
require 'rss' rss = RSS::Parser.parse(rss_source)
最初はバリデーション付きでパースして,valid ではない RSS だった 場合はバリデーション無しでパースするには以下のように書きます。
require 'rss' rss = nil begin rss = RSS::Parser.parse(rss_source) rescue RSS::InvalidRSSError rss = RSS::Parser.parse(rss_source, false) end
これは rss_source が RSS 0.9x/1.0/2.0 のどれか分からない時 にも有効です。RSS 1.0としてバリデー ション付きでパースし、バリデーションに失敗すると RSS 0.9x/(壊 れた)1.0/2.0 のいずれかとしてパースします。
知らない要素の扱い
パーサはデフォルトでは知らない要素(仕様書に規定されていない 要素)を無視します。もし、知らない要素に遭遇した時に例外を発 生させたければ,RSS::Parser.parse の第三引数に false を指定して ください。こうすると、パース中に知らない要素に遭遇した時に RSS::UnknownTagError 例外が発生します。
以下のようにすると,より厳密にRSS 1.0をパースできます。
RSS::Parser.parse(rss_source, true, false)
パースされたRSS
RSS はパースされると String オブジェクトから RSS::RDF, RSS::RDF::Channel, RSS::Rss 等のオブジェクトになります。各オ ブジェクトで子要素オブジェクトにアクセスするために,要素名と 同じ名前のアクセサがあります。
リーダ(reader)
rdf:RDF 要素の子要素である channel 要素を参照するには,以下のよう にします。
rss = RSS::Parser.parse(rss_source) rss.channel # => /rdf:RDF/channel要素; RSS::RDF::Channel
もし、要素が子要素も属性も持たない場合は String が返ってきます。 その要素が省略可能ならばnilが返って来るかもしれません。これ は要素が子要素または属性を持つ場合も同様です。
rss = RSS::Parser.parse(rss_source) rss.channel.description # => /rdf:RDF/channel/text(); String
属性にアクセスする時も同様です。channel要素のrdf:about属性に アクセスするには以下のようにします。属性の値はStringかnilで す。
rss = RSS::Parser.parse(rss_source) rss.channel.about # => /rdf:RDF/channel/@about属性; String または nil
同名の複数の子要素があるかもしれないときも同様です。ただし、 リーダに引数を指定しないと最初の子要素が返ってきます。例えば、 rdf:RDF要素の最初のitem要素にアクセスするには以下のようにし ます。
rss = RSS::Parser.parse(rss_source) rss.item # => /rdf:RDF/item[1]要素; RSS::RDF::Item
3番目のitem要素にアクセスするには以下のようにします。省略さ れなかったリーダの引数はArray#[]の引数と同じように扱われます。
rss = RSS::Parser.parse(rss_source) rss.item(2) # => /rdf:RDF/item[3]要素; RSS::RDF::Item
子要素すべてを取得したいときは要素名の複数形がリーダとなりま す。すべてのitem要素を取得するには以下のようにします。
rss = RSS::Parser.parse(rss_source) rss.items # => /rdf:RDF/item要素の配列; [RSS::RDF::Item, ...]
ライタ(writer)
rdf:RDF要素の子要素であるchannel要素を設定するには以下のよう にします。RSS::RDF::Channel.newの第一引数にはrdf:about属性の 値を指定することもできます。
rss = RSS::Parser.parse(rss_source) rss.channel = RSS::RDF::Channel.new(rdf_about_value)
属性値を設定する場合も同様です。
rss = RSS::Parser.parse(rss_source) rss.channel.about = "http://cozmixng.www.cozmixng.org/"
同名の複数の子要素が存在する場合は少し異なります.要素名の複 数形でのメソッドで要素の配列を取得して,その配列に対して Array#<<やArray#[]=などを用いて要素を設定します.
rss = RSS::Parser.parse(rss_source) item = RSS::RDF::Item.new(rdf_about_value) rss.items << item rss.items.last == item # => true
注意: item=/set_itemなどはRubyっぽくないので使わないでくださ い.
出力
RSS Parserといっているので誤解されがちですが,RSSを出力する こともできます.
基本
to_sするとRSS形式の文字列を返します.
RSSを出力する流れは以下のようになります.
- RSSオブジェクト(RSS::RDFとかRSS::Rssクラス のオブジェクト)を作成する
- 出力エンコーディングを指定する(省略可)
- RSSオブジェクトのto_sメソッドを呼ぶ
xml-stylesheet
xml-stylesheetも出力することができます.
RSSのルート要素(RSS::RDFまたはRSS::Rss)オブジェ クトはxml_stylesheetsという名前の配列を持っています.この配 列にRSS::XMLStyleSheetオブジェクトを挿入することでRSS にxml-stylesheetを関連づけることができます.
rss.xml_stylesheets << RSS::XMLStyleSheet.new(...)
RSS::XMLStyleSheet.newには以下のようなHashまたは 連想配列を渡します.作成されるRSS::XMLStyleSheetオブジェ クトは与えられた引数によって初期化されます.
Hash:
{ :href => "...", :type => "...", :title => "...", :media => "...", :charset => "...", :alternate => "...", }
連想配列:
[ [:href, "..."], [:type, "..."], [:title, "..."], [:media, "..."], [:charset, "..."], [:alternate, "..."], ]
全てのキーは省略可能です.
例えば,xml-stylesheetとしてsample.xslを指定する場合は以下の ようにします.
rss.xml_stylesheets << RSS::XMLStyleSheet.new({:href => "sample.xsl"})
本当は{:type => "text/xsl"}も指定しないといけないとこ ろですが,拡張子が.xslまたは,.cssの場合は適当に推測してくれ るので省略可能です.
RSSオブジェクトを作る
既存のRSSをパースせずに,一から新しくRSSを作成するにはRSS Makerが便利です.
以下のように使います.
require "rss" rss = RSS::Maker.make("バージョン") do |maker| maker.XXX = YYY ... end
例えば,
- http://example.com/にある
- Example Siteという説明文を持つ
- Exampleというサイトを
- http://example.com/index.rdfという名前のRSS 1.0
を生成するには以下のようにします.
require "rss" rss = RSS::Maker.make("1.0") do |maker| maker.channel.about = "http://example.com/index.rdf" maker.channel.title = "Example" maker.channel.description = "Example Site" maker.channel.link = "http://example.com/" end
もし,
- http://example.com/article.htmlにある
- Sample Articleというタイトルの
エントリを含めたければ以下のようにします.
require "rss" rss = RSS::Maker.make("1.0") do |maker| maker.channel.about = "http://example.com/index.rdf" maker.channel.title = "Example" maker.channel.description = "Example Site" maker.channel.link = "http://example.com/" item = maker.items.new_item item.link = "http://example.com/article.html" item.title = "Sample Article" end
もし,先のエントリが
- 2004/11/1 10:10
のものならこうします.
require "rss" rss = RSS::Maker.make("1.0") do |maker| maker.channel.about = "http://example.com/index.rdf" maker.channel.title = "Example" maker.channel.description = "Example Site" maker.channel.link = "http://example.com/" item = maker.items.new_item item.link = "http://example.com/article.html" item.title = "Sample Article" item.date = Time.parse("2004/11/1 10:10") end
サンプル中の
item.date = ...
は
item.dc_date = ...
でも構いません.#dc_date=は#date=の単なる別名で す.
さらに,
- http://example.com/article2.htmlにある
- Sample Article2という
- 2004/11/2 10:10に作成された
エントリを持つなら以下のようにします.
require "rss" rss = RSS::Maker.make("1.0") do |maker| maker.channel.about = "http://example.com/index.rdf" maker.channel.title = "Example" maker.channel.description = "Example Site" maker.channel.link = "http://example.com/" item = maker.items.new_item item.link = "http://example.com/article.html" item.title = "Sample Article" item.date = Time.parse("2004/11/1 10:10") item = maker.items.new_item item.link = "http://example.com/article2.html" item.title = "Sample Article2" item.date = Time.parse("2004/11/2 10:10") end
もし,更新日が新しい順に並び替えたければ
maker.items.do_sort = true
を追加し,以下のようにします.
require "rss" rss = RSS::Maker.make("1.0") do |maker| maker.channel.about = "http://example.com/index.rdf" maker.channel.title = "Example" maker.channel.description = "Example Site" maker.channel.link = "http://example.com/" maker.items.do_sort = true item = maker.items.new_item item.link = "http://example.com/article.html" item.title = "Sample Article" item.date = Time.parse("2004/11/1 10:10") item = maker.items.new_item item.link = "http://example.com/article2.html" item.title = "Sample Article2" item.date = Time.parse("2004/11/2 10:10") end
もし,サイトに
- Example Siteという名前の
- http://example.com/logo.pngというロゴ
がある場合は以下のようにします.
require "rss" rss = RSS::Maker.make("1.0") do |maker| maker.channel.about = "http://example.com/index.rdf" maker.channel.title = "Example" maker.channel.description = "Example Site" maker.channel.link = "http://example.com/" maker.items.do_sort = true item = maker.items.new_item item.link = "http://example.com/article.html" item.title = "Sample Article" item.date = Time.parse("2004/11/1 10:10") item = maker.items.new_item item.link = "http://example.com/article2.html" item.title = "Sample Article2" item.date = Time.parse("2004/11/2 10:10") maker.image.title = "Example Site" maker.image.url = "http://example.com/logo.png" end
もし,
- http://example.com/search.cgiに
- keywordというパラメタ名で検索できる
- Search Example Siteという名前で
- Search Example Site's all textという説明付きの
検索用CGIがあったら以下のようにします.
require "rss" rss = RSS::Maker.make("1.0") do |maker| maker.channel.about = "http://example.com/index.rdf" maker.channel.title = "Example" maker.channel.description = "Example Site" maker.channel.link = "http://example.com/" maker.items.do_sort = true item = maker.items.new_item item.link = "http://example.com/article.html" item.title = "Sample Article" item.date = Time.parse("2004/11/1 10:10") item = maker.items.new_item item.link = "http://example.com/article2.html" item.title = "Sample Article2" item.date = Time.parse("2004/11/2 10:10") maker.image.title = "Example Site" maker.image.url = "http://example.com/logo.png" maker.textinput.title = "Search Example Site" maker.textinput.description = "Search Example Site's all text" maker.textinput.name = "keyword" maker.textinput.link = "http://example.com/search.cgi" end
もし,
- http://example.com/index.xslにある
xml-stylesheetを追加したい場合は以下のようにします.
require "rss" rss = RSS::Maker.make("1.0") do |maker| xss = maker.xml_stylesheets.new_xml_stylesheet xss.href = "http://example.com/index.xsl" maker.channel.about = "http://example.com/index.rdf" maker.channel.title = "Example" maker.channel.description = "Example Site" maker.channel.link = "http://example.com/" maker.items.do_sort = true item = maker.items.new_item item.link = "http://example.com/article.html" item.title = "Sample Article" item.date = Time.parse("2004/11/1 10:10") item = maker.items.new_item item.link = "http://example.com/article2.html" item.title = "Sample Article2" item.date = Time.parse("2004/11/2 10:10") maker.image.title = "Example Site" maker.image.url = "http://example.com/logo.png" maker.textinput.title = "Search Example Site" maker.textinput.description = "Search Example Site's all text" maker.textinput.name = "keyword" maker.textinput.link = "http://example.com/search.cgi" end
もし,RSS 2.0を生成したい場合は以下のように, RSS::Maker.makeの第一引数を変更します.
require "rss" rss = RSS::Maker.make("2.0") do |maker| xss = maker.xml_stylesheets.new_xml_stylesheet xss.href = "http://example.com/index.xsl" maker.channel.about = "http://example.com/index.rdf" maker.channel.title = "Example" maker.channel.description = "Example Site" maker.channel.link = "http://example.com/" maker.items.do_sort = true item = maker.items.new_item item.link = "http://example.com/article.html" item.title = "Sample Article" item.date = Time.parse("2004/11/1 10:10") item = maker.items.new_item item.link = "http://example.com/article2.html" item.title = "Sample Article2" item.date = Time.parse("2004/11/2 10:10") maker.image.title = "Example Site" maker.image.url = "http://example.com/logo.png" maker.textinput.title = "Search Example Site" maker.textinput.description = "Search Example Site's all text" maker.textinput.name = "keyword" maker.textinput.link = "http://example.com/search.cgi" end
もし,RSS 0.91を生成したい場合は,RSS 2.0の場合と同様に RSS::Maker.make の第一引数を"0.91"に変更します.
サンプル
RSS Parser のサンプルスクリプトをいくつか紹介します.これらの スクリプトは sample/ 以下に入っています.
サンプル1 - 項目一覧
それでは、複数のRSSをパースしてitem要素を表示するスクリプト を書いてみましょう。
まず、RSS 0.9x/1.0/2.0をパースできるように以下のようにrequireします。
require 'rss'
パースするRSSはファイルに保存されていて引数で与えられるものとします。
ARGV.each do |fname| rss_source = nil File.open(fname) do |f| rss_source = f.read end rss = nil begin rss = RSS::Parser.parse(rss_source, false) rescue RSS::Error end if rss.nil? puts "#{fname}はRSS 0.9x/1.0/2.0のいずれでもありません。" else print_items(rss) end end
あとはprint_itemsというメソッドを定義するだけです。
RSS::RDFとRSS::Rssには便利のためにitemsというメソッドとimage というメソッドが定義されています。
itemsはRSS::RDFの場合は全ての/rdf:RDF/item要素を配列で返しま す。RSS::Rssの場合は全ての/rss/channel/item要素を配列で返し ます。
imageはRSS::RDFの場合は/rdf:RDF/image要素を返します。 RSS::Rssの場合は/rss/channel/image要素を返します。
def print_items(rss) rss.items.each do |item| puts "#{item.title} : #{item.description}" end end
出力する文字コードを変更するにはRSS::RDF#output_encoding=ま たはRSS::Rss#output_encoding=が使えます。もし、変換できない エンコーディングを指定された場合は RSS::UnknownConversionMethodError例外が発生します。
先程のprint_itemsをEUC-JPで出力するように書き換えてみましょう。
def print_items(rss) begin rss.output_encoding = "EUC-JP" rescue RSS::UnknownConversionMethodError end rss.items.each do |item| puts "#{item.title} : #{item.description}" end end
サンプル2 - 更新順表示
次はDublin Coreモジュールのdate属性を使って更新順にitemを表 示してみましょう。
最初に現れたDublin Coreモジュールの要素にアクセスするには 「dc_要素名」というアクセサが用意されています。全ての要素の 配列にアクセスするには「dc_要素の複数形」((-dc:rightsは dc_rightsesという風になっていて気に入っていません.だれか良 い案を下さい.-))とします.
複数形でアクセスした場合は「要素の内容を表す文字列」ではなく, 「要素を表すオブジェクト」の配列が返ります.「要素を表すオブ ジェクト」から「要素の内容を表す文字列」を取得するには contentメソッドやその別名であるvalueメソッドを利 用します.「要素の内容を表す文字列」を設定するには content=メソッドやその別名であるvalue=メソッドを 利用します.
rss.channel.dc_title # => 「要素の内容を表す文字列」 # ("My site"など) rss.channel.dc_titles # => 「要素を表すオブジェクト」の配列 # ([DublinCoreTitleオブジェクト, ...]) rss.channel.dc_titles.collect {|title| title.value} # => 「要素の内容を表す文字列」の配列 # (["My site", ...]など) rss.channel.dc_titles.first.value == rss.channel.dc_title # => true # 厳密にはこう first_title = rss.channel.dc_titles.first first_title = first_title.value if first_title first_title == rss.channel.dc_title # => true
ちなみにSyndicationモジュールの要素にアクセスするには「sy_要 素名」というアクセサが,Contentモジュールの要素にアクセスす るには「content_要素名」というアクセサが用意されています。
サンプル1と同じようにパースするRSSはファイルに保存されていて 引数で与えられるものとします。
items = [] ARGV.each do |fname| rss_source = nil File.open(fname) do |f| rss_source = f.read end rss = nil begin rss = RSS::Parser.parse(rss_source, true) rescue RSS::Error end if rss.nil? puts "#{fname}はRSS 1.0ではありません。" else begin rss.output_encoding = "euc-jp" rescue RSS::UnknownConversionMethodError end rss.items.each do |item| items << item if item.dc_date end end end print_items(items)
あとはprint_itemsというメソッドを定義するだけです。
Item#dc_dateはTimeオブジェクトかnilを返します。引数の itemsにはdc_dateがnilではないものしか含まれていないは ずなので以下のようにソートできます。
def print_items(items) items.sort do |x, y| y.dc_date <=> x.dc_date end.each do |item| puts "#{item.dc_date.localtime.iso8601} : #{item.title} : #{item.description}" end end
サンプル3 - 複数のRSSをブレンド
TODO: sample/blend.rbを元にしたサンプルを書く.
クラスとモジュール
例外クラス
追加・再定義されるメソッド
RSS::Rss::Channel#generator
[added by rss]RSS::Rss::Channel#generator=
[added by rss]RSS::Rss::Channel#ttl
[added by rss]RSS::Rss::Channel#ttl=
[added by rss]RSS::Rss::Channel::Item#author
[added by rss]RSS::Rss::Channel::Item#author=
[added by rss]RSS::Rss::Channel::Item#comments
[added by rss]RSS::Rss::Channel::Item#comments=
[added by rss]RSS::Rss::Channel::Item#guid
[added by rss]RSS::Rss::Channel::Item#guid=
[added by rss]RSS::Rss::Channel::Item#pubDate
[added by rss]RSS::Rss::Channel::Item#pubDate=
[added by rss]