KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > xerces > dom > NodeIteratorImpl


1 /*
2  * Copyright 1999-2002,2004 The Apache Software Foundation.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16
17 package org.apache.xerces.dom;
18
19 import org.w3c.dom.DOMException JavaDoc;
20 import org.w3c.dom.Node JavaDoc;
21 import org.w3c.dom.traversal.NodeFilter;
22 import org.w3c.dom.traversal.NodeIterator;
23
24
25 /** DefaultNodeIterator implements a NodeIterator, which iterates a
26  * DOM tree in the expected depth first way.
27  *
28  * <p>The whatToShow and filter functionality is implemented as expected.
29  *
30  * <p>This class also has method removeNode to enable iterator "fix-up"
31  * on DOM remove. It is expected that the DOM implementation call removeNode
32  * right before the actual DOM transformation. If not called by the DOM,
33  * the client could call it before doing the removal.
34  *
35  * @xerces.internal
36  *
37  * @version $Id: NodeIteratorImpl.java,v 1.13 2004/10/05 17:12:49 mrglavas Exp $
38  */

39 public class NodeIteratorImpl implements NodeIterator {
40     
41     //
42
// Data
43
//
44

45     /** The DocumentImpl which created this iterator, so it can be detached. */
46     private DocumentImpl fDocument;
47     /** The root. */
48     private Node JavaDoc fRoot;
49     /** The whatToShow mask. */
50     private int fWhatToShow = NodeFilter.SHOW_ALL;
51     /** The NodeFilter reference. */
52     private NodeFilter fNodeFilter;
53     /** If detach is called, the fDetach flag is true, otherwise flase. */
54     private boolean fDetach = false;
55     
56     //
57
// Iterator state - current node and direction.
58
//
59
// Note: The current node and direction are sufficient to implement
60
// the desired behaviour of the current pointer being _between_
61
// two nodes. The fCurrentNode is actually the last node returned,
62
// and the
63
// direction is whether the pointer is in front or behind this node.
64
// (usually akin to whether the node was returned via nextNode())
65
// (eg fForward = true) or previousNode() (eg fForward = false).
66
// Note also, if removing a Node, the fCurrentNode
67
// can be placed on a Node which would not pass filters.
68

69     /** The last Node returned. */
70     private Node JavaDoc fCurrentNode;
71     
72     /** The direction of the iterator on the fCurrentNode.
73      * <pre>
74      * nextNode() == fForward = true;
75      * previousNode() == fForward = false;
76      * </pre>
77      */

78     private boolean fForward = true;
79     
80     /** When TRUE, the children of entites references are returned in the iterator. */
81     private boolean fEntityReferenceExpansion;
82     
83     //
84
// Constructor
85
//
86

87     /** Public constructor */
88     public NodeIteratorImpl( DocumentImpl document,
89                              Node JavaDoc root,
90                              int whatToShow,
91                              NodeFilter nodeFilter,
92                              boolean entityReferenceExpansion) {
93         fDocument = document;
94         fRoot = root;
95         fCurrentNode = null;
96         fWhatToShow = whatToShow;
97         fNodeFilter = nodeFilter;
98         fEntityReferenceExpansion = entityReferenceExpansion;
99     }
100     
101     public Node JavaDoc getRoot() {
102     return fRoot;
103     }
104
105     // Implementation Note: Note that the iterator looks at whatToShow
106
// and filter values at each call, and therefore one _could_ add
107
// setters for these values and alter them while iterating!
108

109     /** Return the whatToShow value */
110     public int getWhatToShow() {
111         return fWhatToShow;
112     }
113
114     /** Return the filter */
115     public NodeFilter getFilter() {
116         return fNodeFilter;
117     }
118     
119     /** Return whether children entity references are included in the iterator. */
120     public boolean getExpandEntityReferences() {
121         return fEntityReferenceExpansion;
122     }
123             
124     /** Return the next Node in the Iterator. The node is the next node in
125      * depth-first order which also passes the filter, and whatToShow.
126      * If there is no next node which passes these criteria, then return null.
127      */

128     public Node JavaDoc nextNode() {
129         
130         if( fDetach) {
131             throw new DOMException JavaDoc(
132             DOMException.INVALID_STATE_ERR,
133                 DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "INVALID_STATE_ERR", null));
134         }
135         
136         // if root is null there is no next node.
137
if (fRoot == null) return null;
138         
139         Node JavaDoc nextNode = fCurrentNode;
140         boolean accepted = false; // the next node has not been accepted.
141

142         accepted_loop:
143         while (!accepted) {
144             
145             // if last direction is not forward, repeat node.
146
if (!fForward && nextNode!=null) {
147                 //System.out.println("nextNode():!fForward:"+fCurrentNode.getNodeName());
148
nextNode = fCurrentNode;
149             } else {
150             // else get the next node via depth-first
151
if (!fEntityReferenceExpansion
152                     && nextNode != null
153                     && nextNode.getNodeType() == Node.ENTITY_REFERENCE_NODE) {
154                     nextNode = nextNode(nextNode, false);
155                 } else {
156                     nextNode = nextNode(nextNode, true);
157                 }
158             }
159    
160             fForward = true; //REVIST: should direction be set forward before null check?
161

162             // nothing in the list. return null.
163
if (nextNode == null) return null;
164             
165             // does node pass the filters and whatToShow?
166
accepted = acceptNode(nextNode);
167             if (accepted) {
168                 // if so, then the node is the current node.
169
fCurrentNode = nextNode;
170                 return fCurrentNode;
171             } else
172                 continue accepted_loop;
173             
174         } // while (!accepted) {
175

176         // no nodes, or no accepted nodes.
177
return null;
178             
179     }
180     
181     /** Return the previous Node in the Iterator. The node is the next node in
182      * _backwards_ depth-first order which also passes the filter, and whatToShow.
183      */

