1/*
2 * reserved comment block
3 * DO NOT REMOVE OR ALTER!
4 */
5/*
6 * Licensed to the Apache Software Foundation (ASF) under one or more
7 * contributor license agreements.  See the NOTICE file distributed with
8 * this work for additional information regarding copyright ownership.
9 * The ASF licenses this file to You under the Apache License, Version 2.0
10 * (the "License"); you may not use this file except in compliance with
11 * the License.  You may obtain a copy of the License at
12 *
13 *      http://www.apache.org/licenses/LICENSE-2.0
14 *
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
20 */
21
22package com.sun.org.apache.xerces.internal.dom;
23
24import org.w3c.dom.DOMException;
25import org.w3c.dom.Node;
26import org.w3c.dom.traversal.NodeFilter;
27import org.w3c.dom.traversal.TreeWalker;
28
29/** This class implements the TreeWalker interface.
30 *
31 * @xerces.internal
32 *
33 */
34
35public class TreeWalkerImpl implements TreeWalker {
36
37    //
38    // Data
39    //
40
41    /** When TRUE, the children of entites references are returned in the iterator. */
42    private boolean fEntityReferenceExpansion = false;
43    /** The whatToShow mask. */
44    int fWhatToShow = NodeFilter.SHOW_ALL;
45    /** The NodeFilter reference. */
46    NodeFilter fNodeFilter;
47    /** The current Node. */
48    Node fCurrentNode;
49    /** The root Node. */
50    Node fRoot;
51
52    //
53    // Implementation Note: No state is kept except the data above
54    // (fWhatToShow, fNodeFilter, fCurrentNode, fRoot) such that
55    // setters could be created for these data values and the
56    // implementation will still work.
57
58
59    //
60    // Constructor
61    //
62
63    /** Public constructor */
64    public TreeWalkerImpl(Node root,
65                          int whatToShow,
66                          NodeFilter nodeFilter,
67                          boolean entityReferenceExpansion) {
68        fCurrentNode = root;
69        fRoot = root;
70        fWhatToShow = whatToShow;
71        fNodeFilter = nodeFilter;
72        fEntityReferenceExpansion = entityReferenceExpansion;
73    }
74
75    public Node getRoot() {
76        return fRoot;
77    }
78
79    /** Return the whatToShow value */
80    public int                getWhatToShow() {
81        return fWhatToShow;
82    }
83
84    public void setWhatShow(int whatToShow){
85        fWhatToShow = whatToShow;
86    }
87    /** Return the NodeFilter */
88    public NodeFilter         getFilter() {
89        return fNodeFilter;
90    }
91
92    /** Return whether children entity references are included in the iterator. */
93    public boolean            getExpandEntityReferences() {
94        return fEntityReferenceExpansion;
95    }
96
97    /** Return the current Node. */
98    public Node               getCurrentNode() {
99        return fCurrentNode;
100    }
101    /** Return the current Node. */
102    public void               setCurrentNode(Node node) {
103        if (node == null) {
104            String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NOT_SUPPORTED_ERR", null);
105              throw new DOMException(DOMException.NOT_SUPPORTED_ERR, msg);
106        }
107
108        fCurrentNode = node;
109    }
110
111    /** Return the parent Node from the current node,
112     *  after applying filter, whatToshow.
113     *  If result is not null, set the current Node.
114     */
115    public Node               parentNode() {
116
117        if (fCurrentNode == null) return null;
118
119        Node node = getParentNode(fCurrentNode);
120        if (node !=null) {
121            fCurrentNode = node;
122        }
123        return node;
124
125    }
126
127    /** Return the first child Node from the current node,
128     *  after applying filter, whatToshow.
129     *  If result is not null, set the current Node.
130     */
131    public Node               firstChild() {
132
133        if (fCurrentNode == null) return null;
134
135        Node node = getFirstChild(fCurrentNode);
136        if (node !=null) {
137            fCurrentNode = node;
138        }
139        return node;
140    }
141    /** Return the last child Node from the current node,
142     *  after applying filter, whatToshow.
143     *  If result is not null, set the current Node.
144     */
145    public Node               lastChild() {
146
147        if (fCurrentNode == null) return null;
148
149        Node node = getLastChild(fCurrentNode);
150        if (node !=null) {
151            fCurrentNode = node;
152        }
153        return node;
154    }
155
156    /** Return the previous sibling Node from the current node,
157     *  after applying filter, whatToshow.
158     *  If result is not null, set the current Node.
159     */
160    public Node               previousSibling() {
161
162        if (fCurrentNode == null) return null;
163
164        Node node = getPreviousSibling(fCurrentNode);
165        if (node !=null) {
166            fCurrentNode = node;
167        }
168        return node;
169    }
170
171    /** Return the next sibling Node from the current node,
172     *  after applying filter, whatToshow.
173     *  If result is not null, set the current Node.
174     */
175    public Node               nextSibling(){
176        if (fCurrentNode == null) return null;
177
178        Node node = getNextSibling(fCurrentNode);
179        if (node !=null) {
180            fCurrentNode = node;
181        }
182        return node;
183    }
184
185    /** Return the previous Node from the current node,
186     *  after applying filter, whatToshow.
187     *  If result is not null, set the current Node.
188     */
189    public Node               previousNode() {
190        Node result;
191
192        if (fCurrentNode == null) return null;
193
194        // get sibling
195        result = getPreviousSibling(fCurrentNode);
196        if (result == null) {
197            result = getParentNode(fCurrentNode);
198            if (result != null) {
199                fCurrentNode = result;
200                return fCurrentNode;
201            }
202            return null;
203        }
204
205        // get the lastChild of result.
206        Node lastChild  = getLastChild(result);
207
208        Node prev = lastChild ;
209        while (lastChild != null) {
210          prev = lastChild ;
211          lastChild = getLastChild(prev) ;
212        }
213
214        lastChild = prev ;
215
216        // if there is a lastChild which passes filters return it.
217        if (lastChild != null) {
218            fCurrentNode = lastChild;
219            return fCurrentNode;
220        }
221
222        // otherwise return the previous sibling.
223        if (result != null) {
224            fCurrentNode = result;
225            return fCurrentNode;
226        }
227
228        // otherwise return null.
229        return null;
230    }
231
232    /** Return the next Node from the current node,
233     *  after applying filter, whatToshow.
234     *  If result is not null, set the current Node.
235     */
236    public Node               nextNode() {
237
238        if (fCurrentNode == null) return null;
239
240        Node result = getFirstChild(fCurrentNode);
241
242        if (result != null) {
243            fCurrentNode = result;
244            return result;
245        }
246
247        result = getNextSibling(fCurrentNode);
248
249        if (result != null) {
250            fCurrentNode = result;
251            return result;
252        }
253
254        // return parent's 1st sibling.
255        Node parent = getParentNode(fCurrentNode);
256        while (parent != null) {
257            result = getNextSibling(parent);
258            if (result != null) {
259                fCurrentNode = result;
260                return result;
261            } else {
262                parent = getParentNode(parent);
263            }
264        }
265
266        // end , return null
267        return null;
268    }
269
270    /** Internal function.
271     *  Return the parent Node, from the input node
272     *  after applying filter, whatToshow.
273     *  The current node is not consulted or set.
274     */
275    Node getParentNode(Node node) {
276
277        if (node == null || node == fRoot) return null;
278
279        Node newNode = node.getParentNode();
280        if (newNode == null)  return null;
281
282        int accept = acceptNode(newNode);
283
284        if (accept == NodeFilter.FILTER_ACCEPT)
285            return newNode;
286        else
287        //if (accept == NodeFilter.SKIP_NODE) // and REJECT too.
288        {
289            return getParentNode(newNode);
290        }
291
292
293    }
294
295    /** Internal function.
296     *  Return the nextSibling Node, from the input node
297     *  after applying filter, whatToshow.
298     *  The current node is not consulted or set.
299     */
300    Node getNextSibling(Node node) {
301                return getNextSibling(node, fRoot);
302        }
303
304    /** Internal function.
305     *  Return the nextSibling Node, from the input node
306     *  after applying filter, whatToshow.
307     *  NEVER TRAVERSES ABOVE THE SPECIFIED ROOT NODE.
308     *  The current node is not consulted or set.
309     */
310    Node getNextSibling(Node node, Node root) {
311
312        if (node == null || node == root) return null;
313
314        Node newNode = node.getNextSibling();
315        if (newNode == null) {
316
317            newNode = node.getParentNode();
318
319            if (newNode == null || newNode == root)  return null;
320
321            int parentAccept = acceptNode(newNode);
322
323            if (parentAccept==NodeFilter.FILTER_SKIP) {
324                return getNextSibling(newNode, root);
325            }
326
327            return null;
328        }
329
330        int accept = acceptNode(newNode);
331
332        if (accept == NodeFilter.FILTER_ACCEPT)
333            return newNode;
334        else
335        if (accept == NodeFilter.FILTER_SKIP) {
336            Node fChild = getFirstChild(newNode);
337            if (fChild == null) {
338                return getNextSibling(newNode, root);
339            }
340            return fChild;
341        }
342        else
343        //if (accept == NodeFilter.REJECT_NODE)
344        {
345            return getNextSibling(newNode, root);
346        }
347
348    } // getNextSibling(Node node) {
349
350    /** Internal function.
351     *  Return the previous sibling Node, from the input node
352     *  after applying filter, whatToshow.
353     *  The current node is not consulted or set.
354     */
355    Node getPreviousSibling(Node node) {
356                return getPreviousSibling(node, fRoot);
357        }
358
359    /** Internal function.
360     *  Return the previousSibling Node, from the input node
361     *  after applying filter, whatToshow.
362         *  NEVER TRAVERSES ABOVE THE SPECIFIED ROOT NODE.
363     *  The current node is not consulted or set.
364     */
365    Node getPreviousSibling(Node node, Node root) {
366
367        if (node == null || node == root) return null;
368
369        Node newNode = node.getPreviousSibling();
370        if (newNode == null) {
371
372            newNode = node.getParentNode();
373            if (newNode == null || newNode == root)  return null;
374
375            int parentAccept = acceptNode(newNode);
376
377            if (parentAccept==NodeFilter.FILTER_SKIP) {
378                return getPreviousSibling(newNode, root);
379            }
380
381            return null;
382        }
383
384        int accept = acceptNode(newNode);
385
386        if (accept == NodeFilter.FILTER_ACCEPT)
387            return newNode;
388        else
389        if (accept == NodeFilter.FILTER_SKIP) {
390            Node fChild =  getLastChild(newNode);
391            if (fChild == null) {
392                return getPreviousSibling(newNode, root);
393            }
394            return fChild;
395        }
396        else
397        //if (accept == NodeFilter.REJECT_NODE)
398        {
399            return getPreviousSibling(newNode, root);
400        }
401
402    } // getPreviousSibling(Node node) {
403
404    /** Internal function.
405     *  Return the first child Node, from the input node
406     *  after applying filter, whatToshow.
407     *  The current node is not consulted or set.
408     */
409    Node getFirstChild(Node node) {
410        if (node == null) return null;
411
412        if ( !fEntityReferenceExpansion
413             && node.getNodeType() == Node.ENTITY_REFERENCE_NODE)
414            return null;
415        Node newNode = node.getFirstChild();
416        if (newNode == null)  return null;
417        int accept = acceptNode(newNode);
418
419        if (accept == NodeFilter.FILTER_ACCEPT)
420            return newNode;
421        else
422        if (accept == NodeFilter.FILTER_SKIP
423            && newNode.hasChildNodes())
424        {
425            Node fChild = getFirstChild(newNode);
426
427            if (fChild == null) {
428                return getNextSibling(newNode, node);
429            }
430            return fChild;
431        }
432        else
433        //if (accept == NodeFilter.REJECT_NODE)
434        {
435            return getNextSibling(newNode, node);
436        }
437
438
439    }
440
441    /** Internal function.
442     *  Return the last child Node, from the input node
443     *  after applying filter, whatToshow.
444     *  The current node is not consulted or set.
445     */
446    Node getLastChild(Node node) {
447
448        if (node == null) return null;
449
450        if ( !fEntityReferenceExpansion
451             && node.getNodeType() == Node.ENTITY_REFERENCE_NODE)
452            return null;
453
454        Node newNode = node.getLastChild();
455        if (newNode == null)  return null;
456
457        int accept = acceptNode(newNode);
458
459        if (accept == NodeFilter.FILTER_ACCEPT)
460            return newNode;
461        else
462        if (accept == NodeFilter.FILTER_SKIP
463            && newNode.hasChildNodes())
464        {
465            Node lChild = getLastChild(newNode);
466            if (lChild == null) {
467                return getPreviousSibling(newNode, node);
468            }
469            return lChild;
470        }
471        else
472        //if (accept == NodeFilter.REJECT_NODE)
473        {
474            return getPreviousSibling(newNode, node);
475        }
476
477
478    }
479
480    /** Internal function.
481     *  The node whatToShow and the filter are combined into one result. */
482    short acceptNode(Node node) {
483        /***
484         7.1.2.4. Filters and whatToShow flags
485
486         Iterator and TreeWalker apply whatToShow flags before applying Filters. If a node is rejected by the
487         active whatToShow flags, a Filter will not be called to evaluate that node. When a node is rejected by
488         the active whatToShow flags, children of that node will still be considered, and Filters may be called to
489         evaluate them.
490         ***/
491
492        if (fNodeFilter == null) {
493            if ( ( fWhatToShow & (1 << node.getNodeType()-1)) != 0) {
494                return NodeFilter.FILTER_ACCEPT;
495            } else {
496                return NodeFilter.FILTER_SKIP;
497            }
498        } else {
499            if ((fWhatToShow & (1 << node.getNodeType()-1)) != 0 ) {
500                return fNodeFilter.acceptNode(node);
501            } else {
502                // What to show has failed. See above excerpt from spec.
503                // Equivalent to FILTER_SKIP.
504                return NodeFilter.FILTER_SKIP;
505            }
506        }
507    }
508}
509