この章では、選択的な DOM Level 2 Traversal の特徴について述べる。この TreeWalker
, NodeIterator
, and NodeFilter
インターフェイスは、容易に利用できる、堅牢(robust)な、文書の内容の選択的なトラバーサル(横断?) を提供する。
このセクション内のインターフェイスは強制的な物ではない。DOM アプリケーションは、実装によってこのモジュールがサポートされているかどうかを判定するのに、値 "Traversal" と "2.0" をそれぞれ引数にもつ DOMImplementation
の hasFeature(feature, version)
メソッドを使用できる。このモジュールの完全なサポートのために、DOM Level 2 Core 仕様 [DOM Level 2 Core] で定義される "Core" の特徴を、実装はサポートしなければならない。DOM Level 2 Core 仕様 [DOM Level 2 Core] における 適合 については追加情報を参照されたい。
NodeIterator
と TreeWalker
は、文書のサブツリーのノードとそれらの存在するノード内の位置をあらわす、2 通りの方法である。NodeIterator
は、ドキュメントオーダー内で与えられた序列あるノードの並びとしてのサブツリーの平らな一覧を示す。この一覧は階層へのの考慮なしに示されるので、イテレータは前後に移動するメソッドを持つが、上下に移動するメソッドは持たない。逆に、TreeWalker
はこの階層のナビゲーションを許可するサブツリー内の階層関係を維持している。一般に、その中で選択されたノードの周囲の文書構造が操作されるような用途には TreeWalker
が向いており、選択された各ノードの内容に注目するような用途には NodeIterator
が向いている。
NodeIterator
と TreeWalker
はそれぞれ、サブツリー内の全ノードを含むとは限らない文書サブツリーの一覧を示す。この仕様では、文書サブツリーそれ自体に該当する 物理一覧(phisical view) と区別するために、これを 論理一覧(logical view) と呼ぶ。イテレータもしくは TreeWalker
を作成するとき、各ノードを検査し論理一覧に出現するか否かを決定する NodeFilter
に関連付けることができる。加えて、フラグを使用して論理一覧に出現するノード型を指定できる。
NodeIterator
と TreeWalker
は動的である - 元文書への変更の反映として論理一覧は変化する。しかし、その変更にどう応じるかでそれらは異なる。NodeIterator
は連続的にノードを示すものであり、シーケンスの内容が変化するときは、そのシーケンス内の位置に対応するロケーションの維持を試みる。TreeWalker
はフィルタをかけられたツリーとしてのノードを示すものであり、ノードが新たなコンテキストに移動する場合は、現在のノードに対応するロケーションとそのノードの付属物の残りを維持する。これらの挙動の詳細は下記にて議論する。
NodeIterators
NodeIterator
はノードのリストのメンバが連続的に返されるとことを可能にする。現在の DOM インターフェイス内で、このリストは常に ドキュメントオーダー(document order) 内に示されるサブツリーのノードで構成されるだろう。イテレータが最初に生成されるとき、nextNode()
メソッドの呼び出しはサブツリーの論理一覧内の最初のノードを返す; 大抵の場合、これはサブツリーのルートである。連続的な各呼び出しは、リストを通して論理表示内で次に利用可能なノードを返しながら NodeIterator
を進める。ノードがなくなったとき、 nextNode()
は null
を返す。
NodeIterator
は DocumentTraversal
インターフェイスの createNodeIterator
メソッドによって生成される。NodeIterator
が生成されるとき、ノード型が "visible" であるか、そしてツリー横断中ノードが "invisible" であるかを決定するフラグを使用できる; これらのフラグは OR
演算子で結合できる。イテレータは、"invisible" であるノードを存在しないかのようにスキップする。
次のコードは、イテレータを生成し、関数を呼び出して各要素名をプリントする:
NodeIterator iter= ((DocumentTraversal)document).createNodeIterator( root, NodeFilter.SHOW_ELEMENT, null); while (Node n = iter.nextNode()) printMe(n);
NodeIterator
は序列のあるリストとしてノードを示し、リスト内で前後に移動する。イテレータの位置は常に、最初のノードの前、あるいは最後のノードの後の、どちらか二つのノードの間である。イテレータが最初に生成されるとき、位置は最初の項目の前に設定される。次の図は、イテレータが特定のサブツリーに提供するリスト表示を示す。アスタリスク "*" は位置を示す:
* A B C D E F G H I
各 nextNode()
呼び出しは、次のノードを返し、位置を進める。具体的には、上記の位置から開始する場合、最初の nextNode()
呼び出しは "A" を返し、イテレータを進める:
[A] * B C D E F G H I
返される最も近いノードを 参照ノード(reference node) と呼び、NodeIterator
の位置を最もよく表す。イテレータ生成時、最初のノードが参照ノードであり、イテレータは参照ノードの前に位置付けられる。この図では、角括弧([]) が参照ノードを示す。
previousNode()
呼び出しは前のノードを返し、位置は後退する。具体的には、"A" と "B" の間の NodeIterator
で開始する場合、"A" が返され、下記の位置に移動する:
* [A] B C D E F G H I
リストの終端で nextNode()
が呼ばれる場合、またリストの先頭で previousNode()
が呼ばれる場合、null
が返され、イテレータの位置は移動しない。 NodeIterator
が最初に生成されたときは、参照ノードは最初のノードである:
* [A] B C D E F G H I
ナビゲートするデータ構造が編集されている間、 NodeIterator
はアクティブであってよく、イテレータは変更の中でも素直に振舞わねばならない。元のデータ構造の追加および削除は NodeIterator
を無効にしない; 実際、 NodeIterator
はその detach()
メソッドが呼ばれない限りは無効化されない。これを可能にするために、イテレータは参照ノードを用いて位置を維持する。イテレータの状態は、イテレータが参照ノードの前に位置しているか、また後に位置しているかに依存する。
イテレータのリストへの変更が参照ノードを除去しない場合は、 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
のイテレータの前ならば、、新しい参照ノードとしてイテレータの直前のノードが選ばれる。次の状態から "D" ノードを取り除くことを考えてみる:
A B C [D] * F G H I
イテレータより前にある NodeIterator
に最も近いノードは "C" ノードであるで、これが新しい参照ノードになる:
A B [C] * F G H I
参照ノードが NodeIterator
より後にある場合、イテレータの直後のノードが新たな参照ノードとして選択される。 previousNode()
が呼出された後など、参照ノードが NodeIterator
の後にあるならば、イテレータの後の直近のノードが新しい参照ノードとして選択される。次の状態から始めて "E" を除去することを想定しよう:
A B C D * [E] F G H I
イテレータの後である NodeIterator
に最も近いので、 "F" ノードが新しい参照ノードになる:
A B C D * [F] G H I
As noted above, ノードの移動は除去に続く挿入と等しい。次の状態から開始して、 "D" ノードをリストの末尾に移動することを考える:
A B C [D] * F G H I C
結果の状態は次である:
A B [C] * F G H I D
参照ノードがリストの末尾、参照ノードが除去されるとき、一つの特殊なケースが発生する。次の状態から開始して、ノード "C" を除去することを考える:
A B * [C]
与えられた規則に従い、新しい参照ノードは NodeIterator
の後の最も近いノードとなるはずであるが、 "C" の後にもうノードはない。同じ状況が previousNode()
がリスト内の最初のノードを返したときにも発生する。 Hence: 参照ノードの元の方向にもうノードがないならば、その反対方向の直近のノードが参照ノードとして選ばれる:
A [B] *
NodeIterator
が除去されたノードのブロックの内部に位置しているならば、上記の規則は clearly 行われるものであるものをあらわす。具体的には、"C" を "D", "E", "F" の 親 ノードとして、次の状態から "C" を除去することを考える:
A B C [D] * E F G H I D
結果の状態は次である:
A [B] * G H I D
最後に、その 親 からの NodeIterator
の root
ノードの除去は、イテレートされているリストを改変せず、イテレータの状態を変更しないことに注意。
繰り返されているもとのデータ構造は、論理ビューの一部でなく、それゆえ 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" を返さない。
NodeFilters
NodeFilters
は、ユーザにノードを "フィルタで濾す (filter out)" オブジェクトの作成を許可する。各フィルタは、ノードを見てそれが文書のトラバーサルの論理ビューの一部として存在するべきか否かを判定するユーザ定義関数を含む。 NodeFilter
を使用して、そのフィルタを使用する NodeIterator
や TreeWalker
を作成する。トラバーサルエンジンは各ノードにフィルタを適用し、フィルタがノードを拒否すれば、トラバーサルはそのノードが文書内に存在しないかのようにスキップする。 NodeFilters
は、操作対象ノードを含む構造のナビゲート方法を知る必要がない。
トラバーサル操作が実行されるとき、また NodeIterator
の参照ノードがいてレートされている下位ツリーから除去され新しい参照ノードを選択しなければならないとき、フィルタが調べられる。しかし、これらのフィルタ呼び出しの厳密なタイミングは、ある DOM 実装から他の DOM 実装まで様々である。その理由については、 NodeFilters
は過去の呼出しの履歴に基づく状態の維持を試みるべきではない; 結果の振る舞いはポータブルでなくてもよい。
同様に、 TreeWalkers
と NodeIterators
は、過去のフィルタの結果を記憶せず、未来の結果を予測しないように振舞うべきである。トラバーサルロジックがノードを検査する最終時に NodeFilter
が試験する条件が変更された (例えば検査する属性の追加削除など) ならば、次のトラバーサル操作が実行されたときのみ可視性の変更が反映する。例えば: 現在のノードのフィルタリングを FILTER_SHOW
から FILTER_SKIP
に変更する場合、 TreeWalker
は任意の方向のそのノードのナビゲートをやめることができるが、フィルタ条件を再び変更しなければそれに戻ることはない。トラバーサル中に変化する NodeFilters
を書くこともできるが、その振る舞いは混乱が起こりやすく、可能ならば避けられるべきである。
NodeFilters
の使用NodeFilter
は、 acceptNode()
というメソッドを持ち、 NodeIterator
または TreeWalker
がフィルタに Node
を渡してそれが論理ビュー内に存在するべきか否かを訊くことを許可する。 acceptNode()
関数は Node
がどのように扱われるかを説明する 3 この値のうちの一つを返す。 acceptNode()
が FILTER_ACCEPT
を返すならば、 Node
は論理ビュー内に存在している; FILTER_SKIP
を返すならば、 Node
は論理ビュー内には存在しないが、 Node
の子は存在してもよい; FILTER_REJECT
を返すならば、 Node
もその 子孫 も論理ビューには存在しない。イテレータは階層のない序列のあるリストとしてノードをあらわすので、 FILTER_REJECT
と FILTER_SKIP
は NodeIterators
にとっては同義であり、単に 1 個の現在のノードを飛ばすだけである。
HTML 文書内の名前付きアンカーを受け付けるフィルタを考える。 HTML では、 HREF は NAME 属性を持つ任意の A 要素を参照できる。これは、ノードを見てそれが名前付きアンカーであるかどうかを判定する、 Java による NodeFilter
である:
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; } }
上の NodeFilter
が NodeIterators
でのみ使用されるものであるならば、 FILTER_SKIP
のところで FILTER_REJECT
を使用してもその振る舞いは変わらない。だが TreeWalker
については、 FILTER_REJECT
は、名前付きアンカーでない任意の要素の子供を拒否し、名前付きアンカーは常に他の要素に含まれているのでこれは名前つきアンカーを見つけられないことを意味する。 FILTER_SKIP
は与えられたノードを拒否するが、その子供の検査を継続する; だから、上述のフィルタは NodeIterator
と TreeWalker
のどちらでも動作する。
このフィルタを使用するには、ユーザは NodeFilter
のインスタンスを生成して、それを使用する NodeIterator
を生成する:
NamedAnchorFilter myFilter = new NamedAnchorFilter(); NodeIterator iter= ((DocumentTraversal)document).createNodeIterator( node, NodeFilter.SHOW_ELEMENT, myFilter);
サンプル NodeFilter
で nodeType
を検査しているので、この例では SHOW_ELEMENT
フラグの使用は厳密には必要ないことに注意。だが文書構造の知識の利点をとることにより SHOW_ELEMENT
の使用を無駄にせずに whatToShow
パフォーマンスの改善が可能な Traversal インターフェイス実装もありうる。逆に、一方で nodeType
検査をフィルタから除去して、 whatToShow
依存で Elements
, Attr
, ProcessingInstructions
の間の区別するようにもできる。
NodeFilters
と例外NodeFilter
を書くときは、ユーザは例外を投げるコードを書くのは避けるべきである。だが、 DOM 実装は投げられる例外を防ぐことが出来ないので、例外を投げるフィルタの振る舞いが充分に定義されることが重要である。 TreeWalker
または NodeIterator
はフィルタによって投げられる例外を受け取らず、また変更しないが、それはユーザのコードまで伝播する。次の関数は NodeFilter
を呼出してよく、そしてフィルタによって例外が投げられる場合は例外を伝播してよい:
NodeIterator
.nextNode()
NodeIterator
.previousNode()
TreeWalker
.firstChild()
TreeWalker
.lastChild()
TreeWalker
.nextSibling()
TreeWalker
.previousSibling()
TreeWalker
.nextNode()
TreeWalker
.previousNode()
TreeWalker
.parentNode()
NodeFilters
と文書変更充分に設計された NodeFilters
は、元の文書構造の変更を行うべきではない。しかし DOM 実装はユーザが文書構造を変更するフィルタコードを書くことを防ぐことが出来ない。トラバーサルはこのケースを扱う特別な処理を提供しない。具体的には、 NodeFilter
が文書からノードを削除する場合、なおそのノードを受け付けることができ、それがトラバースされている下位ツリー内にあるとしても NodeIterator
または TreeWalker
によってそのノードが返されてもよいことを意味する。一般に、この方法は矛盾した混乱する結果を導き、従ってユーザには文書構造を変更しない NodeFilters
を書くことを推奨する。代わりに、トラバーサルオブジェクトにより制御されるループ内で編集を行いなさい。
NodeFilters
と whatToShow
フラグNodeIterator
と TreeWalker
は、フィルタを適用する前にその whatToShow
フラグを適用する。有効な whatToShow
フラグによってノードがスキップされる場合、ノードの評価に NodeFilter
が呼出されることはない。この振る舞いが FILTER_SKIP
のそれと同様であることに注意; そのノードの子は考慮され、フィルタはそれらの評価に呼出される。 NodeFilter
が下位ツリー全体の拒絶を選択するとしても、実際は "スキップ" にあることにも注意; これがアプリケーションに問題を起こす場合、 whatToShow
を SHOW_ALL
に設定すること、そしてフィルタ内部で nodeType
を検査することを考えなさい。
TreeWalker
TreeWalker
インターフェイスは、 NodeIterator
インターフェイスと多くの点で似通った機能を提供する。 2つのインターフェイス間の主な違いは、 TreeWalker
は、イテレータのリスト指向のビューではなく、下位ツリー内のノードのツリー指向のビューを提供する。言い換えると、イテレータは前方また後方への移動を許可するが、 TreeWalker
はそのノードの 親 へ、またその子のうちの一つへ、また 兄弟 への移動も許可される。
TreeWalker
の使用は Node を直接使用したナビゲーションと全く同様であり、2つのインターフェイスのナビゲーションメソッドは類似している。具体的に、これは、まずノードに入った時と子を処理した後で別々の行動をとる、文書オーダー内のノードのツリーを再帰的に歩く関数である:
processMe(Node n) { nodeStartActions(n); for (Node child=n.firstChild(); child != null; child=child.nextSibling()) { processMe(child); } nodeEndActions(n); }
TreeWalker
を使用する同様の処理は、全く同様である。一つだけ違うことがある: 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); }
Node
を直接のナビゲーションする代わりに TreeWalker
を使用する利点は、 TreeWalker
がツリーの適切なビューの選択をユーザに許可することである。 フラグを使用した Comments
や ProcessingInstructions
の表示・隠蔽ができる; 実体は展開され、また EntityReference
ノードとして現れてもよい加えて、 NodeFilters
を使用してツリーのカスタムビューを表すこともできる。章によってリストされる、各章内に表が出現することを示す文書のビューをプログラムが必要としているとしよう。このビューの中では、章要素とそれらが含む表だけが見える。最初のステップは、適切なフィルタを書くことである:
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
の検査と SHOW_ELEMENT
の使用の両方を選んでいるのは、前の NodeIterator
例で議論した理由である。)
上の ProcessMe()
関数に変更を加えることなく、 CHAPTER と TABLE 要素を処理する。プログラマは他のフィルタを書いたり他のフラグを設定して異なるノード集合を選択することもできる; 関数がナビゲートに TreeWalker
を使用する場合、それは TreeWalker
を伴って定義される文書の任意のビューをサポートする。
TreeWalker
のフィルタをかけられた文書のビューの構造は、文書自身の構造とは大きく異なっているかもしれないことに注意。例えば、 whatToShow
パラメータに SHOW_TEXT
だけを指定された TreeWalker
は、 Text
ノード全てを、 親 を持たず、互いに 兄弟 であるかのようにあらわす。
NodeIterator
のように、 TreeWalker
はそれをナビゲートするデータ構造が編集されている間も有効かもしれず、変更面において優雅に降るまわなければならない。元のデータ構造内の追加と削除は TreeWalker
を無効にしない; 実際 TreeWalker
はけして無効にされない。
だがそれらの変更への TreeWalker
の反応は、 NodeIterator
のそれとは全く異なる。繰り返されるリスト内部で NodeIterator
がその位置の維持による編集に反応する一方、 TreeWalkers
は代わりにその currentNode
に据え置く。 TreeWalker
のナビゲーションメソッドの全ては、 TreeWalker
がアクセスされた最終時から、ノードまたその周囲に何が起ころうとも呼出時の currentNode
の文脈条件内で操作する。これは currentNode
が本来の下位ツリーの外に移動されたとしても、依然として正しい。
例として、次のような文書片を考えよう:
... <subtree> <twRoot> <currentNode/> <anotherNode/> </twRoot> </subtree> ...
root
ノードが <twRoot/> 要素で、 currentNode
が <currentNode/> 要素である TreeWalker
を作成した。この図では、上に示されるノードの全ては TreeWalker
の whatToShow
とフィルタの設定によって受け入れられると想定する。
removeChild()
で <currentNode/> 要素をその 親 から除去する場合、その要素は root
ノードの下位ツリー内部でなくても TreeWalker
の currentNode
を残す。親のない currentNode
が持ちうる任意の子を通してナビゲートする TreeWalker
を依然として使用できるが、利用可能な 親 がなくなるため currentNode
から外へのナビゲートが出来なくなる。
insertBefore()
または appendChild()
で <currentNode/> に新しい 親 を与える場合、 TreeWalker
ナビゲーションは currentNode
の新しい位置から操作する。例えば、 <anotherNode/> 要素の直後に <currentNode/> を挿入した場合、 TreeWalker
の previousSibling()
操作はそれを <anotherNode/> まで戻し, parentNode()
呼出しはそれを <twRoot/> まで移動するだろう。
currentNode
を <subtree/> 要素の中に挿入する場合、そのように:
... <subtree> <currentNode/> <twRoot> <anotherNode/> </twRoot> </subtree> ...
TreeWalker
の root
ノード下から、 currentNode
を 外へ移動した。これは TreeWalker
を無効にしない; 依然として currentNode
に関係するナビゲートに使用してよい。その parentNode()
呼出し操作は、例えば、本来の root
ノードの外側であっても、 <subtree/> 要素に移動する。しかしながら、 TreeWalker
のナビゲーションが本来の root
ノードの下位ツリーの中へ戻るべきならば -- 例えば、 parentNode()
呼出しでなはく nextNode()
を呼び、TreeWalker
の <twRoot/> 要素へ移動する場合 -- root
ノードは TreeWalker
を "再捕捉 (recapture)" し、それの外に戻るトラバースを阻止する。
このことはフィルタが使用されていると多少複雑になる。 currentNode
の再配置 -- または新しい currentNode
の明示的な選択、または NodeFilter
がその決定に基づいている条件内の変更 -- は、文書のフィルタをかけられた (論理) ビュー内で可視ではない currentNode
を持つ TreeWalker
内を結果とすることができる。 このノードは、そのビューの "一時的メンバ (transient member)" として考えられる。このノードのナビゲート終了を TreeWalker
に問い合わせるとき、結果はちょうどそれが可視であるかのようになるが、条件を可視に再び変更しなければナビゲートでそれに戻ることは出来ないだろう。
特に: currentNode
が別な方法でフィルタに拒絶された下位ツリーの一部になる場合、完全な下位ツリーが論理ビューの一時的メンバとして追加されてよい。拒絶された 祖先 を過ぎて上方に移動するまで下位ツリー (全て通常のフィルタリングに従う) 内をナビゲートできる。この振る舞いは、拒絶されたノードがそれが残されるまで (下位ツリー内部でとにかく終えると) 単にスキップされるかのようである; したがって、標準フィルタリングを適用する。