184     public Node JavaDoc previousNode() {
185         
186         if( fDetach) {
187             throw new DOMException JavaDoc(
188             DOMException.INVALID_STATE_ERR,
189                 DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "INVALID_STATE_ERR", null));
190         }
191  
192         // if the root is null, or the current node is null, return null.
193
if (fRoot == null || fCurrentNode == null) return null;
194        
195         Node JavaDoc previousNode = fCurrentNode;
196         boolean accepted = false;
197         
198         accepted_loop:
199         while (!accepted) {
200             
201             if (fForward && previousNode != null) {
202                 //repeat last node.
203
previousNode = fCurrentNode;
204             } else {
205                 // get previous node in backwards depth first order.
206
previousNode = previousNode(previousNode);
207             }
208             
209             // we are going backwards
210
fForward = false;
211             
212             // if the new previous node is null, we're at head or past the root,
213
// so return null.
214
if (previousNode == null) return null;
215             
216             // check if node passes filters and whatToShow.
217
accepted = acceptNode(previousNode);
218             if (accepted) {
219                 // if accepted, update the current node, and return it.
220
fCurrentNode = previousNode;
221                 return fCurrentNode;
222             } else
223                 continue accepted_loop;
224         }
225         // there are no nodes?
226
return null;
227     }
228                 
229     /** The node is accepted if it passes the whatToShow and the filter. */
230     boolean acceptNode(Node JavaDoc node) {
231                 
232         if (fNodeFilter == null) {
233             return ( fWhatToShow & (1 << node.getNodeType()-1)) != 0 ;
234         } else {
235             return ((fWhatToShow & (1 << node.getNodeType()-1)) != 0 )
236                 && fNodeFilter.acceptNode(node) == NodeFilter.FILTER_ACCEPT;
237         }
238     }
239     
240     /** Return node, if matches or any parent if matches. */
241     Node JavaDoc matchNodeOrParent(Node JavaDoc node) {
242         // Additions and removals in the underlying data structure may occur
243
// before any iterations, and in this case the reference_node is null.
244
if (fCurrentNode == null) return null;
245         
246         // check if the removed node is an _ancestor_ of the
247
// reference node
248
for (Node JavaDoc n = fCurrentNode; n != fRoot; n = n.getParentNode()) {
249             if (node == n) return n;
250         }
251         return null;
252     }
253     
254     /** The method nextNode(Node, boolean) returns the next node
255      * from the actual DOM tree.
256      *
257      * The boolean visitChildren determines whether to visit the children.
258      * The result is the nextNode.
259      */

260     Node JavaDoc nextNode(Node JavaDoc node, boolean visitChildren) {
261             
262         if (node == null) return fRoot;
263
264         Node JavaDoc result;
265         // only check children if we visit children.
266
if (visitChildren) {
267             //if hasChildren, return 1st child.
268
if (node.hasChildNodes()) {
269                 result = node.getFirstChild();
270                 return result;
271             }
272         }
273             
274         if (node == fRoot) { //if Root has no kids
275
return null;
276         }
277
278         // if hasSibling, return sibling
279
result = node.getNextSibling();
280         if (result != null) return result;
281         
282                 
283         // return parent's 1st sibling.
284
Node JavaDoc parent = node.getParentNode();
285         while (parent != null && parent != fRoot) {
286             result = parent.getNextSibling();
287             if (result != null) {
288                 return result;
289             } else {
290                 parent = parent.getParentNode();
291             }
292                             
293         } // while (parent != null && parent != fRoot) {
294

295         // end of list, return null
296
return null;
297     }
298     
299     /** The method previousNode(Node) returns the previous node
300      * from the actual DOM tree.
301      */

302     Node JavaDoc previousNode(Node JavaDoc node) {
303         
304         Node JavaDoc result;
305         
306         // if we're at the root, return null.
307
if (node == fRoot) return null;
308         
309         // get sibling
310
result = node.getPreviousSibling();
311         if (result == null) {
312             //if 1st sibling, return parent
313
result = node.getParentNode();
314             return result;
315         }
316         
317         // if sibling has children, keep getting last child of child.
318
if (result.hasChildNodes()
319             && !(!fEntityReferenceExpansion
320                 && result != null
321                 && result.getNodeType() == Node.ENTITY_REFERENCE_NODE))
322        
323         {
324             while (result.hasChildNodes()) {
325                 result = result.getLastChild();
326             }
327         }
328             
329         return result;
330     }
331     
332     /** Fix-up the iterator on a remove. Called by DOM or otherwise,
333      * before an actual DOM remove.
334      */

335     public void removeNode(Node JavaDoc node) {
336         
337         // Implementation note: Fix-up means setting the current node properly
338
// after a remove.
339

340         if (node == null) return;
341         
342         Node JavaDoc deleted = matchNodeOrParent(node);
343         
344         if (deleted == null) return;
345         
346         if (fForward) {
347             fCurrentNode = previousNode(deleted);
348         } else
349         // if (!fForward)
350
{
351             Node JavaDoc next = nextNode(deleted, false);
352             if (next!=null) {
353                 // normal case: there _are_ nodes following this in the iterator.
354
fCurrentNode = next;
355             } else {
356                 // the last node in the iterator is to be removed,
357
// so we set the current node to be the previous one.
358
fCurrentNode = previousNode(deleted);
359                 fForward = true;
360             }
361                 
362         }
363         
364     }
365     
366     public void detach() {
367         fDetach = true;
368         fDocument.removeNodeIterator(this);
369     }
370     
371 }
372
Popular Tags