JavaScriptでAtomPubクライアント
はじめに
AtomPubを使ったサーバを作ってからこっち,クライアントはcURLを使ってました.でもそろそろ飽きたので他の手段で試そうと思ってます.それはJavaScript.JavaScriptから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タグがついてます.