このドキュメントは以下で説明するW3C文書の翻訳です。
この翻訳はW3Cの正式な仕様ではありえません。
翻訳者は翻訳の正確さを保証するものではありません
仕様の原文 / 著作権表記
Translation Copyright © 2001/01/26 Ginga

13 November, 2000

1. ドキュメントオブジェクトモデル トラバース

編集者
Joe Kesselman, IBM
Jonathan Robie, Software AG
Mike Champion, Software AG

目次

1.1. 概要

この章はDOM レベル 2のTraversal オプション機能について説明する。 このTreeWalkerNodeIteratorNodeFilter のインターフェースは使いやすく頑丈なドキュメント内容の選択的なトラバース(横断解析)を提供する。

このセクションで見られるインターフェースは必須ではない。 DOMアプリケーションはDOMImplementationインターフェースのhasFeature(feature, version) メソッドを、パラメータ値"Traversal" および "2.0"に(それぞれ)指定して、このモジュールが実装によってサポートされているかどうかを決定することができる。 このモジュールを完全にサポートするためには、実装は DOM レベル 2 コア 仕様 [DOM Level 2 Core]で定義されている"Core"機能もサポートしなければならない。 適合性 に関する追加情報を、DOM レベル 2 コア 仕様 [DOM Level 2 Core]から参照して頂きたい。

NodeIteratorTreeWalker は、ドキュメントサブツリーのノードおよびそれらの存在する位置を表すための、2つの異なる方法である。 NodeIterator はサブツリーのフラットなビューを、ドキュメント順序に表れる、ノードの順序付きシーケンスとして提供する。このビューが階層構造を考慮せずに表現されるため、反復子が前後に移動するメソッドをもつが、上下に移動するものをもたないためである。 逆に、TreeWalker はサブツリーにおける階層構造関係を維持し、この階層構造におけるナビゲーションを可能にする。 一般的に、TreeWalker は選択されたノード周りのドキュメント構造を操作する仕事には向いており、 NodeIterator は選択されたノードのそれぞれの内容に焦点を当てた仕事に向いている。

NodeIteratorTreeWalkers はそれぞれ、ドキュメントサブツリーのビューを、そのサブツリー中で発見される全てのノードは含まない形で表現する。 この仕様では、これを論理ビュー と表現し、そのままのドキュメントサブツリーに該当する物理ビュー とは区別する。 反復子またはTreeWalker が生成されたとき、それは ノードフィルタと関連付けられていても良い。これはそれぞれのノードについて検証し、それが論理ビューの中で出現しても良いかどうかを決定する。さらに、どのノードタイプが論理ビューの中で発生して良いかを指定するフラグも用いられうる。

NodeIteratorTreeWalker は動的である - 論理ビューはもとのドキュメントに加えられた変更を反映する。 ただし、これらは、それらの変更にどう反応するかという点で異なるものになる。 ノードをシーケンシャルに表現するNodeIterator, は、そのシーケンスの内容が変化したときに、そのシーケンスにおける相対位置を維持するよう試みる。 ノードをフィルタされたツリーとして表現するTreeWalkerでは、 カレントノードからの相対位置を維持し、もしそれが新しいコンテキストに移動した時は、ノードをそれに繋げたままにする。以下で、それらの動作をもっと深く論じる。

1.1.1. NodeIterator

NodeIterator はノードのリストのメンバーがシーケンシャルに返されることを可能にする。 現在のDOMインターフェースでは、このリストは常にドキュメント順序で出現するサブツリーのノードからなる。 最初に反復子が生成された時にそのnextNode()メソッドを呼び出すと、そのサブツリーの論理ビューにおける最初のノードを返す。多くの場合、それはサブツリーのルートである。 それぞれの呼び出しで成功したものはNodeIteratorをリスト中で先に進め、論理ビューの中で次に有効なノードを返す。 それ以上ノードが見つからない場合は、nextNode()nullを返す。

NodeIteratorDocumentTraversalインターフェースにあるcreateNodeIterator メソッドを用いて生成される。 NodeIterator が生成される時、ツリーのトラバース中にどのノードタイプが「見え」てどのノードが「見えない」かを決定するフラグが用いられうる。これらのフラグはOR演算子を用いて結合されうる。 「見えない」ノードは、まるで存在しなかったかのように、その反復子からは飛ばされる。

以下のコードは反復子を生成してから、それぞれのエレメント名を出力する関数を呼び出す:

    NodeIterator iter=
     ((DocumentTraversal)document).createNodeIterator(
          root, NodeFilter.SHOW_ELEMENT, null);

    while (Node n = iter.nextNode())
        printMe(n);
     

1.1.1.1. 前後の移動

NodeIterator はノードを順序付きリストで表し、そのリスト内で前後に移動する。 その反復子の位置は常に2つのノード、最初のノードの直前(before the first node)と、最後のノードの直後(after the last node)の間にある。 反復子がはじめに生成されると、その位置は最初のアイテムの直前にセットされる。次の図は、あるサブツリー上で反復子がアスタリスク'*'で示した位置にあることを表すリストの状態表示である:

 * A B C D E F G H I

nextNode() の呼び出しはそれぞれ次のノードを返し、位置を先に進める。 たとえば、もし上記の位置から始めた場合、最初の nextNode() の呼び出しは"A"を返し、反復子を先に進める:

 [A] * B C D E F G H I

NodeIterator の位置は、最後に返されたノード、我々が参照ノード と呼ぶノードに関係して説明できるのが最良である。 反復子が生成されたときは、最初のノードが参照ノードであり、反復子は参照ノードの直前にある。これらの図では、角括弧を用いて参照ノードを示している。

previousNode() の呼び出しは、直前のノードを返し、その位置を前に戻す。 たとえば、 NodeIterator を"A" と"B" の間から始めたとしたら、これは"A"を返し、位置を以下のように移動する:

 * [A] B C D E F G H I

nextNode() がリストの最後で呼び出された場合、あるいは previousNode() がリストの最初で呼び出された場合、これはnull を返し、その反復子の位置は変更しない。 NodeIterator がまず生成されたとき、参照ノードは最初のノードとなる:

 * [A] B C D E F G H I

