HTMLWalkerは、簡単シンプルなJavaScriptのコンストラクタ関数で、JavaScriptによるDOMスクリプティングを補助します。インスタンスのwalkメソッドは、指定したノードから出発して文書順にノードを辿り、その都度nodeNameアトリビュートに基づいてハンドラを呼び出します。
雰囲気としてはDOM Level 2のNodeIteratorインターフェイスに似ていますが、それより低機能かつシンプルなもので、DOM Level 1 HTMLの実装だけを要求します:
メリットはありません。ただ、場合によってはコードが読みやすくなります。また、人によってはメンテナンスがしやすくなるかもしれません。定義するハンドラによっては、稀に、getElementsByTagNameメソッドを多用する通常のDOMスクリプティングよりも実行が高速になります。
洒落で書いたのですが、いつの間にか手放せなくなっていることに気づいて公開しようと考えました。
試しに一対のDT, DD要素を含んだDL要素をトラバースしてみます。こんなHTML断片:
<dl id="TEST_DL"><dt>被定義語句</dt><dd>定義だらだら</dd></dl>
で、「被定義語句:定義だらだら」のような文字列を得ましょう。まずハンドラを書きます。
function DLHandler(){
this.result = [];
this["DT"] = function(dt){
};
this["DD"] = function(dd){
this.result.push(":");
};
this["#text"] = function(node){
this.result.push(node.data);
};
}
配列を用意しまして、テキストノードを検知したらそのdataを配列に追加し、DD要素を検知したら「:」を追加しようってわけです。というわけでつまり、HTMLWalkerインスタンスがDD要素に到達すると、DLHandlerインスタンスをdhとすれば、そのDD要素を引数として渡された関数dh["DD"]が呼び出されるというわけです。dh["DD"]が未定義だった場合、dh["*"]が呼び出されます。でもこれも定義されていませんから、このままでは未定義値をcallしてしまいTypeErrorです。そこで、そのような関数を定義済みのハンドラ、HTMLWalker.DefaultHandlerに、プロトタイプチェインしてしまいます。その為のクラスメソッドを用意してあります。
HTMLWalker.normalizeHandler(DLHandler);
これでOKです。
またはJavaScript1.5なエンジンを利用するのであれば:
DLHandler.prototype.__proto__ = HTMLWalker.DefaultHandler.prototype;
こうした方が断然スマートってもんです。
ハンドラを書いたところで、HTMLWalkerを作成し、walkメソッドでトラバースを開始します。
var handler = new DLHandler;
var walker = new HTMLWalker(handler, document.getElementById("TEST_DL"));
walker.walk();
これで、目的の文字列は参照可能になっています。
都合の良い例を挙げてしまえば、HTMLを含め、どれだけコードが見通しの良いものになるかお見せしましょう。詳細はまた今度。