htsign's blog

ノンジャンルで書くつもりだけど技術系が多いんじゃないかと思います

IEの開発者コンソールで見るテキストノードについて

IEの開発者コンソールで

var textNodeIterator = document.createNodeIterator(
    document,
    NodeFilter.SHOW_TEXT,
    function(node){
        return /^\s*$/.test(node.textContent)
        ? NodeFilter.FILTER_ACCEPT
        : NodeFilter.FILTER_SKIP;
    },
    false);
textNodeIterator.nextNode();

ってやるとコンソールにEmptyTextNodeって表示される。
あー空のテキストノードに特別に名前つけてんだーって思いました。っていうそれだけのお話。

それだけだと寂しいので少しだけ解説。

Document#createNodeIteratorNodeIteratorっつーオブジェクトが作られる。
これはDOM Level 2で定義されたインターフェースで、ドキュメント全体から条件に一致したDOMノードを自由に取ってこれる便利なアレ。

イテレータなので、nextNode()previousNode()で内部のポインタが動き、逐一ポインタが指すノードを返す。
ポインタが終端・または始端にある状態でそれぞれnextNode()previousNode()を実行するとnullを返す。
このインターフェースには現在のポインタに位置するノードを返すメソッド・プロパティはないので、

var currentNode;
currentNode = textNodeIterator.nextNode();

などとしないと値を保持できない。

ちなみにNodeIteratorには上記2つ以外にdetach()を加えた3つしかメソッドが存在しない。

以下、引数について書く。

第一引数がルートノード。
ここに指定したノード、およびその子孫から条件に一致したものを抜き取る。

第二引数がどの属性のノードを持ってくるか。
ここでまた新しくNodeFilterインターフェースが出てきたけど、ここにNodeIteratorTreeWalker*1で使われる定数が保持されてる。
今回はテキストノードのみが欲しかったのでNodeFilter.SHOW_TEXTとした。

第三引数には、第一引数と第二引数の条件にマッチしたノードを引数としたコールバック関数を置く。*2
この関数の戻り値としてNodeFilter.FILTER_ACCEPTを受け取るとそのノードはパスされ、逆にNodeFilter.FILTER_SKIPを受け取るとそのノードは弾かれる。
他にNodeFilter.FILTER_REJECTというのもあるが、これはNodeIteratorを使っている場合、NodeFilter.FILTER_SKIPと同じ意味を持つ。
違いが出てくるのはTreeWalkerの場合だけど、ここでは割愛。

ちなみに、フィルタリングなんか必要ねぇよっていう場合は、第三引数はnullでいいです。

第四引数は、エンティティ参照を文字列で置き換えるかの真偽値。だと思う。
trueにすると、例えば「♠」が「♠」に置き換えられる。たぶん。
実は試したことない。
勝手に置き換わると後々面倒だし、無難にfalseにしとくのがいいと思う。

正規表現部分については今更説明必要ないと思うけど、一応。
/^\s*$/の意味するところは、最初から最後まで半角スペースやタブ文字、改行コードのみになっていればマッチ。
プラスではなくアスタリスクなので0回以上の出現、つまり空文字の場合もマッチする。


これらを総合して、冒頭のコードの意味を見ると、
ドキュメント全体から、半角スペース・タブ文字・改行文字のみで構成された文字列、あるいは空文字のテキストノードをイテレータとして抽出し、イテレータの最初の1つを取り出した。
と言った感じ。

以上。
少しだけ解説のつもりが、記事の大半が解説になってしまった。

*1:NodeIteratorが平面的に列挙するのに対して、TreeWalkerは木構造をそのまま持ってくる。より自由に階層を潜ることが出来るが、メソッドも多くて複雑。

*2:"acceptNode"をキーとしたハッシュにして置いてもいい