1.1.1.2. 維持性(Robustness)

NodeIterator は、それがナビゲートするデータ構造の変更を考慮して動作しなければならないため、それらを編集している間はアクティブであってよい。 そのデータ構造に対する追加および削除は、NodeIteratorを無効にしない。実際、NodeIterator はそのdetach() メソッドが呼び出されない限りは無効とならない。 これを可能にするためには、反復子はその位置を維持するために参照ノードを用いる。 この反復子の状態は、反復子が参照ノードの前後に位置するかどうかにも依存する。

反復子の指定されたリスト(iterated list)に対する変更が参照ノードを削除しない場合は、それらはNodeIteratorの状態に影響しない。 たとえば、反復子の近辺に新しいノードが追加された場合や、参照ノード以外のノードが削除された場合、反復子の状態は影響しない。 たとえば、次の位置から:

A B C [D] * E F G H I

ここから"E"を削除してみよう。その結果の状態は:

A B C [D] * F G H I

新しいノードが追加された場合、NodeIterator は参照ノードと隣接したままになる。もしノードが"D"と"F"の間に追加された場合、それは反復子と"F"の間に出現する:

A B C [D] * X F G H I

ノードの移動は削除とそれに続く追加に等しい。もし"I"を"X"の直前の位置に移動する場合、その結果は:

A B C [D] * I X F G H

もし参照ノードが反復子で指定されたリストから削除される場合、別のノードが参照ノードとして選ばれる。 もし参照ノードの位置がNodeIteratorの前であれば、通常の場合はnextNode() が呼ばれた後であるが、 その反復子より前で最も近いノードが新しい参照ノードとして選ばれる。 たとえば次の状態から"D"ノードを削除する場合:

A B C [D] * F G H I

"C" ノードがNodeIterator の前で最も近いノードなので、新しい参照ノードとなる:

A B [C] * F G H I

もし参照ノードがNodeIteratorの後であれば、通常の場合はpreviousNode() が呼び出された後であるが、その反復子より後で最も近いノードが新しい参照ノードとして選ばれる。 たとえば次の状態から"E"を削除する場合:

A B C D * [E] F G H I

"F" ノードがNodeIterator の後で最も近いノードなので、新しい参照ノードとなる:

A B C D * [F] G H I

前述の通り、ノードの移動は削除とそれに続く追加に等しい。 たとえば次の状態から"D"をリストの最後に移動したい場合:

A B C [D] * F G H I C (Cは不要?)

結果となる状態は次の通り:

A B [C] * F G H I D

参照ノードがリストの最後にあってそれが削除されたときはスペシャルケースである。 たとえば次の状態からノード"C"を削除すると:

A B * [C]

与えられたルールによると、新しい参照ノードはNodeIteratorより後にある最も近いノードでなければならないが、"C"より後にはそれ以上ノードが存在しない。 同様の状況がpreviousNode() がリスト中から最初のノードを返し、その後それが削除される場合にも発生する。 よって: 参照ノードの原点の方向にノードが存在しない場合、反対側で最も近いノードが参照ノードとして選ばれる:

A [B] *

もしNodeIterator が削除されたブロックの間に位置していた場合、上記のルールが明示的にその取るべき結果を表している。 たとえば、"C" が"D", "E", "F"のであるとして、次の状態から"C"を削除した場合:

A B C [D] * E F G H I D (最後のDは?重複?)

その結果の状態は:

A [B] * G H I D

最後に、NodeIteratorroot ノードをそのparent から削除しても、 反復子を指定されたリストを変更するものではなく、反復子の状態を変更するものでもないことに注意。

1.1.1.3. ノードの可視性

反復子を指定されるデータ構造は論理ビューの一部とならないノードを含んでも良く、従ってそれらはNodeIteratorから返されることはない。 whatToShowフラグの値によって排除されるノードについては、 nextNode() は排除された「不可視」ノードをスキップして、次の可視ノードを返す もし NodeFilter が存在するなら、それはノードを返す前に適用される; もしそのフィルタがノードを受容しない場合、この処理はあるノードがそのフィルタに受容され返されるまで繰り返される。 もし可視ノードに遭遇しなかった場合はnull が返され、反復子はリストの最後に位置される。 この場合、参照ノードは、可視であるかそうでないかは関係なくリスト中の最後のノードとなる。 同様のアプローチが、反対側のpreviousNode()についても採られる。

以下の例では、データ構造中にあるが論理ビューにはないノードを小文字で表す。 たとえば次のようなリストを考えよう:

A [B] * c d E F G

nextNode() の呼び出しはEを返し、次の場所に進める:

A B c d [E] * F G

しかしながら、参照ノードが削除されても、不可視のノードは参照ノードとして用いられることがありうる。 たとえば上記の状態からノード"E"が削除されても、その結果の状態は:

A B c [d] * F G

たとえば新しい可視ノード"X"が"d"の前に追加された場合、結果の状態は:

A B c X [d] * F G

previousNode() の呼び出しは、この場合ノードXを返すということに注意。 重要なのは、参照ノードが削除されたときに、不可視ノードがスキップされないということにある。 というのは、上記のようなケースでは、間違った結果が返されうるのである。"E"が削除されたとき、もし新しい参照ノードが"d"ではなく"B"にされていたら、previousNode() の呼び出しは"X"を返さない。

1.1.2. ノードフィルタ

ノードフィルタ は、ユーザーが「フィルタされた」ノードのオブジェクトを生成することを可能にする。 各フィルタには、ノードを探してそれがドキュメントのトラバースの論理ビューの一部として出現してよいかどうかを決定するような、ユーザー定義の関数が含まれる。 NodeFilterを使うためには、 そのフィルタを使うようなNodeIterator あるいはTreeWalker を生成しなければならない。 トラバースエンジンはフィルタをそれぞれのノードに適用し、もしフィルタがそのノードを受容しない場合は、トラバースは、そのノードがドキュメント中に存在しなかったかのようにスキップする。 ノードフィルタ では、処理されたノードを含む構造がどのようにナビゲートされたかを知る必要はない。

