JavaScript、Ajax、HTML5(API)、Ruby…Web及び関連技術の実験&情報公開&制作物紹介。

JKL.ParseXML.JSON のエラー処理について

Ajax基本ライブラリといえば prototype.jsJSANHTTP.Request クラスが有名ですが、私は Kawa.net xp で公開されている JKL.ParseXML を愛用しています。
Ajax関連のライブラリを探していて、「手軽に使えて簡単便利」なものとして見つけたのですが、以下のような特徴があります。

  • 依存ライブラリなし、単体で使用可能
  • 取得したデータをJSオブジェクトに変換してくれるので、処理が簡単(DOMの煩雑さ・手順の多さに比べれば)
  • XML以外にもJSONやCSVなどの形式の読み込みに対応

特に最後の「JSONにそのまま対応している」というのがお手軽で良いのです。
ただ、今回ある目的でいろいろ触っていて、その「JSON対応機能」で少し難があったので、作者へのフィードバックがてら、対処法とともに覚え書きとして残しておきます。
発見した問題点は、以下の2点:

  • JKL.ParseXML.JSON クラス使用時、ある条件下で、捕捉されない(捕捉できない)JavaScriptエラーが発生する
  • 親クラスの JKL.ParseXML クラスに用意されているエラーハンドリング機構が、JKL.ParseXML.JSON クラスでは有効ではない

追記:2007/01/05】この記事の記述は、JKL.ParseXML ver.0.19 のものです。
これらの問題点をクリアしたver.0.22が即日(2007/01/04付けで)公開されました。
作者のKawasaki Yusukeさま、迅速なご対応ありがとうございます(^-^)

JKL.ParseXML.JSON クラス使用時の捕捉されないエラーについて

問題が発生する条件は、以下の通りです。

  • ブラウザとしてOperaを使用時
  • async()メソッドを使用した非同期通信モード時
  • 存在しないURLを指定したとき(ステータスが404)等のHTTPエラー時

発生する「捕捉できないエラー」は、端的に表せば以下のような内容です:
eval呼び出し時の文法エラー:"()"
つまり eval("()"); というのを実行しようとしてエラーになっている、ということ。
本来"()"の括弧の中には、URLから読み込んだテキストが入ります。ただし指定されたURLが存在しないと、Operaの場合空の文字列(もしくはNULL?)になってしまうため、そのような現象が起きてしまうのです。
ではMSIEやFirefox等はどうなのかというと、非同期通信モードの場合、内部でステータス404等のHTTPエラー発生時に適切な処理が行われるらしく、返ってきたテキストをevalで処理する前に処理が中断されている模様です。
また同期通信モードでは、確かにそのエラーは出ますが、処理を実行するparse()メソッド呼び出し部分を try { ? } catch(e) {...} で囲ってやればエラーが捕捉できます。非同期だとそれもできないわけです。

回避方法

Operaで「ステータスが404の時に内部できちんと処理されない」のは気になりますが、とりあえずの回避策として、問題の発生するメソッドを再定義してしまう、という方法が採れます。
<script>タグで jkl-parsexml.js を読み込んだ後に、JavaScript で以下のように記述すればOK。

// JKL.ParseXML.JSON の parseResponse() メソッドを再定義
JKL.ParseXML.JSON.prototype.parseResponse = function () {
    var text = this.http.responseText();
    if (!text) return; // ↓ でエラーが出ないように
    var data = eval( "("+text+")" );
    return data;
}

あとは、戻り値(というより非同期モードの場合はコールバック関数の引数)が undefined だったら、内部でエラーが起きたモノとして然るべき処理を書けばOK、というワケです。

追記:2007/01/05】この問題は最新バージョン(ver.0.22以降)ではクリアされています。
よってこの対処法を実践する必要はありません。
なお、ver.0.22では、もう少し行儀良く↓のようになっていました。

JKL.ParseXML.JSON.prototype.parseResponse = function () {
    var text = this.http.responseText();
    // http://www.antimon2.atnifty.com/2007/01/jklparsexmljson.html
    if ( typeof(text) == 'undefined' ) return;
    if ( ! text.length ) return;
    var data = eval( "("+text+")" );
    return data;
}

つまり、「textが undefined の場合と、長さが0の場合にリターン」というわけです。
私の書いた回避方法だと、テキストがたまたま半角数字「0」一文字だった場合にも無効なモノとしてリターンしてしまいます。

JKL.ParseXML.JSON クラスのエラーハンドリング機構について

JKL.ParseXML クラスには、エラーハンドリング機構が用意されています。
var XXX = new JKL.ParseXML( url ); として XXX.onerror( func ); とすると、引数url で指定したURLの処理中にエラーが発生した場合に、その処理を 引数func で指定した関数に実施させることができます。

ところがこれが、JKL.ParseXML.JSON では使用できなくなっています。
JKL.ParseXML.JSON で同じことを使用とすると、実行時に以下のようなエラーが発生します:
『オブジェクトでサポートされていないプロパティまたはメソッドです。』(MSIE)
『XXX.onerror is not a function』(Firefox)
『TypeError: Type mismatch』(Opera)

回避方法

これは単純に、JKL.ParseXMLからJKL.ParseXML.JSONにonerrorメソッドが引き継がれていないだけなので、引き継いでもらう記述をどこかに(実際にonerrorメソッドを使う前に)書いておけばOK。

// JKL.ParseXML.JSON の onerror() メソッドを JKL.ParseXML からオーバーライド
JKL.ParseXML.JSON.prototype.onerror = JKL.ParseXML.prototype.onerror;

これだけで、HTTPエラー発生時の処理等、(Opera以外では)きちんとエラーハンドリング処理が行われることを確認済みです。
この場合、try?catchの使えない非同期通信モードの場合でも使えるので便利です。

追記:2007/01/05】こちらも最新バージョン(ver.0.22以降)には取り込まれています。
よってこの対処法を実践する必要はありません。

備考

jkl-parsexml.js のソースをざっと眺めてみて、今回発見した問題は、どうやら「JSONファイルは存在しているモノ」という前提で処理が書かれているのかな、という印象を受けました。あと、JSON形式として妥当かどうか等のチェックも省略されています(そのことについては、「evalしてるだけなのでサーバ上のJSONデータは信頼できる内容にしてね」という注意書きもありますけれど)。
でも、JSONが手軽なデータ受け渡しフォーマットとして注目されている(と思う)今、動的生成されることも多くなると思われますし、もうちょっと注意を払ったコーディングに改良した方が良いのでは? なんて、思ってしまいました。
それをjkl-parsexml.jsに求めるか、JSON処理専用のクラスを希望するか、もしくは自作するか、は、今後の動向次第ですけれど。

カテゴリ

月別 アーカイブ

OpenID対応しています OpenIDについて

このブログ記事について

このページは、あんちもん2が2007年1月 4日 12:16に書いたブログ記事です。

ひとつ前のブログ記事は「模様替え@2007」です。

次のブログ記事は「<blockquote>要素で横スクロールバーを出す方法」です。

最近のコンテンツはインデックスページで見られます。過去に書かれたものはアーカイブのページで見られます。