要点
- RSSフィード=HTTP GETのレスポンスに対して指定された形式のXMLをContents-Type=application/xml+atomで返すだけのもの
- google.appengine.ext.db.Model.to_xml()は役に立たない
- GAEでRSSフィードを作るときは、テンプレートエンジンを使うととっても簡単、でももっと良いライブラリがあるかも
- テンプレートエンジン使用時は、日付の指定だけがちょっと面倒で難しいので注意する
現在Google App Engine上でちょこちょこ作っているアプリに、このたびRSSフィード機能を追加いたしました。実はRSSフィードの仕様書を見たのも今回が初めて(!)という初心者丸出し状態でスタートしたのですが、App Engineの機能を使えば簡単にRSSフィード機能を持たせることが出来ます。
今回使用するRSSフィードの種類はAtom1.0にしました。
一番新しそうな感じがするのと、GAEのdb.Modelクラスにto_xml()というメソッドがありまして、これを使えばAtom互換のXMLを自動的に作ってくれるとか何とか言う説明書きを見たので、一番楽そうに見えたのが主な理由です。
まずはAtomの仕様書を見ることにしました。
http://ja.wikipedia.org/wiki/Atom
http://fdays.blogspot.com/2007/12/rss-atom-xml.html
なるほど、指定された書式のXMLをHTTP GETのレスポンスとして返せばいいんですね。Contents-Typeの設定も忘れずにと。
私はRSSフィードというとサーバー側からRSSリーダーに対してプッシュ的にデータを送る必要があるんじゃないかと恐れていたのですが、RSSリーダーが定期的に指定されたURLにアクセスしてくるだけと分かって一安心です。
また、RSSリーダーが定期的にアクセスしてくるならば、バッチ処理のできないGAEにとって福音です。自動的にアクセスしてきたGETに対応してジョブを実行すれば簡易バッチの代わりになります。たとえば一定時間おきに特定ウェブサイトの内容を取得してデータストアに保存したいとか。
続いてModel.to_xml()の実験です。本当にこのメソッドを使えばAtom形式になってくれるんでしょうか?
ということで実行してみた結果がこちら。
<entity kind="Article" key="hogehoge">
<key>
tag:myapp.gmail.com,2008-09-28:Article[hogehoge]
</key>
<property name="content" type="text">
HTMLテキストがここに入っているよ
</property>
<property name="date_new" type="gd:when">
2008-09-28 11:48:55.462361
</property>
<property name="date_update" type="gd:when">
2008-09-28 11:49:01.002539
</property>
<property name="title" type="string">
タイトルだよ
</property>
<property name="url" type="atom:link">
<link href="http://www.hogehoge_dayo.com/article/01.html" />
</property>
</entity>
全然駄目じゃん!!!これのどこがAtomじゃー!!
仕方ないので自分でXMLを作ることにします。
XMLを作るのには、GAE付属のDjango Template Engineを活用することにしました。
当たり前のことなのですが、このテンプレートエンジン、どんな文字列に対しても適用できるんですよね。
(いっつもHTMLを生成するのに使っているので忘れがちなのですが、その気になればCSSやJavaScriptさえ生成できるはずです)
こんなテンプレートを用意します。
<?xml version="1.0" encoding="utf-8" ?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="ja">
<title>Myapp - {{news_category_name}}</title>
<link href="http://myapp.appspot.com/"/>
<link rel="self" href="hogehoge"/>
<author>
<name>akisute</name>
</author>
<updated>{{date_update|date:"Y-m-d\TH:i:s\Z"}}</updated>
<id>hogehoge-this-is-unique-id-hogehoge</id>
{% for article in articles %}
<entry>
<title>{{article.title}}</title>
<link href="{{article.url}}"/>
<content type="html">{{article.content|escape}}</content>
<updated>{{article.date_update|date:"Y-m-d\TH:i:s\Z"}}</updated>
<id>{{article.url}}</id>
</entry>
{% endfor %}
</feed>
後はこのテンプレートを、普段HTMLのレスポンスを返すのと全く同じようにして返すだけ。
class NewsRSS(webapp.RequestHandler):
def get(self, news_category):
self.response.headers['Content-Type'] =
'application/atom+xml'
rss_type = self.request.get('type')
if rss_type != 'atom':
path = 'template/error.html'
self.response.out.write(template.render(path, None))
parser = ParserFactory.getInstance(news_category)
articles = parser.parse()
if articles:
path = 'template/rss/atom-1.0.xml'
p = {
'articles':articles,
'news_category':news_category,
'news_category_name':NEWS_NAME[news_category],
'date_update':datetime.datetime.now(),
}
self.response.out.write(template.render(path, p))
ご覧の通り、GAEで普通のリクエストハンドラーを作るのと全く同じような処理です。
さて、これで全部できました!早速Googleリーダーに読ませてみましょう。
※申し訳ありませんがアプリ名やフィード名は公開できません。
お~~~~~~
読んでる読んでる・・・
自分が作った物を他の人のプログラムがきちんと読んでくれるってなんだか素敵!
初心者丸出し発言ですみません]]>