フィルタはトラバース操作が実行されたとき、あるいは NodeIterator の参照ノードが、反復子を指定された、新しいものを選ばなければならないようなサブツリーから削除されたときに設計される。 しかし、これらのフィルタの呼び出しの正確なタイミングはDOMインプリメンテーションによって異なりうる。 そのため、ノードフィルタ では、過去の呼び出しの履歴に基づく状態を維持しようとすべきではない。 その結果の動作には互換性がないであろう。

同様に、TreeWalkerNodeIterator は過去のフィルタリングの結果のためのメモリなど持たないように動作するべきであり、 将来の結果の予測もすべきではない。 もし NodeFilter が検証したある状態が、そのトラバースロジックがこのノードを検証した最後の状態から変化した(たとえばそれが検証する属性が追加あるいは削除された)場合、 この可視状態の変化は次のトラバース命令が実行された時にのみ発覚する。 たとえば: もしカレントノードに対するフィルタリングが FILTER_SHOW から FILTER_SKIPに変わった場合、 TreeWalker はそのノードをどの方向からのナビゲートも遮断することができるが、そのフィルタリング状態がもう一度変化しない限りこれは反映されない。 トラバース中に変化するノードフィルタ を書くこともできるが、その動作は混乱しやすいものであり、可能なら回避されるべきものである。

1.1.2.1. ノードフィルタの使用

ノードフィルタ は、NodeIterator あるいはTreeWalkerノード をフィルタに渡し、それが論理ビュー中に出現するかどうかを問い合わせるための、acceptNode()という名前のメソッドをもつ。 acceptNode()関数は、そのノード がどのように扱われるかを表す3つの値のうちの1つを返す。 acceptNode()FILTER_ACCEPTを返す場合、そのノード は論理ビュー中に出現する。FILTER_SKIPを返す場合、そのノード は論理ビュー中には出現しないが、そのNode の子は出現してもよい。FILTER_REJECTを返す場合、そのノード もその子孫 も論理ビュー中には出現しない。 反復子がノードを順序付きリストとして階層構造なしに表すため、FILTER_REJECTFILTER_SKIPNodeIteratorsにとっては同義語となり、単一のカレントノードのみをスキップする。

HTMLドキュメント中で名前付けされたアンカーを受容するようなフィルタを考えよう。 HTMLでは、HREFが、どんなNAME 属性をもつ A エレメントをも参照することができる。 これはJavaで書かれた、ノードを探して名前付けされたアンカーであるかどうかを決定するノードフィルタである:

    class NamedAnchorFilter implements NodeFilter
    {
     short acceptNode(Node n) {
      if (n.getNodeType()==Node.ELEMENT_NODE) {
       Element e = (Element)n;
       if (! e.getNodeName().equals("A"))
        return FILTER_SKIP;
      if (e.getAttributeNode("NAME") != null)
        return FILTER_ACCEPT;
       }
        return FILTER_SKIP;
      }
    }

もし上記のノードフィルタNodeIterator にのみ使用されるのであれば、FILTER_REJECTFILTER_SKIP が使われている場所のどこに使ってもよく、その動作は変わらない。しかしTreeWalker, については、FILTER_REJECT は全ての名前付きアンカーでないエレメントの子を拒絶することになり、また名前付きアンカーは常に他のエレメントに含まれるものであるため、名前付きアンカーは見つからないということになる。 FILTER_SKIP はそのノードを拒絶するが、その子については検証を続ける。従って、上記のフィルタは NodeIterator であってもツリーであっても作用する。

このフィルタを使用するためには、ユーザーはNodeFilter のインスタンスを生成し、それを使用するNodeIterator を生成する:

NamedAnchorFilter myFilter = new NamedAnchorFilter(); 
NodeIterator iter=
     ((DocumentTraversal)document).createNodeIterator(
          node, NodeFilter.SHOW_ELEMENT, myFilter);
   

ちなみに、我々のサンプルではノードフィルタnodeTypeをテストしているので、SHOW_ELEMENT フラグの使用はこの例では厳密に言えば必要ではない。 しかし、トラバースのインターフェースの実装には、ドキュメント構造を知っていることの利用してwhatToShow の実行を改善し、SHOW_ELEMENT の利用を価値のあるものにしているものがあるかもしれない。 逆に、我々は nodeType のテストをフィルタから削除することができるとしたら、それはwhatToShowElementsAttrProcessingInstructionsを区別するということに基づいている。

1.1.2.2. ノードフィルタ と例外

ノードフィルタを書くとき、ユーザーは例外を投げることが出来るようなコードを回避すべきである。 しかしながら、DOMインプリメンテーションは投げられる例外を妨げることはできないので、例外を投げるフィルタの動作がしっかり定義されたものであることが重要である。 TreeWalker あるいはNodeIterator はフィルタから投げられる例外をキャッチしたり置き換えたりはしないが、それをユーザーのコードまで伝播するようにする。以下の関数は NodeFilterを呼び出すかもしれず、もしフィルタによって投げられた例外があればそれを伝播する:

  1. NodeIterator .nextNode()
  2. NodeIterator .previousNode()
  3. TreeWalker .firstChild()
  4. TreeWalker .lastChild()
  5. TreeWalker .nextSibling()
  6. TreeWalker .previousSibling()
  7. TreeWalker .nextNode()
  8. TreeWalker .previousNode()
  9. TreeWalker .parentNode()

1.1.2.3. ノードフィルタ とドキュメントの変更

良く設計された ノードフィルタ はドキュメントの構造を変更すべきではない。 しかしDOMインプリメンテーションは、ユーザーがドキュメント構造を変化させるようなフィルタのコードを書くことを防ぐことができない。 トラバースはこのケースを扱うための特別な処理を提供しない。 たとえば、もしノードフィルタ がノードをドキュメント中から削除する場合、これはなおそのノードを受容することができる。これは、それがもはやサブツリー中でトラバースされているとしても、NodeIterator あるいはTreeWalker によって返されてよいということを意味する。 一般的に、これは矛盾した、混乱した結果を導きうる。そのため、我々はユーザーが ドキュメント構造に変更を加えないようなノードフィルタ を書くことを推奨している。この代わりに、トラバースオブジェクトによって制御されるループ中で編集を行ってほしい。

