JavaScriptでAtomPubクライアント

はじめに

AtomPubを使ったサーバを作ってからこっち,クライアントはcURLを使ってました.でもそろそろ飽きたので他の手段で試そうと思ってます.それはJavaScriptJavaScriptからPUTやDELETEが使えるなんて知らなかったのですが,XMLHttpRequestを使う場合には一般的だったみたい.ってことで使い慣れたjqueryでAtomPub Clientに挑戦することにしました.とりあえずできるかどうかを確かめるためなので,GUIは無視して,firefox+firebug環境で実行しています.

GET いろいろ

まずは"http://localhost:3000/myservice"でサービスドキュメントをGETして,

<?xml vrsion="1.0" encoding="utf-8"?>
<service xmlns="http://www.w3.org/2007/app">
  <workspace>
    <atom:title xmlns:atom="http://www.w3.org/2005/Atom">MyAtom</atom:title>
    <collection href="http://localhost:3000/mycollection">
      <atom:title xmlns:atom="http://www.w3.org/2005/Atom">MyCollection</atom:title>
    </collection>
  </workspace>
</service>

その中から"workspace title"と"collection title"を取得します.まず,"workspace title"を取得するコードは,

$.ajax({
 type:    "GET",
 url:     "myservice",
 success: function(xml){console.log($($("title",$(xml))[0]).text())}
})

となり,"MyAtom"を出力します.同様に,"collection title"を取得するコードは

$.ajax({
 type:    "GET",
 url:     "myservice",
 success: function(xml){console.log($("workspace collection title",$(xml)).text())}
})

となり,"MyCollection"を出力します.次に,"collection url"を取得するコードは

$.ajax({
 type:    "GET",
 url:     "myservice",
 success: function(xml){console.log($($("workspace collection",$(xml))).attr('href'))}
})

となって,これは"http://localhost:3000/mycollection"と出力するので,登録したエントリ一覧をentriesという配列に入れるコードは以下のようになります.

var collectionUrl;
var entries = new Array();
$.ajax({
 type:    "GET",
 url:     "myservice",
 success: function(xml){
  collectionUrl = $($("workspace collection",$(xml))).attr('href')
 }
});
$.ajax({
 type:    "GET",
 url:     collectionUrl,
 success: function(xml){
  $("entry",$(xml)).each(function(){entries.push(this)})
 }
})

これでentriesという配列に取得したentryが入ってるわけですが,中身を確認する方法が見つけるのが大変でした.結局jquery pluginsからtoXMLというモジュールを見つけてインストールすることで解決しました.

jQuery.fn.toXML = function () {
    var out = '';
    if (this.length > 0) {
        if (typeof XMLSerializer == 'function' ||
            typeof XMLSerializer == 'object')
        {
            var xs = new XMLSerializer();
            this.each(function() {
                out += xs.serializeToString(this);
            });
        } else if (this[0].xml !== undefined) {
            this.each(function() {
                out += this.xml;
            });
        } else {
            // TODO: Manually serialize DOM here,
            // for browsers that support neither
            // of two methods above.
        }
    }
    return out;
};

このplugin IE(6)では動かないって書いてあるけど,気にしない!で,entriesの中身を見るのはこんなコードになります.

$.each(entries, function(){console.log($(this).toXML())})

POST

エントリを投稿するにはPOSTメソッドを使います.まずエントリのテンプレートを準備します.追記:たけまるさんのはてブでわかったんですが,このxmlで使っている名前空間が古かったので,PUTしたときにおかしくなったようです.名前空間を"http://www.w3.org/2005/Atom"に変更したらPUTが正しく動くようになりました.

xml = '<?xml version="1.0" encoding="utf-8"?>';
xml += '<entry xmlns="http://purl.org/atom/ns#">';
xml += '<title>TITLE</title>';
xml += '<content mode="xml"><div xmlns="http://www.w3.org/1999/xhtml">BODY</div></content>';
xml += '</entry>';

実際に投稿する際には,正規表現を使ってxmlを完成させることを前提としてます.つまり,

xml.replace('TITLE',title);
xml.replace('BODY',body);

こんな感じ.このxmlを投稿するコードはこうなります

$.ajax({
 beforeSend: function(xhr){xhr.setRequestHeader("Content-Type", "application/atom+xml")},
 type: "POST",
 url: "mycollection",
 data: xml,
 success: function(msg){console.log($(msg).toXML())}
})

これを実行すると,

