このドキュメントは以下で説明するW3C文書の翻訳です。
この翻訳はW3Cの正式な仕様ではありえません。
翻訳者は翻訳の正確さを保証するものではありません
仕様の原文 / 著作権表記
Translation Copyright © 2001/01/26 Ginga
この章はDOM レベル 2のTraversal オプション機能について説明する。
このTreeWalker、
NodeIterator、
NodeFilter
のインターフェースは使いやすく頑丈なドキュメント内容の選択的なトラバース(横断解析)を提供する。
このセクションで見られるインターフェースは必須ではない。
DOMアプリケーションはDOMImplementationインターフェースのhasFeature(feature, version) メソッドを、パラメータ値"Traversal" および "2.0"に(それぞれ)指定して、このモジュールが実装によってサポートされているかどうかを決定することができる。
このモジュールを完全にサポートするためには、実装は
DOM レベル 2 コア 仕様 [DOM Level 2 Core]で定義されている"Core"機能もサポートしなければならない。
適合性 に関する追加情報を、DOM レベル 2 コア 仕様 [DOM Level 2
Core]から参照して頂きたい。
NodeIterator
とTreeWalker
は、ドキュメントサブツリーのノードおよびそれらの存在する位置を表すための、2つの異なる方法である。
NodeIterator
はサブツリーのフラットなビューを、ドキュメント順序に表れる、ノードの順序付きシーケンスとして提供する。このビューが階層構造を考慮せずに表現されるため、反復子が前後に移動するメソッドをもつが、上下に移動するものをもたないためである。
逆に、TreeWalker
はサブツリーにおける階層構造関係を維持し、この階層構造におけるナビゲーションを可能にする。
一般的に、TreeWalker
は選択されたノード周りのドキュメント構造を操作する仕事には向いており、
NodeIterator
は選択されたノードのそれぞれの内容に焦点を当てた仕事に向いている。
NodeIterator
とTreeWalkers
はそれぞれ、ドキュメントサブツリーのビューを、そのサブツリー中で発見される全てのノードは含まない形で表現する。
この仕様では、これを論理ビュー と表現し、そのままのドキュメントサブツリーに該当する物理ビュー とは区別する。
反復子またはTreeWalker
が生成されたとき、それは
ノードフィルタと関連付けられていても良い。これはそれぞれのノードについて検証し、それが論理ビューの中で出現しても良いかどうかを決定する。さらに、どのノードタイプが論理ビューの中で発生して良いかを指定するフラグも用いられうる。
NodeIterator
とTreeWalker
は動的である - 論理ビューはもとのドキュメントに加えられた変更を反映する。
ただし、これらは、それらの変更にどう反応するかという点で異なるものになる。
ノードをシーケンシャルに表現するNodeIterator,
は、そのシーケンスの内容が変化したときに、そのシーケンスにおける相対位置を維持するよう試みる。
ノードをフィルタされたツリーとして表現するTreeWalkerでは、
カレントノードからの相対位置を維持し、もしそれが新しいコンテキストに移動した時は、ノードをそれに繋げたままにする。以下で、それらの動作をもっと深く論じる。
NodeIteratorNodeIterator
はノードのリストのメンバーがシーケンシャルに返されることを可能にする。
現在のDOMインターフェースでは、このリストは常にドキュメント順序で出現するサブツリーのノードからなる。
最初に反復子が生成された時にそのnextNode()メソッドを呼び出すと、そのサブツリーの論理ビューにおける最初のノードを返す。多くの場合、それはサブツリーのルートである。
それぞれの呼び出しで成功したものはNodeIteratorをリスト中で先に進め、論理ビューの中で次に有効なノードを返す。
それ以上ノードが見つからない場合は、nextNode()はnullを返す。
NodeIterator
はDocumentTraversalインターフェースにあるcreateNodeIterator メソッドを用いて生成される。
NodeIterator
が生成される時、ツリーのトラバース中にどのノードタイプが「見え」てどのノードが「見えない」かを決定するフラグが用いられうる。これらのフラグはOR演算子を用いて結合されうる。
「見えない」ノードは、まるで存在しなかったかのように、その反復子からは飛ばされる。
以下のコードは反復子を生成してから、それぞれのエレメント名を出力する関数を呼び出す:
NodeIterator iter=
((DocumentTraversal)document).createNodeIterator(
root, NodeFilter.SHOW_ELEMENT, null);
while (Node n = iter.nextNode())
printMe(n);
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
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
最後に、NodeIteratorの
root ノードをそのparent から削除しても、
反復子を指定されたリストを変更するものではなく、反復子の状態を変更するものでもないことに注意。
反復子を指定されるデータ構造は論理ビューの一部とならないノードを含んでも良く、従ってそれらは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"を返さない。
ノードフィルタノードフィルタ
は、ユーザーが「フィルタされた」ノードのオブジェクトを生成することを可能にする。
各フィルタには、ノードを探してそれがドキュメントのトラバースの論理ビューの一部として出現してよいかどうかを決定するような、ユーザー定義の関数が含まれる。
NodeFilterを使うためには、
そのフィルタを使うようなNodeIterator
あるいはTreeWalker
を生成しなければならない。
トラバースエンジンはフィルタをそれぞれのノードに適用し、もしフィルタがそのノードを受容しない場合は、トラバースは、そのノードがドキュメント中に存在しなかったかのようにスキップする。
ノードフィルタ
では、処理されたノードを含む構造がどのようにナビゲートされたかを知る必要はない。
フィルタはトラバース操作が実行されたとき、あるいは
NodeIterator
の参照ノードが、反復子を指定された、新しいものを選ばなければならないようなサブツリーから削除されたときに設計される。
しかし、これらのフィルタの呼び出しの正確なタイミングはDOMインプリメンテーションによって異なりうる。
そのため、ノードフィルタ
では、過去の呼び出しの履歴に基づく状態を維持しようとすべきではない。
その結果の動作には互換性がないであろう。
同様に、TreeWalker
とNodeIterator
は過去のフィルタリングの結果のためのメモリなど持たないように動作するべきであり、
将来の結果の予測もすべきではない。
もし
NodeFilter
が検証したある状態が、そのトラバースロジックがこのノードを検証した最後の状態から変化した(たとえばそれが検証する属性が追加あるいは削除された)場合、
この可視状態の変化は次のトラバース命令が実行された時にのみ発覚する。
たとえば: もしカレントノードに対するフィルタリングが
FILTER_SHOW から FILTER_SKIPに変わった場合、
TreeWalker
はそのノードをどの方向からのナビゲートも遮断することができるが、そのフィルタリング状態がもう一度変化しない限りこれは反映されない。
トラバース中に変化するノードフィルタ
を書くこともできるが、その動作は混乱しやすいものであり、可能なら回避されるべきものである。
ノードフィルタの使用ノードフィルタ は、NodeIterator あるいはTreeWalker がノード をフィルタに渡し、それが論理ビュー中に出現するかどうかを問い合わせるための、acceptNode()という名前のメソッドをもつ。
acceptNode()関数は、そのノード がどのように扱われるかを表す3つの値のうちの1つを返す。
acceptNode() が
FILTER_ACCEPTを返す場合、そのノード は論理ビュー中に出現する。FILTER_SKIPを返す場合、そのノード は論理ビュー中には出現しないが、そのNode の子は出現してもよい。FILTER_REJECTを返す場合、そのノード もその子孫 も論理ビュー中には出現しない。
反復子がノードを順序付きリストとして階層構造なしに表すため、FILTER_REJECT と
FILTER_SKIP はNodeIteratorsにとっては同義語となり、単一のカレントノードのみをスキップする。
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_REJECT を
FILTER_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 のテストをフィルタから削除することができるとしたら、それはwhatToShow が
ElementsとAttrとProcessingInstructionsを区別するということに基づいている。
ノードフィルタ
と例外ノードフィルタを書くとき、ユーザーは例外を投げることが出来るようなコードを回避すべきである。
しかしながら、DOMインプリメンテーションは投げられる例外を妨げることはできないので、例外を投げるフィルタの動作がしっかり定義されたものであることが重要である。
TreeWalker
あるいはNodeIterator
はフィルタから投げられる例外をキャッチしたり置き換えたりはしないが、それをユーザーのコードまで伝播するようにする。以下の関数は
NodeFilterを呼び出すかもしれず、もしフィルタによって投げられた例外があればそれを伝播する:
NodeIterator
.nextNode()NodeIterator
.previousNode()TreeWalker
.firstChild()TreeWalker
.lastChild()TreeWalker
.nextSibling()TreeWalker
.previousSibling()TreeWalker
.nextNode()TreeWalker
.previousNode()TreeWalker
.parentNode()ノードフィルタ
とドキュメントの変更良く設計された
ノードフィルタ
はドキュメントの構造を変更すべきではない。
しかしDOMインプリメンテーションは、ユーザーがドキュメント構造を変化させるようなフィルタのコードを書くことを防ぐことができない。
トラバースはこのケースを扱うための特別な処理を提供しない。
たとえば、もしノードフィルタ
がノードをドキュメント中から削除する場合、これはなおそのノードを受容することができる。これは、それがもはやサブツリー中でトラバースされているとしても、NodeIterator
あるいはTreeWalker
によって返されてよいということを意味する。
一般的に、これは矛盾した、混乱した結果を導きうる。そのため、我々はユーザーが
ドキュメント構造に変更を加えないようなノードフィルタ
を書くことを推奨している。この代わりに、トラバースオブジェクトによって制御されるループ中で編集を行ってほしい。
ノードフィルタ
と whatToShow フラグNodeIterator
およびTreeWalker
は、フィルタを適用する前に、それらのwhatToShow フラグを適用する。
もしノードがアクティブなwhatToShow フラグによってスキップされた場合、
ノードフィルタ
はそのノードを評価するためには呼び出されない。
この動作はFILTER_SKIPのそれに類似しているということに注意していただきたい。 そのノードの子は考慮され、フィルタはそれらを評価するために呼び出されうる。これは、たとえその ノードフィルタ
がサブツリー全体を拒絶する方を選んだとしても、実際には「スキップ」となることにも注意。
これがアプリケーションで問題となる場合、
whatToShow を SHOW_ALL にセットして
nodeType のテストをそのフィルタの中で実行するとよい。
TreeWalkerTreeWalker
インターフェースは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 ノードを、親がいないにもかかわらず、あたかもそれらが兄弟
であるかのように表す。
NodeIteratorsと同様、
TreeWalker
はそのナビゲートするデータ構造が編集される間はアクティブであってもよく、
その変更を考慮して動作しなければならない。
現存のデータ構造に対する追加および削除は
TreeWalkerを無効にしない; 実際のところでも、TreeWalkerは絶対に無効化されない。
しかしこれらの変更に対するTreeWalkerの
反応は NodeIterator
におけるそれとは全く異なる。
NodeIterators
がそのリスト中の反復子の位置の維持によって編集行為に反応するのに対して、TreeWalkers
はそのcurrentNodeをそこに残したままにしておく。
TreeWalker
の全てのナビゲーションメソッドは、
TreeWalker
がアクセスされた最後の時点から、そのノードおよびその周辺に何が起ころうとも、
呼び出されたときのcurrentNodeのコンテキストに基づいて指令する。
これはたとえcurrentNode がオリジナルのサブツリーの外側に移動したとしても成り立つ。
例として、次のようなドキュメントフラグメントを考えてみる:
...
<subtree>
<twRoot>
<currentNode/>
<anotherNode/>
</twRoot>
</subtree>
...
ここで、root ノードが <twRoot/> エレメントでありcurrentNode が <currentNode/> エレメントとなるような
TreeWalker
を生成したとしよう。
この図から、上記の全ノードはこの
TreeWalkerの
whatToShow とフィルタ設定から受容されているとみなす。
もし <currentNode/> エレメントをその親 から削除するためにremoveChild() を用いた場合、たとえroot ノードのサブツリー内に存在しないとしても、 そのエレメントはTreeWalkerの
currentNodeであり続ける。
これでもまだTreeWalker
を使って、孤児となったcurrentNode が持っているあらゆる子をナビゲートすることができるが、もはや利用可能な親 が存在しないため、currentNode の外側にナビゲートすることはできない。
もしinsertBefore() あるいはappendChild() を用いて、その<currentNode/> に新しい親 を与えた場合、
TreeWalker
ナビゲーションはcurrentNodeの新しいロケーションから指令する。
たとえば、もし<currentNode/>を
<anotherNode/> エレメントのすぐ後に追加した場合、 このTreeWalkerの
previousSibling() 指令はこれを <anotherNode/>に戻し、parentNode() の呼び出しは <twRoot/>に移動する。
もし次のようにcurrentNode を <subtree/> エレメントに追加した場合:
...
<subtree>
<currentNode/>
<twRoot>
<anotherNode/>
</twRoot>
</subtree>
...
currentNode は TreeWalkerの
root ノードの下から移動した。これは
TreeWalkerを無効化してはいない; これはまだcurrentNodeから相対的にナビゲートするために用いられうる。
たとえばこれのparentNode()命令の呼び出しは、
それもまたオリジナルのroot ノードの外側にあるのであるが、
そのウォーカーを <subtree/> エレメントまで移動する。
しかし、もしこのTreeWalkerの
ナビゲーションがオリジナルのrootノードのサブツリーまで戻されなければならない場合 -- たとえばparentNode() ではなくnextNode()を呼び出して、TreeWalker
を <twRoot/> エレメントまで移動した場合 -- root ノードはTreeWalkerを「もう一度捕獲」し、トラバースから手を引くのを防ぐ。
これはフィルタが使用された場合に、さらに少々複雑になる。
currentNodeの移転 -- あるいは新しいcurrentNodeの明示的な選択、あるいはNodeFilter
がその決定に基づいているような状態の変更
-- は、TreeWalker
が、フィルタされた(論理上の)ドキュメントのビューにおいて不可視となるようなcurrentNode を持つ結果となってもよい。
このノードはそのビューにおける「変遷メンバー(transient view)」であると考えてもよい。
TreeWalker
にこのノードをナビゲートから外すことを頼む場合、その結果はあたかもそれが可視であるかのようであるが、これをもう一度可視にするような状態変化がない限り、これにナビゲーションを戻すことはできない。
特に: もしこのcurrentNode がフィルタによって拒絶されるようなサブツリーの一部となった場合、そのサブツリー全体がその論理ビューにおける変遷メンバーとして追加される。
かつて拒絶された祖先まで移動する間は、そのサブツリー中をナビゲートすることができる(通常の全てのフィルタリングには従う)。
その動作はあたかも、そこから離れるまでは、拒絶されたノードが単にスキップされたかのようになる(そのサブツリー内で曲がりくねりながらも進むことになるのである)。そして、標準のフィルタリングが適用される。この辺りは難解で、いまいち上手く翻訳し切れていないです。)
反復子 はノードのセットの間をステップするために用いる。たとえば、NodeList中のノードのセット、特定のNodeに結びつけられたドキュメントサブツリー、クエリの結果、あるいはその他のノードのセットなどがある。
反復子を指定されるノードのセットはNodeIteratorの実装によって決定される。
DOM レベル 2 では、ドキュメント順序でドキュメントサブツリーをトラバースするための単一のNodeIteratorの実装を規定している。
これらの反復子のインスタンスはDocumentTraversal.createNodeIterator()を呼び出すことによって生成される。
// 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型, readonlywhatToShow やフィルタよりも優先する事に注意。
また、これは現在では、NodeIterators が個別のノードをスキップするのではなく完全なサブツリーを拒絶する、唯一のシチュエーションであるということにも注意。whatToShow フラグを用いてそのエンティティ参照ノードを隠し、そしてこの反復子を生成するときにexpandEntityReferences をtrueに設定する。
エンティティ参照ノードをもつがエンティティを展開しないようなドキュメントのビューを作り出すためには、whatToShow フラグを用いてエンティティ参照ノードを表示し、かつexpandEntityReferences をfalseにする。filter NodeFilter型,
readonlyNodeFilter。root
Node型, readonlyNodeIterator のルートノード。whatToShow
unsigned long型, readonlyNodeFilter
インターフェースで定義されている。
whatToShow で受容されなかったノードはスキップされるが、それらの子はなお検証の対象となる。このスキップはフィルタよりも優先適用されることに注意。detachNodeIterator を、反復子を指定されているセットから切り離し、計算中のリソースを解放してその反復子を INVALID 状態にする。
detach が呼び出された後は、nextNode あるいは previousNode の呼び出しは例外 INVALID_STATE_ERR を発生させる。
nextNodeNodeIterator が生成された後は、nextNode() の最初の呼び出しは、そのセット中で最初のノードを返す。
|
|
そのセット中で反復子を指定される次の |
|
|
INVALID_STATE_ERR: このメソッドが、 |
previousNodeNodeIteratorの位置をそのセットの中で前に戻す。
|
|
そのセット中で反復子を指定される前の |
|
|
INVALID_STATE_ERR: このメソッドが、 |
フィルタはどのようにノードを「フィルタアウトするか」を知るオブジェクトである。NodeIterator
あるいは TreeWalker
にNodeFilterが与えられると、それは次のノードを返す前にこのフィルタを適用する。
もしこのフィルタがそのノードを受容すると言うのであれば、トラバースロジックはそれを返し、そうでなければトラバースは次のノードを探し、その拒絶されたノードはそこには存在しなかったかのように装う。
DOM は何らフィルタを提供しない。
NodeFilter は、ユーザーが実装して自身のフィルタを生成することができるような、単なるインターフェースである。
NodeFilters はどのようにノードからノードにトラバースするかを知る必要はないし、トラバースされることになるデータ構造について何ら知っている必要もない。知らなければならないのは単一のノードをどのように評価するかということだけなので、これはフィルタを非常に記述し易くしている。
1つのフィルタは多くのトラバースに用いられてもよく、コードの再利用を促進している。
// 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() メソッドによって返される:
FILTER_ACCEPTNodeIterator
あるいは TreeWalker
で定義されたナビゲーションメソッドはこのノードを返す。FILTER_REJECTNodeIterator
あるいは TreeWalker
で定義されたナビゲーションメソッドはこのノードを返さない。
TreeWalker,
については、このノードの子もまた拒絶される。
NodeIterators
はこれをFILTER_SKIPと同様に扱う。FILTER_SKIPNodeIterator
あるいは TreeWalker
で定義されたナビゲーションメソッドはこのノードを返さない。
NodeIterator
と TreeWalker
の両方とも、そのノードの子はなお検証の対象となる。これらはTreeWalkers
および NodeIterators
で利用されるwhatToShow
パラメータの有効な値となる。
これらはNodeの有効なタイプのセットと同様であり、それらの値は
同じノードタイプのnodeType で該当する値のビット位置を用いて派生される。
もしwhatToShow のビットがfalseにセットされた場合、それはこのタイプのノードがスキップされるよう要求されていることを表す。その場合の動作はFILTER_SKIPのそれと同様である。
もし32種類以上のノードタイプが導入された場合、それらはそれぞれを
whatToShowを通じてテストすることができない。
もしそのようなニーズが生じた場合、それはSHOW_ALL の選択と適切なNodeFilterによって扱われることで可能になる。
SHOW_ALLNodesを表示する。SHOW_ATTRIBUTEAttr ノードを表示する。
これは反復子あるいはツリーウォーカーの生成時に、属性値をその
rootとして指定した場合にのみ有効である。この場合、それはその属性ノードがその反復子あるいはトラバースの最初の位置に出現することを表す。
属性は他のノードの子にはなりえないので、それらはドキュメントツリーのトラバース中に出現することはない。SHOW_CDATA_SECTIONCDATASection ノードを表示する。SHOW_COMMENTComment ノードを表示する。SHOW_DOCUMENTDocument ノードを表示する。SHOW_DOCUMENT_FRAGMENTDocumentFragment ノードを表示する。SHOW_DOCUMENT_TYPEDocumentType ノードを表示する。SHOW_ELEMENTElement ノードを表示する。SHOW_ENTITYEntity ノードを表示する。
これは反復子あるいはツリーウォーカーを、Entity
ノードをそのrootとして生成した場合にのみ有効である。
この場合、これはこの
Entity ノードがトラバースの最初の位置に出現することを意味する。
エンティティはドキュメントツリーの一部ではないため、それらはドキュメントツリーのトラバース中に出現することはない。SHOW_ENTITY_REFERENCEEntityReference ノードを表示する。SHOW_NOTATIONNotation ノードを表示する。
これは反復子あるいはツリーウォーカーを、Notation
ノードをそのrootとして生成した場合にのみ有効である。
この場合、これはこの
Notation ノードがトラバースの最初の位置に出現することを意味する。
ノーテーションはドキュメントツリーの一部ではないため、それらはドキュメントツリーのトラバース中に出現することはない。SHOW_PROCESSING_INSTRUCTIONProcessingInstruction ノードを表示する。SHOW_TEXTText ノードを表示する。acceptNodeTreeWalker
あるいは NodeIterator
の論理ビューについて可視であるかどうかをテストする。
この関数はTreeWalker
および NodeIteratorの実装によって呼び出される。
これは通常ユーザーのコードからは直接呼び出されない。(ただ、同じフィルタを用いてアプリケーションロジックをガイドしたいというのであれば、それは可能である。)
n
Node型|
|
そのノードが受容されるか、拒絶されるか、スキップされるかを判別する定数。 上記の定義の通り。 |
TreeWalker オブジェクトはドキュメントツリーあるいはサブツリーを、whatToShow フラグと(もしあれば)フィルタとによって定義されたドキュメントのビューを用いてナビゲートするために用いられる。
TreeWalkerを用いたナビゲーションを実行する関数は、TreeWalkerで定義されたビューをサポートする。
サブツリーの論理ビューからノードを省略した結果は、同じサブツリーの、完全な、フィルタされていないドキュメントとは全く異なる構造となってもよい。
TreeWalker 上で兄弟となっているものは、異なった、オリジナルビューにおけるばらばらのノードの子でありうる。
たとえば、Textノード以外の全てをスキップするようなNodeFilterと、ドキュメントのルートノードについて考えてみよう。
その結果の論理ビューでは、全てのテキストノードが兄弟 であり、たとえオリジナルドキュメントの構造中でどれだけ深い位置に存在していたとしても、そのルートノードの直下に出現する。
// 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 が現在位置しているノード。TreeWalkerに関連付けられたフィルタによって受容されなくなるようになるかもしれない。
currentNode はそれがroot ノードによって指定されたサブツリー中に存在するかしないか、あるいはフィルタやwhatToShow フラグによって受容されるかどうか、といったことに関わりなく、明示的に任意のノードに指定されうる。
それ以上の解析は、リクエストされた方向でそのフィルタを適用された結果たとえcurrentNodeがカレントビューの一部でなくなったとしても、このcurrentNodeからの相対で発生する。
もし有効なトラバースが存在しない場合は、currentNode は変更されない。|
|
NOT_SUPPORTED_ERR: |
expandEntityReferences
boolean型, readonlyTreeWalkerから可視とされるかどうかを決定する。
falseであれば、それらとそれらの子孫 は拒絶される。
この拒絶はwhatToShow および(もしあれば)フィルタより優先適用されることに注意。whatToShow フラグをもちいてエンティティ参照ノードを隠し、TreeWalkerの生成時にexpandEntityReferences をtrueにセットすればよい。
エンティティ参照ノードを持つがエンティティは展開しないようなドキュメントのビューを作り出すためには、
whatToShow フラグを用いてエンティティ参照ノードを表示し、expandEntityReferences をfalseにセットすればよい。filter
NodeFilter型,
readonlyroot
Node型, readonlyTreeWalkerのroot ノード。whatToShow
unsigned long型, readonlyTreeWalkerを通して出現するかを決定する。有効な定数のセットはNodeFilter インターフェースで定義されている。
whatToShow で受容されないノードはスキップされるが、それらの子はなお検証の対象となる。このスキップは(もしあれば)フィルタより優先適用されることに注意。firstChildTreeWalker をカレントノード中の最初の可視の子 に移動し、その新しいノードを返す。
もしカレントノードが可視の子をもたない場合はnullを返し、カレントノードを維持する。
|
|
新しいノード、あるいはもしカレントノードが |
lastChildTreeWalker をカレントノード中の最後の可視の子 に移動し、その新しいノードを返す。
もしカレントノードが可視の子をもたない場合はnullを返し、カレントノードを維持する。
|
|
新しいノード、あるいはもしカレントノードが |
nextNodeTreeWalker をドキュメント順序でカレントノードから相対的に次にある可視ノードに移動し、新しいノードを返す。もしカレントノードに次のノードがない場合、あるいはnextNodeの検索がTreeWalkerのroot ノードより上に移動しようとした場合は、nullを返し、カレントノードを維持する。
|
|
新しいノード、あるいはもしカレントノードが |
nextSiblingparentNodepreviousNodeTreeWalker をドキュメント順序でカレントノードから相対的に前にある可視ノードに移動し、新しいノードを返す。もしカレントノードに次のノードがない場合、あるいはpreviousNodeの検索がTreeWalkerのroot ノードより上に移動しようとした場合は、nullを返し、カレントノードを維持する。
|
|
新しいノード、あるいはもしカレントノードが |
previousSiblingDocumentTraversal は反復子とツリーウォーカーを生成してノードおよびその子をドキュメント順序でトラバースするメソッドを含む(最初の深さで、ドキュメントのテキスト表現において開始タグが出現した順序に等しい順序の規定されたトラバースとなる)。
Traversal featureをサポートするDOMでは、DocumentTraversal
はDocumentインターフェースを実装しているものと同じオブジェクトによって実装される。
// 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);
};
createNodeIteratorNodeIteratorを生成する。
root
Node型whatToShow フラグおよび(もしあれば)フィルタは、この位置をセットする際には考慮されない。ルートはnullであってはならない。whatToShow
unsigned long型NodeFilter
の有効なSHOW_ の値のセットに関する説明を参照。ORを用いて結合されうる。filter
NodeFilter型TreeWalker(NodeIteratorでは?)で用いられる
NodeFilter
、あるいはフィルタを指定しない場合はnull。entityReferenceExpansion
boolean型|
新たに生成された |
|
|
NOT_SUPPORTED_ERR: 指定された |
createTreeWalkerTreeWalkerを生成する。
root
Node型TreeWalker
のrootとして使用されるノード。
whatToShow フラグおよびNodeFilter
はこの値を設定するときには考慮されない。いかなるタイプのノードもrootとして許容される。
TreeWalker
のcurrentNodeは、それが可視であるかないかを問わず、このノードに初期化される。
root はparentNode あるいは nextNode のようなドキュメント構造を上に探すようなトラバースメソッドにおいて、ストップ位置として機能する。
root はnullであってはならない。whatToShow
unsigned long型NodeFilter
の有効なSHOW_ の値に関する説明を参照。ORを用いて結合されうる。filter
NodeFilter型TreeWalkerで使用されるNodeFilter、あるいはフィルタを指定しない場合はnull。entityReferenceExpansion
boolean型EntityReference ノードの内容は論理ビュー中で出現しない。|
新しく生成された |
|
|
NOT_SUPPORTED_ERR: 指定された |