1.1.2.4. ノードフィルタwhatToShow フラグ

NodeIterator およびTreeWalker は、フィルタを適用する前に、それらのwhatToShow フラグを適用する。 もしノードがアクティブなwhatToShow フラグによってスキップされた場合、 ノードフィルタ はそのノードを評価するためには呼び出されない。 この動作はFILTER_SKIPのそれに類似しているということに注意していただきたい。 そのノードの子は考慮され、フィルタはそれらを評価するために呼び出されうる。これは、たとえその ノードフィルタ がサブツリー全体を拒絶する方を選んだとしても、実際には「スキップ」となることにも注意。 これがアプリケーションで問題となる場合、 whatToShowSHOW_ALL にセットして nodeType のテストをそのフィルタの中で実行するとよい。

1.1.3. TreeWalker

TreeWalker インターフェースはNodeIterator インターフェースと同様の利益の多くを提供する。 これら2つのインターフェース間の主な違いは、TreeWalker がサブツリー中のノードについて、反復子のリスト指向のビューではなく、ツリー指向のビューを表すことにある。 言い換えれば、反復子は前後に移動することを可能にしているが、 TreeWalker はノードの 、子のひとつ、 兄弟に移動したりすることも可能にする。

TreeWalker の使用はノードを直接的に用いたナビゲーションに非常に似ており、2つのインターフェースにおけるナビゲーションメソッドは類似している。 たとえば、ドキュメント順序でノードのツリーを再帰的にウォークし、最初のノードに入るのとその後の全ての子の処理とで異なるアクションをとるような関数がある:

processMe(Node n) {
   nodeStartActions(n);
   for (Node child=n.firstChild(); 
        child != null;
        child=child.nextSibling()) {
      processMe(child);
   }
   nodeEndActions(n);
}

TreeWalker を用いて同様のことを行うものは非常に似ている。 これらには1つの違いがある: TreeWalker におけるナビゲーションはカレント位置を、この関数の最後で変更した位置に変更する。 currentNode という名前の読み書き属性は、 TreeWalkerのカレントノードが、クエリされたものであることも、セットされたものであることも可能にする。これを この関数が完了したときにTreeWalker の位置が保存されたことを確かめるために使用する:

processMe(TreeWalker tw) {
   Node n = tw.getCurrentNode();
   nodeStartActions(tw);
   for (Node child=tw.firstChild(); 
        child!=null;
        child=tw.nextSibling()) {
      processMe(tw);
   }

   tw.setCurrentNode(n);
   nodeEndActions(tw);
}

TreeWalker を直接的なNode のナビゲーションの代わりに使用する場合の利点は、 TreeWalker はユーザーがツリーの適切なビューを選ぶことを可能にしているという点にある。 フラグはComments あるいは ProcessingInstructionsを表示あるいは隠蔽するために用いても良い; エンティティは展開されるかEntityReference ノードとして表示されうる。 さらに、ノードフィルタ がこのツリーのカスタムビューを表すために用いられて良い。 あるプログラムが、ドキュメントのそれぞれのchapterで出現するものとして列挙されたテーブルを表すビューを必要としているとする。 このビューでは、chapterエレメントとそれが含むテーブルが見られる。最初のステップは適切なフィルタを書くことである:

class TablesInChapters implements NodeFilter {

   short acceptNode(Node n) {
      if (n.getNodeType()==Node.ELEMENT_NODE) {
    
          if (n.getNodeName().equals("CHAPTER"))
             return FILTER_ACCEPT;

          if (n.getNodeName().equals("TABLE"))
             return FILTER_ACCEPT;

          if (n.getNodeName().equals("SECT1")
              || n.getNodeName().equals("SECT2")
              || n.getNodeName().equals("SECT3")
              || n.getNodeName().equals("SECT4")
              || n.getNodeName().equals("SECT5")
              || n.getNodeName().equals("SECT6")
              || n.getNodeName().equals("SECT7"))
             return FILTER_SKIP;

      }

      return FILTER_REJECT;
    }
}

このフィルタでは、TABLEエレメントはCHAPTERあるいはSECTnにダイレクトに含まれているとみなしている。 もし他の種類のエレメントに遭遇した場合、それとその子は拒絶される。 もしSECTnエレメントに遭遇した場合、それはスキップされるが、その子は探索され、TABLEエレメントを含んでいないかどうか確かめられる。

今、このプログラムはこのNodeFilter, のインスタンスを生成し、 それを使うTreeWalker を生成し、 そのTreeWalker を我々のProcessMe() 関数に渡すことが可能になった:

TablesInChapters tablesInChapters  = new TablesInChapters();
TreeWalker tw  = 
     ((DocumentTraversal)document).createTreeWalker(
          root, NodeFilter.SHOW_ELEMENT, tablesInChapters);
processMe(tw);

(繰り返しになるが、我々はこのフィルタのロジック中でnodeType をテストし、さらに先のNodeIterator の例で議論した理由からSHOW_ELEMENTを用いるという途を選んだ。)

上記のProcessMe()関数を変更することなく、これは今やCHAPTERとTABLEのエレメントだけを処理する。 プログラマーは他のフィルタを書いたり、他のフラグをセットしたりして、他のノードのセットを選ぶことができる; もし関数がTreeWalker をナビゲートに使った場合、それらはTreeWalkerで定義されたドキュメントのあらゆるビューをサポートすることになるであろう。

TreeWalkerの フィルタされたドキュメントのビューの構造は、そのドキュメント自身とは根本的に異なりうる。 たとえば、SHOW_TEXT のみを whatToShow パラメータで指定されたTreeWalker は全ての Text ノードを、がいないにもかかわらず、あたかもそれらが兄弟 であるかのように表す。

1.1.3.1. 維持性(Robustness)

NodeIteratorsと同様、 TreeWalker はそのナビゲートするデータ構造が編集される間はアクティブであってもよく、 その変更を考慮して動作しなければならない。 現存のデータ構造に対する追加および削除は TreeWalkerを無効にしない; 実際のところでも、TreeWalkerは絶対に無効化されない。

