KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > xquark > xpath > datamodel > xerces > dom > NodeIteratorImpl


1 /*
2  * The Apache Software License, Version 1.1
3  *
4  *
5  * Copyright (c) 1999 The Apache Software Foundation. All rights
6  * reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright
13  * notice, this list of conditions and the following disclaimer.
14  *
15  * 2. Redistributions in binary form must reproduce the above copyright
16  * notice, this list of conditions and the following disclaimer in
17  * the documentation and/or other materials provided with the
18  * distribution.
19  *
20  * 3. The end-user documentation included with the redistribution,
21  * if any, must include the following acknowledgment:
22  * "This product includes software developed by the
23  * Apache Software Foundation (http://www.apache.org/)."
24  * Alternately, this acknowledgment may appear in the software itself,
25  * if and wherever such third-party acknowledgments normally appear.
26  *
27  * 4. The names "Xerces" and "Apache Software Foundation" must
28  * not be used to endorse or promote products derived from this
29  * software without prior written permission. For written
30  * permission, please contact apache@apache.org.
31  *
32  * 5. Products derived from this software may not be called "Apache",
33  * nor may "Apache" appear in their name, without prior written
34  * permission of the Apache Software Foundation.
35  *
36  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
37  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
38  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
39  * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
40  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
41  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
42  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
43  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
44  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
45  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
46  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
47  * SUCH DAMAGE.
48  * ====================================================================
49  *
50  * This software consists of voluntary contributions made by many
51  * individuals on behalf of the Apache Software Foundation and was
52  * originally based on software copyright (c) 1999, International
53  * Business Machines, Inc., http://www.apache.org. For more
54  * information on the Apache Software Foundation, please see
55  * <http://www.apache.org/>.
56  */

57
58 package org.xquark.xpath.datamodel.xerces.dom;
59
60 import org.w3c.dom.DOMException JavaDoc;
61 import org.w3c.dom.Node JavaDoc;
62 import org.w3c.dom.traversal.NodeFilter;
63 import org.w3c.dom.traversal.NodeIterator;
64
65 /** DefaultNodeIterator implements a NodeIterator, which iterates a
66  * DOM tree in the expected depth first way.
67  *
68  * <p>The whatToShow and filter functionality is implemented as expected.
69  *
70  * <p>This class also has method removeNode to enable iterator "fix-up"
71  * on DOM remove. It is expected that the DOM implementation call removeNode
72  * right before the actual DOM transformation. If not called by the DOM,
73  * the client could call it before doing the removal.
74  */