<?xml version="1.0" encoding="UTF-8"?>
<entry xmlns="http://purl.org/atom/ns#">
 <title>TITLE</title>
 <content mode="xml">
  <div xmlns="http://www.w3.org/1999/xhtml">BODY</div>
 </content>
 <app:edited xmlns:app="http://www.w3.org/2007/app">2008-02-22T18:19:37+09:00</app:edited>
 <modified>2008-02-22T18:19:37+09:00</modified>
 <id>http://localhost:3000/mycollection/20080222-181937-514451.atom</id>
 <link xmlns="http://www.w3.org/2005/Atom"
  rel="edit" href="http://localhost:3000/mycollection/20080222-181937-514451.atom"/>
</entry>

と表示するので,正しく投稿できたことがわかります.

PUT

エントリを編集するにはPUTメソッドを使います.GETの項で書いた,登録したエントリ一覧をentriesという配列に入れるコードを使うと,今投稿したエントリはentries[0]にあるので,エントリ編集用のurlを取得するコードは

console.log($("link[@rel=edit]", $(entries[0])).attr('href'))

となって,この場合"http://localhost:3000/mycollection/20080222-181937-514451.atom"が返って来ます.一々"entries[0]"と書くのもメンドクサイので"newxml"という名前に変えて,ついでにタイトルを"New Title"に変更すると

newxml = entries[0];
$("title",$(newxml)).text("New Title");
console.log($(newxml).toXML())

タイトルだけ変わったxmlが出来上がります.これをさっき取り出したエントリ編集用のurlにPUTすると

$.ajax({
 beforeSend: function(xhr){xhr.setRequestHeader("Content-Type", "application/atom+xml")},
 type: "PUT",
 url: "mycollection/20080222-181937-514451.atom",
 data: $(newxml).toXML(),
 success: function(msg){console.log($(msg).toXML())}
})

こんなxmlが返ってきます

<?xml version="1.0" encoding="UTF-8"?>
<entry xmlns="http://purl.org/atom/ns#">
 <title>New Title</title>
 <content mode="xml">
  <div xmlns="http://www.w3.org/1999/xhtml">BODY</div>
 </content>
 <modified>2008-02-22T18:19:37+09:00</modified>
 <link xmlns="http://www.w3.org/2005/Atom"
  rel="edit" href="http://localhost:3000/mycollection/20080222-181937-514451.atom"/>
 <app:edited xmlns:app="http://www.w3.org/2007/app">2008-02-22T19:10:50+09:00</app:edited>
 <id>http://localhost:3000/mycollection/20080222-181937-514451.atom</id>
 <link xmlns="http://www.w3.org/2005/Atom"
  rel="edit" href="http://localhost:3000/mycollection/20080222-181937-514451.atom"/>
</entry>

あ,あれ?編集用のurlを示してるlinkタグが二つある!ここまで書いてて初めて気がつきました.やっぱりPUTで送るxmlがおかしいのかなぁ.これは引き続き調べます.

DELETE

エントリを削除するメソッドはDELETEです.コードはこんな感じになります.

$.ajax({
 type:    "DELETE",
 url:     "mycollection/20080222-181937-514451.atom",
 success: function(msg){console.log(msg)}
})

終わりに

うう,できたと思ったのに.PUTがおかしいことを日記を書いてる最中に発見するとは….がっくし

追記

上でも書きましたが,今回の失敗はエントリをcreateした時のxmlで使っている名前空間が古かったために起こりました.名前空間を新しくしたテンプレートは以下のようになります.

xml = '<?xml version="1.0" encoding="utf-8"?>';
xml += '<entry xmlns="http://www.w3.org/2005/Atom">';
xml += '<title>TITLE</title>';
xml += '<content mode="xml"><div xmlns="http://www.w3.org/1999/xhtml">BODY</div></content>';
xml += '</entry>';

そして,このテンプレートを元にして,日記に書いた通りの処理を行ってPUTした結果は以下のようになりました.

<?xml version="1.0" encoding="UTF-8"?>
<entry xmlns="http://www.w3.org/2005/Atom">
 <title>New Title</title>
 <content mode="xml">
  <div xmlns="http://www.w3.org/1999/xhtml">BODY</div>
 </content>
 <updated>2008-02-23T18:58:44+09:00</updated>
 <app:edited xmlns:app="http://www.w3.org/2007/app">2008-02-23T19:02:19+09:00</app:edited>
 <id>http://localhost:3000/mycollection/20080223-185844-228104.atom</id>
 <link rel="edit" href="http://localhost:3000/mycollection/20080223-185844-228104.atom"/>
</entry>

前のだとmodifiedタグがついてたけど,今度はupdatedタグがついてます.