しかしこれらの変更に対するTreeWalkerの 反応は NodeIterator におけるそれとは全く異なる。 NodeIterators がそのリスト中の反復子の位置の維持によって編集行為に反応するのに対して、TreeWalkers はそのcurrentNodeをそこに残したままにしておく。 TreeWalker の全てのナビゲーションメソッドは、 TreeWalker がアクセスされた最後の時点から、そのノードおよびその周辺に何が起ころうとも、 呼び出されたときのcurrentNodeのコンテキストに基づいて指令する。 これはたとえcurrentNode がオリジナルのサブツリーの外側に移動したとしても成り立つ。

例として、次のようなドキュメントフラグメントを考えてみる:

    ...
    <subtree>
        <twRoot>
            <currentNode/>
            <anotherNode/>
        </twRoot>
    </subtree>
    ...
 

ここで、root ノードが <twRoot/> エレメントでありcurrentNode が <currentNode/> エレメントとなるような TreeWalker を生成したとしよう。 この図から、上記の全ノードはこの TreeWalkerwhatToShow とフィルタ設定から受容されているとみなす。

もし <currentNode/> エレメントをその から削除するためにremoveChild() を用いた場合、たとえroot ノードのサブツリー内に存在しないとしても、 そのエレメントはTreeWalkercurrentNodeであり続ける。 これでもまだTreeWalker を使って、孤児となったcurrentNode が持っているあらゆる子をナビゲートすることができるが、もはや利用可能な が存在しないため、currentNode の外側にナビゲートすることはできない。

もしinsertBefore() あるいはappendChild() を用いて、その<currentNode/> に新しい を与えた場合、 TreeWalker ナビゲーションはcurrentNodeの新しいロケーションから指令する。 たとえば、もし<currentNode/>を <anotherNode/> エレメントのすぐ後に追加した場合、 このTreeWalkerpreviousSibling() 指令はこれを <anotherNode/>に戻し、parentNode() の呼び出しは <twRoot/>に移動する。

もし次のようにcurrentNode を <subtree/> エレメントに追加した場合:

    ...
    <subtree>
        <currentNode/>
        <twRoot>
            <anotherNode/>
        </twRoot>
    </subtree>
    ...

currentNodeTreeWalkerroot ノードの下から移動した。これは TreeWalkerを無効化してはいない; これはまだcurrentNodeから相対的にナビゲートするために用いられうる。 たとえばこれのparentNode()命令の呼び出しは、 それもまたオリジナルのroot ノードの外側にあるのであるが、 そのウォーカーを <subtree/> エレメントまで移動する。 しかし、もしこのTreeWalkerの ナビゲーションがオリジナルのrootノードのサブツリーまで戻されなければならない場合 -- たとえばparentNode() ではなくnextNode()を呼び出して、TreeWalker を <twRoot/> エレメントまで移動した場合 -- root ノードはTreeWalkerを「もう一度捕獲」し、トラバースから手を引くのを防ぐ。

これはフィルタが使用された場合に、さらに少々複雑になる。 currentNodeの移転 -- あるいは新しいcurrentNodeの明示的な選択、あるいはNodeFilter がその決定に基づいているような状態の変更 -- は、TreeWalker が、フィルタされた(論理上の)ドキュメントのビューにおいて不可視となるようなcurrentNode を持つ結果となってもよい。 このノードはそのビューにおける「変遷メンバー(transient view)」であると考えてもよい。 TreeWalker にこのノードをナビゲートから外すことを頼む場合、その結果はあたかもそれが可視であるかのようであるが、これをもう一度可視にするような状態変化がない限り、これにナビゲーションを戻すことはできない。

特に: もしこのcurrentNode がフィルタによって拒絶されるようなサブツリーの一部となった場合、そのサブツリー全体がその論理ビューにおける変遷メンバーとして追加される。 かつて拒絶された祖先まで移動する間は、そのサブツリー中をナビゲートすることができる(通常の全てのフィルタリングには従う)。 その動作はあたかも、そこから離れるまでは、拒絶されたノードが単にスキップされたかのようになる(そのサブツリー内で曲がりくねりながらも進むことになるのである)。そして、標準のフィルタリングが適用される。この辺りは難解で、いまいち上手く翻訳し切れていないです。)

1.2. 形式的なインターフェース定義

インターフェース NodeIterator (DOM レベル 2で導入)

反復子 はノードのセットの間をステップするために用いる。たとえば、NodeList中のノードのセット、特定のNodeに結びつけられたドキュメントサブツリー、クエリの結果、あるいはその他のノードのセットなどがある。 反復子を指定されるノードのセットはNodeIteratorの実装によって決定される。 DOM レベル 2 では、ドキュメント順序でドキュメントサブツリーをトラバースするための単一のNodeIteratorの実装を規定している。 これらの反復子のインスタンスはDocumentTraversal.createNodeIterator()を呼び出すことによって生成される。


IDL 定義
// DOM レベル 2で導入:
interface NodeIterator {
  readonly attribute Node             root;
  readonly attribute unsigned long    whatToShow;
  readonly attribute NodeFilter       filter;
  readonly attribute boolean          expandEntityReferences;
  Node               nextNode()
                                        raises(DOMException);
  Node               previousNode()
                                        raises(DOMException);
  void               detach();
};

アトリビュート
expandEntityReferences boolean型, readonly
このフラグの値はエンティティ参照ノードである子が反復子に可視とされるかどうかを決定する。falseであれば、それらとそれらの子孫は拒絶される。 この拒絶はwhatToShow やフィルタよりも優先する事に注意。 また、これは現在では、NodeIterators が個別のノードをスキップするのではなく完全なサブツリーを拒絶する、唯一のシチュエーションであるということにも注意。

