KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > enhydra > apache > 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.enhydra.apache.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
66 /** DefaultNodeIterator implements a NodeIterator, which iterates a
67  * DOM tree in the expected depth first way.
68  *
69  * <p>The whatToShow and filter functionality is implemented as expected.
70  *
71  * <p>This class also has method removeNode to enable iterator "fix-up"
72  * on DOM remove. It is expected that the DOM implementation call removeNode
73  * right before the actual DOM transformation. If not called by the DOM,
74  * the client could call it before doing the removal.
75  */

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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