75 public class NodeIteratorImpl implements NodeIterator {
76     
77     //
78
// Data
79
//
80

81     /** The DocumentImpl which created this iterator, so it can be detached. */
82     private DocumentImpl fDocument;
83     /** The root. */
84     private Node JavaDoc fRoot;
85     /** The whatToShow mask. */
86     private int fWhatToShow = NodeFilter.SHOW_ALL;
87     /** The NodeFilter reference. */
88     private NodeFilter fNodeFilter;
89     /** If detach is called, the fDetach flag is true, otherwise flase. */
90     private boolean fDetach = false;
91     
92     //
93
// Iterator state - current node and direction.
94
//
95
// Note: The current node and direction are sufficient to implement
96
// the desired behaviour of the current pointer being _between_
97
// two nodes. The fCurrentNode is actually the last node returned,
98
// and the
99
// direction is whether the pointer is in front or behind this node.
100
// (usually akin to whether the node was returned via nextNode())
101
// (eg fForward = true) or previousNode() (eg fForward = false).
102
// Note also, if removing a Node, the fCurrentNode
103
// can be placed on a Node which would not pass filters.
104

105     /** The last Node returned. */
106     private Node JavaDoc fCurrentNode;
107     
108     /** The direction of the iterator on the fCurrentNode.
109      * <pre>
110      * nextNode() == fForward = true;
111      * previousNode() == fForward = false;
112      * </pre>
113      */

114     private boolean fForward = true;
115     
116     /** When TRUE, the children of entites references are returned in the iterator. */
117     private boolean fEntityReferenceExpansion;
118     
119     //
120
// Constructor
121
//
122

123     /** Public constructor */
124     public NodeIteratorImpl( DocumentImpl document,
125                              Node JavaDoc root,
126                              int whatToShow,
127                              NodeFilter nodeFilter,
128                              boolean entityReferenceExpansion) {
129         fDocument = document;
130         fRoot = root;
131         fCurrentNode = null;
132         fWhatToShow = whatToShow;
133         fNodeFilter = nodeFilter;
134         fEntityReferenceExpansion = entityReferenceExpansion;
135     }
136     
137     public Node JavaDoc getRoot() {
138     return fRoot;
139     }
140
141     // Implementation Note: Note that the iterator looks at whatToShow
142
// and filter values at each call, and therefore one _could_ add
143
// setters for these values and alter them while iterating!
144

145     /** Return the whatToShow value */
146     public int getWhatToShow() {
147         return fWhatToShow;
148     }
149
150     /** Return the filter */
151     public NodeFilter getFilter() {
152         return fNodeFilter;
153     }
154     
155     /** Return whether children entity references are included in the iterator. */
156     public boolean getExpandEntityReferences() {
157         return fEntityReferenceExpansion;
158     }
159             
160     /** Return the next Node in the Iterator. The node is the next node in
161      * depth-first order which also passes the filter, and whatToShow.
162      * If there is no next node which passes these criteria, then return null.
163      */

164     public Node JavaDoc nextNode() {
165         
166         if( fDetach) {
167             throw new DOMException JavaDoc(
168                 DOMException.INVALID_STATE_ERR,
169             "DOM011 Invalid state");
170         }
171         
172         // if root is null there is no next node.
173
if (fRoot == null) return null;
174         
175         Node JavaDoc nextNode = fCurrentNode;
176         boolean accepted = false; // the next node has not been accepted.
177

178         accepted_loop:
179         while (!accepted) {
180             
181             // if last direction is not forward, repeat node.
182
if (!fForward && nextNode!=null) {
183                 //System.out.println("nextNode():!fForward:"+fCurrentNode.getNodeName());
184
nextNode = fCurrentNode;
185             } else {
186             // else get the next node via depth-first
187
if (!fEntityReferenceExpansion
188                     && nextNode != null
189                     && nextNode.getNodeType() == Node.ENTITY_REFERENCE_NODE) {
190                     nextNode = nextNode(nextNode, false);
191                 } else {
192                     nextNode = nextNode(nextNode, true);
193                 }
194             }
195    
196             fForward = true; //REVIST: should direction be set forward before null check?
197

198             // nothing in the list. return null.
199
if (nextNode == null) return null;
200             
201             // does node pass the filters and whatToShow?
202
accepted = acceptNode(nextNode);
203             if (accepted) {
204                 // if so, then the node is the current node.
205
fCurrentNode = nextNode;
206                 return fCurrentNode;
207             } else
208                 continue accepted_loop;
209             
210         } // while (!accepted) {
211

212         // no nodes, or no accepted nodes.
213
return null;
214             
215     }
216     
217     /** Return the previous Node in the Iterator. The node is the next node in
218      * _backwards_ depth-first order which also passes the filter, and whatToShow.
219      */

220     public Node JavaDoc previousNode() {
221         
222         if( fDetach) {
223             throw new DOMException JavaDoc(
224                 DOMException.INVALID_STATE_ERR,
225             "DOM011 Invalid state");
226         }
227  
228         // if the root is null, or the current node is null, return null.
229
if (fRoot == null || fCurrentNode == null) return null;
230        
231         Node JavaDoc previousNode = fCurrentNode;
232         boolean accepted = false;
233         
234         accepted_loop:
235         while (!accepted) {
236             
237             if (fForward && previousNode != null) {
238                 //repeat last node.
239
previousNode = fCurrentNode;
240             } else {
241                 // get previous node in backwards depth first order.
242
previousNode = previousNode(previousNode);
243             }
244             
245             // we are going backwards
246
fForward = false;
247             
248             // if the new previous node is null, we're at head or past the root,
249
// so return null.
250
if (previousNode == null) return null;
251             
252             // check if node passes filters and whatToShow.
253
accepted = acceptNode(previousNode);
254             if (accepted) {
255                 // if accepted, update the current node, and return it.
256
fCurrentNode = previousNode;
257                 return fCurrentNode;
258             } else
259                 continue accepted_loop;
260         }
261         // there are no nodes?
262
return null;
263     }
264                 
265     /** The node is accepted if it passes the whatToShow and the filter. */
266     boolean acceptNode(Node JavaDoc node) {
267                 
268         if (fNodeFilter == null) {
269             return ( fWhatToShow & (1 << node.getNodeType()-1)) != 0 ;
270         } else {
271             return ((fWhatToShow & (1 << node.getNodeType()-1)) != 0 )
272                 && fNodeFilter.acceptNode(node) == NodeFilter.FILTER_ACCEPT;
273         }
274     }
275     
276     /** Return node, if matches or any parent if matches. */
277     Node JavaDoc matchNodeOrParent(Node JavaDoc node) {
278         for (Node JavaDoc n = node; n != fRoot; n = n.getParentNode()) {
279             if (node == n) return n;
280         }
281         return null;
282     }
283     
284     /** The method nextNode(Node, boolean) returns the next node
285      * from the actual DOM tree.
286      *
287      * The boolean visitChildren determines whether to visit the children.
288      * The result is the nextNode.
289      */

290     Node JavaDoc nextNode(Node JavaDoc node, boolean visitChildren) {
291             
292         if (node == null) return fRoot;
293
294         Node JavaDoc result;
295         // only check children if we visit children.
296
if (visitChildren) {
297             //if hasChildren, return 1st child.
298
if (node.hasChildNodes()) {
299                 result = node.getFirstChild();
300                 return result;
301             }
302         }
303             
304         if (node == fRoot) { //if Root has no kids
305
return null;
306         }
307
308         // if hasSibling, return sibling
309
result = node.getNextSibling();
310         if (result != null) return result;
311         
312                 
313         // return parent's 1st sibling.
314
Node JavaDoc parent = node.getParentNode();
315         while (parent != null && parent != fRoot) {
316             result = parent.getNextSibling();
317             if (result != null) {
318                 return result;
319             } else {
320                 parent = parent.getParentNode();
321             }
322                             
323         } // while (parent != null && parent != fRoot) {
324

325         // end of list, return null
326
return null;
327     }
328     
329     /** The method previousNode(Node) returns the previous node
330      * from the actual DOM tree.
331      */

332     Node JavaDoc previousNode(Node JavaDoc node) {
333         
334         Node JavaDoc result;
335         
336         // if we're at the root, return null.
337
if (node == fRoot) return null;
338         
339         // get sibling
340
result = node.getPreviousSibling();
341         if (result == null) {
342             //if 1st sibling, return parent
343
result = node.getParentNode();
344             return result;
345         }
346         
347         // if sibling has children, keep getting last child of child.
348
if (result.hasChildNodes()
349             && !(!fEntityReferenceExpansion
350                 && result != null
351                 && result.getNodeType() == Node.ENTITY_REFERENCE_NODE))
352        
353         {
354             while (result.hasChildNodes()) {
355                 result = result.getLastChild();
356             }
357         }
358             
359         return result;
360     }
361     
362     /** Fix-up the iterator on a remove. Called by DOM or otherwise,
363      * before an actual DOM remove.
364      */

365     public void removeNode(Node JavaDoc node) {
366         
367         // Implementation note: Fix-up means setting the current node properly
368
// after a remove.
369

370         if (node == null) return;
371         
372         Node JavaDoc deleted = matchNodeOrParent(node);
373         
374         if (deleted == null) return;
375         
376         if (fForward) {
377             fCurrentNode = previousNode(deleted);
378         } else
379         // if (!fForward)
380
{
381             Node JavaDoc next = nextNode(deleted, false);
382             if (next!=null) {
383                 // normal case: there _are_ nodes following this in the iterator.
384
fCurrentNode = next;
385             } else {
386                 // the last node in the iterator is to be removed,
387
// so we set the current node to be the previous one.
388
fCurrentNode = previousNode(deleted);
389                 fForward = true;
390             }
391                 
392         }
393         
394     }
395     
396     public void detach() {
397         fDetach = true;
398         fDocument.removeNodeIterator(this);
399     }
400     
401 }
402
Popular Tags