エンティティ参照が展開され、かつそのエンティティ参照ノード自身は表に出さないようなドキュメントのビューを作り出すためには、whatToShow フラグを用いてそのエンティティ参照ノードを隠し、そしてこの反復子を生成するときにexpandEntityReferences をtrueに設定する。 エンティティ参照ノードをもつがエンティティを展開しないようなドキュメントのビューを作り出すためには、whatToShow フラグを用いてエンティティ参照ノードを表示し、かつexpandEntityReferences をfalseにする。
filter NodeFilter型, readonly
ノードをふるいにかけるために用いるNodeFilter
root Node型, readonly
生成時に指定されたNodeIterator のルートノード。
whatToShow unsigned long型, readonly
この属性はどのノードタイプが反復子を通して出現するかを決定する。 有効な定数のセットはNodeFilter インターフェースで定義されている。 whatToShow で受容されなかったノードはスキップされるが、それらの子はなお検証の対象となる。このスキップはフィルタよりも優先適用されることに注意。
メソッド
detach
そのNodeIterator を、反復子を指定されているセットから切り離し、計算中のリソースを解放してその反復子を INVALID 状態にする。 detach が呼び出された後は、nextNode あるいは previousNode の呼び出しは例外 INVALID_STATE_ERR を発生させる。
パラメータ なし
戻り値 なし
例外 なし
nextNode
セットにおける次のノードを返し、反復子の位置をそのセットの中で先に進める。NodeIterator が生成された後は、nextNode() の最初の呼び出しは、そのセット中で最初のノードを返す。
戻り値

Node

そのセット中で反復子を指定される次のNode か、もしそのセットにそれ以上のメンバーが存在しない場合はnull

例外

DOMException

INVALID_STATE_ERR: このメソッドが、detach メソッドが呼び出された後に呼び出された場合に発生する。

パラメータ なし
previousNode
セットにおける前のノードを返し、NodeIteratorの位置をそのセットの中で前に戻す。
戻り値

Node

そのセット中で反復子を指定される前のNode か、もしそのセットにそれ以上のメンバーが存在しない場合はnull

例外

DOMException

INVALID_STATE_ERR: このメソッドが、detach メソッドが呼び出された後に呼び出された場合に発生する。

パラメータ なし
インターフェース NodeFilter ( DOM レベル 2で導入)

フィルタはどのようにノードを「フィルタアウトするか」を知るオブジェクトである。NodeIterator あるいは TreeWalkerNodeFilterが与えられると、それは次のノードを返す前にこのフィルタを適用する。 もしこのフィルタがそのノードを受容すると言うのであれば、トラバースロジックはそれを返し、そうでなければトラバースは次のノードを探し、その拒絶されたノードはそこには存在しなかったかのように装う。

DOM は何らフィルタを提供しない。 NodeFilter は、ユーザーが実装して自身のフィルタを生成することができるような、単なるインターフェースである。

NodeFilters はどのようにノードからノードにトラバースするかを知る必要はないし、トラバースされることになるデータ構造について何ら知っている必要もない。知らなければならないのは単一のノードをどのように評価するかということだけなので、これはフィルタを非常に記述し易くしている。 1つのフィルタは多くのトラバースに用いられてもよく、コードの再利用を促進している。


IDL 定義
// DOM レベル 2で導入:
interface NodeFilter {

  // acceptNodeによって返される定数
  const short               FILTER_ACCEPT                  = 1;
  const short               FILTER_REJECT                  = 2;
  const short               FILTER_SKIP                    = 3;


  // whatToShowのための定数
  const unsigned long       SHOW_ALL                       = 0xFFFFFFFF;
  const unsigned long       SHOW_ELEMENT                   = 0x00000001;
  const unsigned long       SHOW_ATTRIBUTE                 = 0x00000002;
  const unsigned long       SHOW_TEXT                      = 0x00000004;
  const unsigned long       SHOW_CDATA_SECTION             = 0x00000008;
  const unsigned long       SHOW_ENTITY_REFERENCE          = 0x00000010;
  const unsigned long       SHOW_ENTITY                    = 0x00000020;
  const unsigned long       SHOW_PROCESSING_INSTRUCTION    = 0x00000040;
  const unsigned long       SHOW_COMMENT                   = 0x00000080;
  const unsigned long       SHOW_DOCUMENT                  = 0x00000100;
  const unsigned long       SHOW_DOCUMENT_TYPE             = 0x00000200;
  const unsigned long       SHOW_DOCUMENT_FRAGMENT         = 0x00000400;
  const unsigned long       SHOW_NOTATION                  = 0x00000800;

  short              acceptNode(in Node n);
};

定義グループ acceptNodeによって返される定数

以下の定数は acceptNode() メソッドによって返される:

定義済み定数
FILTER_ACCEPT
ノードを受容する。NodeIterator あるいは TreeWalker で定義されたナビゲーションメソッドはこのノードを返す。
FILTER_REJECT
ノードを拒絶する。NodeIterator あるいは TreeWalker で定義されたナビゲーションメソッドはこのノードを返さない。 TreeWalker, については、このノードの子もまた拒絶される。 NodeIterators はこれをFILTER_SKIPと同様に扱う。
FILTER_SKIP
この1つのノードをスキップする。NodeIterator あるいは TreeWalker で定義されたナビゲーションメソッドはこのノードを返さない。 NodeIteratorTreeWalker の両方とも、そのノードの子はなお検証の対象となる。
定義グループ whatToShowのための定数

これらはTreeWalkers および NodeIterators で利用されるwhatToShow パラメータの有効な値となる。 これらはNodeの有効なタイプのセットと同様であり、それらの値は 同じノードタイプのnodeType で該当する値のビット位置を用いて派生される。 もしwhatToShow のビットがfalseにセットされた場合、それはこのタイプのノードがスキップされるよう要求されていることを表す。その場合の動作はFILTER_SKIPのそれと同様である。

もし32種類以上のノードタイプが導入された場合、それらはそれぞれを whatToShowを通じてテストすることができない。 もしそのようなニーズが生じた場合、それはSHOW_ALL の選択と適切なNodeFilterによって扱われることで可能になる。

