FIREFOX HACKS' (3)
昨日、医者へ行って、背中に出来た「こぶ」を取ってもらってきた。正確には、「ふんりゅう」とか言うそうな。昔からこぶはあって、ご丁寧にも、ふたこぶ だったのだ。数年前に、一つ取ってもらい、ひとこぶ になっていたけど、今回は残りのやつも取ってもらった。
術後の痛さよりも、当日はアルコール禁止の方が痛かったのは、秘密だ。でも、今日から解禁、よかったね >俺
不満が残るぞ、SQL
前回は、gaucheを使って、sqlite3のDBを暴いた。結果、分かった事は、テーブルが多過ぎて、収集がつかない事。更に、INTEGER と言う、DB上のポインターの多さよ。
リレーショナルDBは、マシン独立に設計され、ポインターとは無縁の世界です、なんて言われているけど、結局、INTEGERに置き換えただけじゃん。どうせなら、INTEGERなんて言う、チンケなものややめて、有理数(実数)に置き換えたらどうだい。面倒な事が無くなるよ、と、Web+DB の、「SQLアタマ アカデミー」に書かれていた。なんでも、カントール集合とか言うそうな。
と、言う事で、SQLはきっぱりと諦めます。そもそも、FIREFOX HACKS(大げさな!)を始めた目的は、いろいろなマシンで使っている、FIREFOX の Bookmarkをマージしたかったからだ。
ある時は、Windowsで、ある時はLinuxでと、気分のままにFirefoxを使っていて、Bookmarkを更新していくと、あれ、あのURL どこに残していたかなあ となってしまい、はなはだ不便だからだ。きっと、こういう不満を解消するアプリは出ているだろうけど、前回の、事件(設定ファイル削除)を機に、調べてみる気になったのでした。
じゃーー、どうする? ブックマークの管理メニューを見たら、どうやら JSON形式でも BackUP出来るみたいだ。そんじゃ、やってみんべ。
JSON って、何ものよ?
女房に聞いたら、ジェイソンって、聞き返されちゃいました。ええ、13日の金曜日に出てくる、恐い人ですね。どうやら、聞く人を間違えた。世界の百科辞典で調べてみます。
JavaScript Object Notation、俺的には、いやだなぁ。
JSONは単純であるので、特にAjaxの分野で利用が広がりつつある。 JavaScriptでJSONをパースして読み込むには、文字列をJavaScriptのコードとして 解釈させるeval()関数を作用させるだけでよい
eval()ですか! こりゃ、ちゃんとしないと恐いわな。
恐いもの見たさにJSONの紹介なんて所まで行ってみました。なるほどねぇ。RFC 4627 になって、世界を席圏中ですか。
JSONデータを読んでみるぞ
さて、そんじゃ、FIREFOXから取り出した、jsonデータを読んでみるか。gaucheを使いたい所だけど、まだ、rfc.4627は準備中との事で(HEADには、あると、風の噂です)すので、素直に ruby で、行きます。
生憎と、JSONのモジュールは提供されていない。lib/rubyの下にある、yaml.rb でも、代用出来るそうだけど、折角なので、正しい道を歩む事にします。
Ruby用 Jsonパーサーを頂いてきました。だって、gemは嫌いだもん。 仰せにしたがって、
require "./simple-json" str = File.read('Bookmarks_2009-06-08.json') parser = JsonParser.new res = parser.parse(str, {:validation => false })
早速、実行してみると
[sakae@fb ~/json]$ ruby simple.rb ./simple-json.rb:169:in `parse_value': [JsonParser] Syntax error (RuntimeError) from ./simple-json.rb:203:in `parse_array' from ./simple-json.rb:178:in `parse_value' from ./simple-json.rb:189:in `parse_hash' from ./simple-json.rb:83:in `parse' from simple.rb:4
ありゃりゃ、エラーですよ! 何故? rubyが、1.8.7 だから? そんじゃ、ruby のHeadにしたるわい。(久しぶりに、ruby-1.9.xxをコンパイル)
[sakae@fb ~/json]$ /home/sakae/mine/bin/ruby -v ruby 1.9.2dev (2009-06-07 trunk 23644) [i386-freebsd6.4] [sakae@fb ~/json]$ /home/sakae/mine/bin/ruby simple.rb /home/sakae/json/simple-json.rb:169:in `parse_value': [JsonParser] Syntax error (RuntimeError) from /home/sakae/json/simple-json.rb:203:in `parse_array' from /home/sakae/json/simple-json.rb:178:in `parse_value' from /home/sakae/json/simple-json.rb:189:in `parse_hash' from /home/sakae/json/simple-json.rb:83:in `parse' from simple.rb:4:in `<main>'
やはり、同じか。しゃーない、gem版のjsonも入れてみるか。
[sakae@fb ~/json]$ PATH=/home/sakae/mine/bin:$PATH [sakae@fb ~/json]$ gem list --local *** LOCAL GEMS *** json (1.1.6) .....
#!/home/sakae/mine/bin/ruby require "json" str = File.read('Bookmarks_2009-06-08.json') res = JSON.parse(str) [sakae@fb ~/json]$ ./test.rb /home/sakae/mine/lib/ruby/gems/1.9.1/gems/json-1.1.6/lib/json/common.rb:122:in `parse': 349: unexpected token at ']}' (JSON::ParserError) from /home/sakae/mine/lib/ruby/gems/1.9.1/gems/json-1.1.6/lib/json/common.rb:122:in `parse' from ./test.rb:4:in `<main>'
Uum ... 一歩前進。食わせたデータが間違っていると。。今、使った、Bookmarks_2009-06-08.json は、FreeBSD上の Firefox から、吐き出したやつだ。FreeBSD特有な問題でも 抱えているのだろうか? > Firefox君
ならば、Windows上の Firefox から、jsonを採取。実験してみるよ。# => 同様にParseError が、発生。
見たくないけど、しやーない、見るか!
{"title":"","id":1, ..... "charset":"EUC-JP"}]},]}
改行が1つも入っていない、一本糞 みたいなファイルです。Windows上のemacsに食わせたら、硬直を起こし、反応しなくなりました。(笑)
最初と最後だけを載せましたが、バランスが崩れていますねぇ。どちらに合わせるのが良いのでしょうか? 取り敢えず、最後の部分を5文字削ってみます。
..... jp/~takumi/","charset":"EUC-JP"} (JSON::ParserError) ' from /home/sakae/mine/lib/ruby/gems/1.9.1/gems/json-1.1.6/lib/json/common.rb:122:in `parse' from ./test.rb:4:in `<main>'
今度は、データの最後の部分で、エラーになってしまいました。 viで、開いて % を使いながら、括弧のバランスを取ってみましたが、エラーを根治できませんでした。残念!
Firefoxでは、ちゃんと扱えるの?
外部に取り出して、検定するとエラーになる JSON ファイルだけれど、Firefoxではちゃんと扱えるの? やってみたら、エラーを出す事なく、ちゃんと読めちゃったよ。その結果は、正しく Bookmarkに反映されてた。
やっぱり、ジェイソン! 外から覗くのはご法度なのね。触らぬ神に祟りなし。 なお、json形式でバックアップしたのを戻すと、favicon が消えてしまいます。faviconまで、正しく戻したい場合、bookmarks.html で、輸出入しましょう。
結論みたいな事を書いてしまったけど、改めてFirefoxのメニューを見たら、toolの所で、javascriptの実験が出来るのね。知らなかった。eval("/home/sakae/json/bookmarks.json")と、無謀な事をしたら、正規表現と誤認しやがるの。しゃーない、ファイルから一度読み込んでと思って、それらしいのを探してみたら、危険防止の為、そういう関数(read)は、提供されてないのね。当たり前の事よ! この当たり前を、堂々と破ってくれているのが、M$です。便利なのは良い事だで、相変わらず節操が無いなあ。
ふと思って、firefoxに、壊れた(壊した)jsonファイルを与えてみたら、ちゃんとエラーになってくれるのだろうか? 乗りかけた舟なので、やってみた。 結果は、受取を拒否されました。拒否の言い訳を頼りに firefoxのソースを検索してみます。
[sakae@fb ~/mozilla]$ find . -type f | xargs grep 'Unable to process the backup file.' ..... ./browser/locales/en-US/chrome/browser/places/places.properties:bookmarksRestoreParseError=Unable to process the backup file.
こやつは、メッセージの定義ファイルでしたよ。再び、検索の旅へと出かけます。
[sakae@fb ~/mozilla]$ find . -type f | xargs grep bookmarksRestoreParseError ./browser/components/places/content/places.js: this._showErrorAlert(PlacesUIUtils.getString("bookmarksRestoreParseError"));
places.js って事は、javascript なんだ。へぇー、firefox内部でも使っているのね、と改めて驚いてみる。(漫才で、ここ笑う所ですよ、と言うのと一緒)
try { PlacesUtils.restoreBookmarksFromJSONFile(aFile, [PlacesUIUtils.leftPaneFolderId]); } catch(ex) { this._showErrorAlert(PlacesUIUtils.getString("bookmarksRestoreParseError")); }
今度は、restoreBookmarksFromJSONFile を探して見てみます。 /home/sakae/mozilla/toolkit/components/places/src/utils.js に、有りました。相変わらず js だなあ。どうやって、ファイルから読むんだよう?
/** * Restores bookmarks/tags from a JSON file. * WARNING: This method *removes* any bookmarks in the collection before * restoring from the file. * * @param aFile * nsIFile of bookmarks in JSON format to be restored. * @param aExcludeItems * Array of root item ids (ie: children of the places root) * to not delete when restoring. */ restoreBookmarksFromJSONFile: function PU_restoreBookmarksFromJSONFile(aFile, aExcludeItems) { // open file stream var stream = Cc["@mozilla.org/network/file-input-stream;1"]. createInstance(Ci.nsIFileInputStream); stream.init(aFile, 0x01, 0, 0); var converted = Cc["@mozilla.org/intl/converter-input-stream;1"]. createInstance(Ci.nsIConverterInputStream); converted.init(stream, "UTF-8", 1024, Ci.nsIConverterInputStream.DEFAULT_REPLACEMENT_CHARACTER); // read in contents var str = {}; var jsonStr = ""; while (converted.readString(4096, str) != 0) jsonStr += str.value; converted.close(); if (jsonStr.length == 0) return; // empty file this.restoreBookmarksFromJSONString(jsonStr, true, aExcludeItems); },
雰囲気からすると、指定されたファイルを streamにmapして、UTF-8変換を掛けながら 文字列として読み込んでいる。読んだ文字列を引数にして、restoreしてるんだ。 以下、このファイルを解析すれば、DBとのやり取りも判明します。javascriptをちょいと勉強して、1600行ぐらいあるファイルを真面目に読んでみようかな。