おさらい
それでは、Atomの詳細を解説していきたいとおもいます。
前回、Atomの基本部分は二つの仕様から構成されていることをご紹介しました。
一つはAtomフィードと呼ばれるサーバから配信されるデータフォーマットに関する仕様で、二つめはサーバへコンテンツを登録したりそのデータを編集したりするためのプロトコル仕様です。
前者はAtom Syndication Format、後者はAtom Publishing Protocolというのが正式名称です。本稿では、それぞれAtomフィード、AtomPubという呼び方を使うことにします。
AtomフィードはRSSフィードがあるにも関わらず、新しく作られました。
これについては、RSSを使うべきだったという否定的な意見もありますし、RSSではできないことがあるからこそ作ったという肯定的な意見もあります。
いずれにせよAtomフィードは、RSSフィードとともに使われていくことになるでしょう。それぞれのフィードはよく考えられた仕様であり、シンプルにできていますので、両方に対応することはさほど難しくありません。並存することのデメリットについて、あまり目くじらをたてる必要もないでしょう。
また、よくRSSとの違いを聞かれますが、RSSはAtomのようにサーバ側に向かう方向の仕様がありません。サーバからの情報配信に利用することはできても、クライアントからサーバへWebリソースを登録・更新・削除する際にRSSを利用することはできません。
Atomフィード
本稿ではAtomPubを中心に説明する予定ですので、Atomフィードのフォーマットについてはあまり深く説明をしません。しかし、AtomPubでもこのフォーマットを利用しますので、かいつまんで紹介します。既にご存知の方は、読み飛ばして「AtomPub:Webリソースの操作」からお読みください。
Atomフィードは情報のリストであり、XML文書で表現されます。フィードはエントリと呼ばれる一つ一つの情報から構成されています。それぞれentry要素、feed要素で表現されます。RSSをご存知の方は、item要素がentry要素に相当し、channel要素がfeed要素に相当するとお考えください。
フィードは後で説明するコレクションのXML表現に相当し、エントリはメンバのXML表現に相当します。
フィードフォーマット
次に示すコードはAtomフィードの一例です。フィード自身のタイトルや作者の情報、そしてidが記述されています。このidはフィード固有のもので、何らかの法則で割り振られます。
フィードは情報のリストですので、0個以上のentry要素を子要素として持つことができます。以下の例では一つのエントリがリストアップされています。
表1はatom:feed(接頭辞はRFC 4287で規定されている名前空間 http://www.w3.org/2005/Atom の意味で使用しています)に出現できる主な子要素の一覧です。子要素の順番については意味がないと定義されていますので出現順序は任意となっています。
表1 atom:feedに出現できる子要素(表中の「出現ルール」は、*:0個以上、?:1個または0個、1:1個出現するという意味で使用している)
要素 | 出現ルール | 内容 |
atom:author | *[注1] | 著者情報 |
atom:category | * | カテゴリを表す |
atom:contributor | * | 貢献した人 |
atom:generator | ? | 生成したソフトウエア等の情報 |
atom:icon | ? | このフィードに対するアイコン |
atom:id | 1 | フィードを一意に識別する識別子 |
atom:link | *[注2] | web リソースに対するリンク(意味が与えられる場合があります) |
atom:logo | ? | フィードに対するロゴイメージ |
atom:rights | ? | 権利情報 |
atom:subtitle | ? | 人間が理解できる説明または副題 |
atom:title | 1 | 人間が理解できるタイトル |
atom:updated | 1 | (重要でない更新を除く)最新更新時刻 |
atom:entry | * | |
基本的には表中の出現ルールに従いますが、以下の条件がつきます。
- [注1]子要素のatom:entryが全くatom:authorを含まない場合は1個以上のatom:authorが出現する必要があります。
- [注2]自分自身のフィードを取得するためのURIをrel属性値がselfである要素として一つだけ含むべきです。
- [注2]rel属性値がalternateである要素において、type属性値とhreflang属性値の組み合わせが同じような要素を複数出現させることはできません。
エントリフォーマット
次に示すコードはAtomエントリの一例です。エントリのメタ情報とともにcontent要素内にその情報が記載されています。フィードと同様、エントリ固有のidがあります。更新された時刻についてはupdated要素で知ることができます。
表2はatom:entryに出現できる主な子要素の一覧です。子要素の順番についてはatom:feedと同じく意味がないと定義されていますので出現順序は任意となっています。
表2 atom:entryに出現できる子要素(表中の「出現ルール」は、*:0個以上、?:1個または0個、1:1個出現するという意味で使用している)
要素 | 出現ルール | 内容 |
atom:author | *[注1] | 著者情報 |
atom:category | * | カテゴリを表す |
atom:content | ? | エントリの内容を表す(リンクを使って表現することも可能) |
atom:contributor | * | 貢献した人 |
atom:id | 1 | エントリを一意に識別する識別子 |
atom:link | * [注2] | webリソースに対するリンク(意味が与えられる場合があります) |
atom:published | ? | リソースが作成されたもしくは利用できるようになった日付時刻 |
atom:rights | ? | 人間が可読な権利情報 |
atom:source | ? | エントリを複製する際に元のメタ情報を格納できる |
atom:summary | ?[注3] | エントリの要約 |
atom:title | 1 | エントリのタイトル |
atom:updated | 1 | 変更された日付時刻 |
app:edited | ? | エントリが編集された最終時刻 |
※接頭辞appは、名前空間http://www.w3.org/2007/appの意味で使用しています。
- [注1]一つ以上のatom:author要素を含む必要があります。ただしatom:author要素を含むatom:source要素を含む場合はこの限りではありません。また、フィード文書に出現しているエントリの場合で、そのatom:feed要素自体がatom:author要素を含む場合は、この限りではありません(要するにどこかでatom:authorが出てきていれば良いということです)。
- [注2]atom:content要素を含まない場合は、rel="alternate"であるatom:link要素が少なくとも一つは必要です。
- [注2]rel="alternate"であるatom:link要素において、type属性値とhreflang属性値の組み合わせが同じような要素を複数出現させることはできません。
- [注3]atom:contentがsrc属性を含んで外部のリソースを参照している場合やatom:contentの内容がbase64でエンコードされている場合などは、content自体がこの要素内で分かりませんので、atom:summary要素が必須と規定されています。
atom:link要素
ここで、フィードとエントリ内で使われるatom:link要素について説明しておきます。atom:link要素は、entry要素またはfeed要素内からwebリソースへの参照を示すために使われます。この要素はrel属性をもつことができ、リンクの関係性を表すことができます。Atomではこれらをうまく使うことにより表現をより豊かにしています。
また、atom:content要素でもsrc属性を使ってリンクを表現することが可能となっており、rel="alternate"と近い意味で使われることがありますが、今回は紙面の都合上詳しくは触れません。
表3 atom:link要素における、rel属性の意味
rel属性値 | 意味 |
rel属性が出現しない | rel="alternate"と解釈する |
alternate | そのエントリ、フィードの別バージョンを示します(よく使われるのは,そのエントリ、フィードを Web ブラウザで見られるページを示します)。 |
related | そのエントリ、フィードで説明されるリソースに関連するリソースを示します(具体的には関連するものであれば何でも良いようです)。 |
self | そのエントリ、フィードと等価なリソースを示します。 |
enclosure | 関連するリソースを指し示しますが、サイズが大きい可能性があって特別な処理を必要とすることを意味します(具体的にはそのリソースに含まれる画像などが対象となるようです)。 |
via | 情報源のリソースを示します。 |
edit | メンバリソースを操作するためのURIを示します(後述)。 |
edit-media | メディアリソースを操作するためのURIを示します(後述)。 |
AtomPub:Webリソースの操作
リソースのCRUD操作
さて、いよいよAtompubにおけるWebリソースの操作をみていくことにしましょう。
前回説明したように、AtomPubのデータモデルは簡単に言うと、「コレクション」と呼ばれるWebリソースの集合と、その中に入る「メンバリソース」から構成されています。一般的にはサーバ側に複数のコレクションがあり、それぞれのコレクションにはURI[1]が割り当てられるでしょう。また、コレクションの中にあるメンバリソースの一つ一つにもURIが割り当てられます。コレクションおよびメンバリソースを操作する際には対応するURIに対してHTTPメソッドを適用することになります。
次からメンバリソースの取得・追加・更新・削除のそれぞれについて解説します。これらの操作は、Create, Read, Update, Deleteのそれぞれの頭文字をとってCRUDと呼ばれます。
- 一覧の取得
メンバリソースの一覧を取得するためにはコレクションURIに対してGETメソッドを適用します。メンバリソース(のうち後述するエントリリソースのみ)がリストとなって帰ってきます。これをフィード文書と呼びます。
- 取得
メンバリソースを取得するためにはメンバURIに対してGETメソッドを適用します。指定したメンバリソースの内容がエントリとなって帰ってきます。これをエントリ文書と呼びます。
- 追加
メンバリソースを追加するためにはコレクションURIに対してPOSTメソッドを適用します。このとき追加したい内容のエントリ文書を送ります。その内容で新しいメンバリソースが生成されます。
- 更新
メンバリソースを更新するためにはメンバURIに対してPUTメソッドを適用します。このとき更新したい内容のエントリ文書をつけて送ります。
- 削除
メンバリソースを削除するためにはメンバURIに対してDELETEメソッドを適用します。
メディアリソースの操作
メンバリソースの中でもXML形式のエントリで表現できないようなデータ(典型的な例は画像データ)はメディアリソースと呼ばれます(表4)。
表4 メンバリソースの種類
メンバリソースの種類 | 内容 |
エントリリソース | Atom Entryで表現されるデータ |
メディアリソース | (通常は)Atom Entryで表現できないデータ |
メディアリソースを扱う場合、リソースをエントリとして表現するために「メディアリンクエントリ」と呼ばれるエントリリソースが用意されます。
そしてこのエントリリソースからはメディアリソースへのリンクが張られます(atom:linkエントリで表現され、メディアリンクエントリ内に保持されます)。
以下にCRUD操作を紹介しますが、いずれも図中の点線でかかれているリソースがメディアリソース、実線のリソースがエントリリソース(メディアリンクエントリ)、伸びている矢印はメディアリンクエントリ内にあるatom:link要素を表現しています。
- 取得
メディアリソースをGETした場合は、エントリ文書以外のメディアタイプで実際のリソースを取得することができるでしょう。
- 追加
コレクションに対してメディアリソースをPOSTした場合は、メディアリソースおよびメンバエントリ(メディアリンクエントリ)が作成されます。メディアリンクエントリはメディアリソースのメタ情報を表現するメンバリソースとなります。
- 更新
メディアリソースを更新したい場合は、メディアリソースのURIを、メタ情報を更新したい場合は、メディアリンクエントリのURIに対してPUTを適用します。
- 削除
エントリリソース(メディアリンクエントリ)を消去した場合は、対応するメディアリソースも削除されるべきであると規定されています。このため多くのサーバではメディアリソースも同時に削除されてしまうことになるでしょう。図中の /member/1 を削除した場合は同時に /member/2 も削除されてしまうでしょう。
また、メディアリソースを削除した場合は、メディアリソースが削除されます。このとき対応するエントリリソース(メディアリンクエントリ)も多くの場合、削除されるでしょう(厳密に言えばこの場合も実装依存になっています)。
サービス文書
それではどのように、Webリソースを操作するURIを取得するのでしょうか?
それを解決してくれるのがサービス文書です。サービス文書を取得することがクライアントにとってAtomサーバの提供しているサービスを知ることができる唯一の方法です。
通常、クライアント側にはサービス文書を取得するためのURI(サービス文書URI)をなんらかの方法によって伝えます。このURIをGETすることによってクライアント側は様々なURIを知ることになります。
では実際にどのようなものかみてみましょう。
サービス文書は、ルート要素がapp:service要素である文書です。
app:service要素は一つ以上のapp:workspace要素から構成されています。
app:workspace要素には、atom:title要素が必ず一つ含まれています。またapp:collection要素が0個以上含まれています。workspaceについてはcollectionを束ねるものとしか定義されておらず、あまり意味はありません。ここではcollectionに注目していきます。
app:collection要素のhref属性は、そのコレクションのURIを表現しています。
ここに記載されているURIに対してPOSTやGETができます。
app:collection要素はapp:accept要素を持つことができます。app:accept要素は、そのコレクションがPOSTを受け付けることができるファイルタイプを示しており、RFC 2616で定義されているmedia-rangeの内容を指定できます。
この要素が省略された場合はAtomエントリ文書のみが受け付け可能と解釈されるべきであると規定されています。また、空要素(<accept></accept>)のみが現れている場合は、何も受け付けられないと解釈するべきであると規定されています。
全てのファイル形式が受け付け可能な場合は<accept>*/*</accept>という表現が利用できます。
上記の例では、My Blog Entriesコレクションに対しては、エントリ文書を登録することができます。また、Picturesというコレクションに対してはPNG形式の画像ファイルのみが登録できると解釈することができます。
さて、次回はこのサービス文書を手がかりに、リソースへのCRUD操作を追っていくことにしましょう。