定義済み定数
SHOW_ALL
全てのNodesを表示する。
SHOW_ATTRIBUTE
Attr ノードを表示する。 これは反復子あるいはツリーウォーカーの生成時に、属性値をその rootとして指定した場合にのみ有効である。この場合、それはその属性ノードがその反復子あるいはトラバースの最初の位置に出現することを表す。 属性は他のノードの子にはなりえないので、それらはドキュメントツリーのトラバース中に出現することはない。
SHOW_CDATA_SECTION
CDATASection ノードを表示する。
SHOW_COMMENT
Comment ノードを表示する。
SHOW_DOCUMENT
Document ノードを表示する。
SHOW_DOCUMENT_FRAGMENT
DocumentFragment ノードを表示する。
SHOW_DOCUMENT_TYPE
DocumentType ノードを表示する。
SHOW_ELEMENT
Element ノードを表示する。
SHOW_ENTITY
Entity ノードを表示する。 これは反復子あるいはツリーウォーカーを、Entity ノードをそのrootとして生成した場合にのみ有効である。 この場合、これはこの Entity ノードがトラバースの最初の位置に出現することを意味する。 エンティティはドキュメントツリーの一部ではないため、それらはドキュメントツリーのトラバース中に出現することはない。
SHOW_ENTITY_REFERENCE
EntityReference ノードを表示する。
SHOW_NOTATION
Notation ノードを表示する。 これは反復子あるいはツリーウォーカーを、Notation ノードをそのrootとして生成した場合にのみ有効である。 この場合、これはこの Notation ノードがトラバースの最初の位置に出現することを意味する。 ノーテーションはドキュメントツリーの一部ではないため、それらはドキュメントツリーのトラバース中に出現することはない。
SHOW_PROCESSING_INSTRUCTION
ProcessingInstruction ノードを表示する。
SHOW_TEXT
Text ノードを表示する。
メソッド
acceptNode
指定されたノードがTreeWalker あるいは NodeIterator の論理ビューについて可視であるかどうかをテストする。 この関数はTreeWalker および NodeIteratorの実装によって呼び出される。 これは通常ユーザーのコードからは直接呼び出されない。(ただ、同じフィルタを用いてアプリケーションロジックをガイドしたいというのであれば、それは可能である。)
パラメータ
n Node
このフィルタを通るかどうかチェックしたいノード。
戻り値

short

そのノードが受容されるか、拒絶されるか、スキップされるかを判別する定数。 上記の定義の通り。

例外 なし
インターフェース TreeWalker ( DOM レベル 2で導入)

TreeWalker オブジェクトはドキュメントツリーあるいはサブツリーを、whatToShow フラグと(もしあれば)フィルタとによって定義されたドキュメントのビューを用いてナビゲートするために用いられる。 TreeWalkerを用いたナビゲーションを実行する関数は、TreeWalkerで定義されたビューをサポートする。

サブツリーの論理ビューからノードを省略した結果は、同じサブツリーの、完全な、フィルタされていないドキュメントとは全く異なる構造となってもよい。 TreeWalker 上で兄弟となっているものは、異なった、オリジナルビューにおけるばらばらのノードの子でありうる。 たとえば、Textノード以外の全てをスキップするようなNodeFilterと、ドキュメントのルートノードについて考えてみよう。 その結果の論理ビューでは、全てのテキストノードが兄弟 であり、たとえオリジナルドキュメントの構造中でどれだけ深い位置に存在していたとしても、そのルートノードの直下に出現する。


IDL 定義
// DOM レベル 2で導入:
interface TreeWalker {
  readonly attribute Node             root;
  readonly attribute unsigned long    whatToShow;
  readonly attribute NodeFilter       filter;
  readonly attribute boolean          expandEntityReferences;
           attribute Node             currentNode;
                                        // raises(DOMException) on setting

  Node               parentNode();
  Node               firstChild();
  Node               lastChild();
  Node               previousSibling();
  Node               nextSibling();
  Node               previousNode();
  Node               nextNode();
};

アトリビュート
currentNode Node
TreeWalker が現在位置しているノード。
DOMツリーの置換はカレントノードがもはやTreeWalkerに関連付けられたフィルタによって受容されなくなるようになるかもしれない。 currentNode はそれがroot ノードによって指定されたサブツリー中に存在するかしないか、あるいはフィルタやwhatToShow フラグによって受容されるかどうか、といったことに関わりなく、明示的に任意のノードに指定されうる。 それ以上の解析は、リクエストされた方向でそのフィルタを適用された結果たとえcurrentNodeがカレントビューの一部でなくなったとしても、このcurrentNodeからの相対で発生する。 もし有効なトラバースが存在しない場合は、currentNode は変更されない。
セット時の例外

DOMException

NOT_SUPPORTED_ERR: currentNodenullにセットされようとしたときに発生する。

expandEntityReferences boolean型, readonly
このフラグの値は、エンティティ参照ノードの子がTreeWalkerから可視とされるかどうかを決定する。 falseであれば、それらとそれらの子孫 は拒絶される。 この拒絶はwhatToShow および(もしあれば)フィルタより優先適用されることに注意。
展開されたエンティティ参照をもち、かつそのエンティティ参照ノードは表に出さないようなドキュメントのビューを作り出すためには、 whatToShow フラグをもちいてエンティティ参照ノードを隠し、TreeWalkerの生成時にexpandEntityReferences をtrueにセットすればよい。 エンティティ参照ノードを持つがエンティティは展開しないようなドキュメントのビューを作り出すためには、 whatToShow フラグを用いてエンティティ参照ノードを表示し、expandEntityReferences をfalseにセットすればよい。
filter NodeFilter型, readonly
ノードをふるいにかけるために用いられるフィルタ。
root Node型, readonly
生成時に指定されたTreeWalkerroot ノード。
whatToShow unsigned long型, readonly
この属性はどのノードタイプがTreeWalkerを通して出現するかを決定する。有効な定数のセットはNodeFilter インターフェースで定義されている。 whatToShow で受容されないノードはスキップされるが、それらの子はなお検証の対象となる。このスキップは(もしあれば)フィルタより優先適用されることに注意。
メソッド
firstChild
TreeWalker をカレントノード中の最初の可視の に移動し、その新しいノードを返す。 もしカレントノードが可視の子をもたない場合はnullを返し、カレントノードを維持する。
戻り値

Node

新しいノード、あるいはもしカレントノードがTreeWalkerの論理ビューおける可視の子をもたない場合はnull

