KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sun > org > apache > xerces > internal > dom > NodeIteratorImpl


1 /*
2  * The Apache Software License, Version 1.1
3  *
4  *
5  * Copyright (c) 1999-2002 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 com.sun.org.apache.xerces.internal.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  * @version $Id: NodeIteratorImpl.java,v 1.11 2002/11/06 22:58:28 elena Exp $
77  */

78 public class NodeIteratorImpl implements NodeIterator {
79     
80     //
81
// Data
82
//
83

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

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

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

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

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

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

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

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

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

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

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

334         // end of list, return null
335
return null;
336     }
337     
338     /** The method previousNode(Node) returns the previous node
339      * from the actual DOM tree.
340      */

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

374     public void removeNode(Node JavaDoc node) {
375         
376         // Implementation note: Fix-up means setting the current node properly
377
// after a remove.
378

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