パラメータ なし
例外 なし
lastChild
TreeWalker をカレントノード中の最後の可視の に移動し、その新しいノードを返す。 もしカレントノードが可視の子をもたない場合はnullを返し、カレントノードを維持する。
戻り値

Node

新しいノード、あるいはもしカレントノードがTreeWalkerの論理ビューおける可視の子をもたない場合はnull

パラメータ なし
例外 なし
nextNode
TreeWalker をドキュメント順序でカレントノードから相対的に次にある可視ノードに移動し、新しいノードを返す。もしカレントノードに次のノードがない場合、あるいはnextNodeの検索がTreeWalkerroot ノードより上に移動しようとした場合は、nullを返し、カレントノードを維持する。
戻り値

Node

新しいノード、あるいはもしカレントノードがTreeWalkerの論理ビューで次のノードをもたない場合はnull

パラメータ なし
例外 なし
nextSibling
TreeWalker を次の兄弟に移動し、新しいノードを返す。もしカレントノードの次の可視兄弟がない場合はnullを返し、カレントノードを維持する。
戻り値

Node

新しいノード、あるいはもしカレントノードがTreeWalkerの論理ビューで次の兄弟をもたない場合はnull

パラメータ なし
例外 なし
parentNode
カレントノードから最も近い可視の祖先 ノードに移動してそれを返す。 もしparentNode の検索がTreeWalkerrootより上に移動しようとするか、可視の祖先 ノードが存在しない場合、このメソッドはカレント位置を保持し、nullを返す。
戻り値

Node

新しい ノード、あるいはもしカレントノードがTreeWalkerの論理ビューで親をもたない場合はnull

パラメータ なし
例外 なし
previousNode
TreeWalker をドキュメント順序でカレントノードから相対的に前にある可視ノードに移動し、新しいノードを返す。もしカレントノードに次のノードがない場合、あるいはpreviousNodeの検索がTreeWalkerroot ノードより上に移動しようとした場合は、nullを返し、カレントノードを維持する。
戻り値

Node

新しいノード、あるいはもしカレントノードがTreeWalkerの論理ビューで前のノードをもたない場合はnull

パラメータ なし
例外 なし
previousSibling
TreeWalker を前の兄弟に移動し、新しいノードを返す。もしカレントノードの前の可視兄弟がない場合はnullを返し、カレントノードを維持する。
戻り値

Node

新しいノード、あるいはもしカレントノードがTreeWalkerの論理ビューで前の兄弟をもたない場合はnull

パラメータ なし
例外 なし
インターフェース DocumentTraversal (introduced in DOM Level 2)

DocumentTraversal は反復子とツリーウォーカーを生成してノードおよびその子をドキュメント順序でトラバースするメソッドを含む(最初の深さで、ドキュメントのテキスト表現において開始タグが出現した順序に等しい順序の規定されたトラバースとなる)。 Traversal featureをサポートするDOMでは、DocumentTraversal はDocumentインターフェースを実装しているものと同じオブジェクトによって実装される。


IDL 定義
// DOM レベル 2で導入:
interface DocumentTraversal {
  NodeIterator       createNodeIterator(in Node root, 
                                        in unsigned long whatToShow, 
                                        in NodeFilter filter, 
                                        in boolean entityReferenceExpansion)
                                        raises(DOMException);
  TreeWalker         createTreeWalker(in Node root, 
                                      in unsigned long whatToShow, 
                                      in NodeFilter filter, 
                                      in boolean entityReferenceExpansion)
                                        raises(DOMException);
};

メソッド
createNodeIterator
指定されたノードをサブツリーのルートとする、新しいNodeIteratorを生成する。
パラメータ
root Node
その子ともども反復子を指定されるノード。この反復子は最初はこのノードの前に位置する。 whatToShow フラグおよび(もしあれば)フィルタは、この位置をセットする際には考慮されない。ルートはnullであってはならない。
whatToShow unsigned long
このフラグはどのノードタイプがこの反復子によって表示されるツリーの論理ビューによって出現してもよいかを指定する。 NodeFilter の有効なSHOW_ の値のセットに関する説明を参照。
これらのフラグはORを用いて結合されうる。
filter NodeFilter
このTreeWalker(NodeIteratorでは?)で用いられる NodeFilter 、あるいはフィルタを指定しない場合はnull
entityReferenceExpansion boolean
このフラグの値はエンティティ参照ノードが展開されるかどうかを決定する。
戻り値

NodeIterator

新たに生成されたNodeIterator

例外

DOMException

NOT_SUPPORTED_ERR: 指定されたrootnullであった場合に発生する。

createTreeWalker
指定されたノードをサブツリーのルートとする、新しいTreeWalkerを生成する。
パラメータ
root Node
TreeWalkerrootとして使用されるノード。 whatToShow フラグおよびNodeFilter はこの値を設定するときには考慮されない。いかなるタイプのノードもrootとして許容される。 TreeWalkercurrentNodeは、それが可視であるかないかを問わず、このノードに初期化される。 rootparentNode あるいは nextNode のようなドキュメント構造を上に探すようなトラバースメソッドにおいて、ストップ位置として機能する。 rootnullであってはならない。
whatToShow unsigned long
このフラグはどのノードタイプがツリーウォーカーによるツリーの論理ビューで出現してよいかを決定する。 NodeFilter の有効なSHOW_ の値に関する説明を参照。
これらのフラグはORを用いて結合されうる。
filter NodeFilter
このTreeWalkerで使用されるNodeFilter、あるいはフィルタを指定しない場合はnull
entityReferenceExpansion boolean
もしこのフラグがfalseであれば、EntityReference ノードの内容は論理ビュー中で出現しない。
戻り値

TreeWalker

新しく生成されたTreeWalker.

例外

DOMException

NOT_SUPPORTED_ERR: 指定された rootnullであった場合に発生する。

このドキュメントは以下で説明するW3C文書の翻訳です。
この翻訳はW3Cの正式な仕様ではありえません。
翻訳者は翻訳の正確さを保証するものではありません
仕様の原文 / 著作権表記
Translation Copyright © 2001/01/26 Ginga