KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > xml > dtm > ref > DTMDefaultBaseTraversers


1 /*
2  * Copyright 1999-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  * $Id: DTMDefaultBaseTraversers.java,v 1.19 2004/02/16 23:06:11 minchau Exp $
18  */

19 package org.apache.xml.dtm.ref;
20
21 import org.apache.xml.dtm.*;
22
23 import javax.xml.transform.Source JavaDoc;
24
25 import org.apache.xml.utils.XMLStringFactory;
26
27 import org.apache.xml.res.XMLErrorResources;
28 import org.apache.xml.res.XMLMessages;
29
30
31 /**
32  * This class implements the traversers for DTMDefaultBase.
33  *
34  * PLEASE NOTE that the public interface for all traversers should be
35  * in terms of DTM Node Handles... but they may use the internal node
36  * identity indices within their logic, for efficiency's sake. Be very
37  * careful to avoid confusing these when maintaining this code.
38  * */

39 public abstract class DTMDefaultBaseTraversers extends DTMDefaultBase
40 {
41
42   /**
43    * Construct a DTMDefaultBaseTraversers object from a DOM node.
44    *
45    * @param mgr The DTMManager who owns this DTM.
46    * @param domSource the DOM source that this DTM will wrap.
47    * @param source The object that is used to specify the construction source.
48    * @param dtmIdentity The DTM identity ID for this DTM.
49    * @param whiteSpaceFilter The white space filter for this DTM, which may
50    * be null.
51    * @param xstringfactory The factory to use for creating XMLStrings.
52    * @param doIndexing true if the caller considers it worth it to use
53    * indexing schemes.
54    */

55   public DTMDefaultBaseTraversers(DTMManager mgr, Source JavaDoc source,
56                                   int dtmIdentity,
57                                   DTMWSFilter whiteSpaceFilter,
58                                   XMLStringFactory xstringfactory,
59                                   boolean doIndexing)
60   {
61     super(mgr, source, dtmIdentity, whiteSpaceFilter, xstringfactory,
62           doIndexing);
63   }
64
65   /**
66    * Construct a DTMDefaultBaseTraversers object from a DOM node.
67    *
68    * @param mgr The DTMManager who owns this DTM.
69    * @param domSource the DOM source that this DTM will wrap.
70    * @param source The object that is used to specify the construction source.
71    * @param dtmIdentity The DTM identity ID for this DTM.
72    * @param whiteSpaceFilter The white space filter for this DTM, which may
73    * be null.
74    * @param xstringfactory The factory to use for creating XMLStrings.
75    * @param doIndexing true if the caller considers it worth it to use
76    * indexing schemes.
77    * @param blocksize The block size of the DTM.
78    * @param usePrevsib true if we want to build the previous sibling node array.
79    * @param newNameTable true if we want to use a new ExpandedNameTable for this DTM.
80    */

81   public DTMDefaultBaseTraversers(DTMManager mgr, Source JavaDoc source,
82                                   int dtmIdentity,
83                                   DTMWSFilter whiteSpaceFilter,
84                                   XMLStringFactory xstringfactory,
85                                   boolean doIndexing,
86                                   int blocksize,
87                                   boolean usePrevsib,
88                                   boolean newNameTable)
89   {
90     super(mgr, source, dtmIdentity, whiteSpaceFilter, xstringfactory,
91           doIndexing, blocksize, usePrevsib, newNameTable);
92   }
93
94   /**
95    * This returns a stateless "traverser", that can navigate
96    * over an XPath axis, though perhaps not in document order.
97    *
98    * @param axis One of Axes.ANCESTORORSELF, etc.
99    *
100    * @return A DTMAxisTraverser, or null if the given axis isn't supported.
101    */

102   public DTMAxisTraverser getAxisTraverser(final int axis)
103   {
104
105     DTMAxisTraverser traverser;
106
107     if (null == m_traversers) // Cache of stateless traversers for this DTM
108
{
109       m_traversers = new DTMAxisTraverser[Axis.names.length];
110       traverser = null;
111     }
112     else
113     {
114       traverser = m_traversers[axis]; // Share/reuse existing traverser
115

116       if (traverser != null)
117         return traverser;
118     }
119
120     switch (axis) // Generate new traverser
121
{
122     case Axis.ANCESTOR :
123       traverser = new AncestorTraverser();
124       break;
125     case Axis.ANCESTORORSELF :
126       traverser = new AncestorOrSelfTraverser();
127       break;
128     case Axis.ATTRIBUTE :
129       traverser = new AttributeTraverser();
130       break;
131     case Axis.CHILD :
132       traverser = new ChildTraverser();
133       break;
134     case Axis.DESCENDANT :
135       traverser = new DescendantTraverser();
136       break;
137     case Axis.DESCENDANTORSELF :
138       traverser = new DescendantOrSelfTraverser();
139       break;
140     case Axis.FOLLOWING :
141       traverser = new FollowingTraverser();
142       break;
143     case Axis.FOLLOWINGSIBLING :
144       traverser = new FollowingSiblingTraverser();
145       break;
146     case Axis.NAMESPACE :
147       traverser = new NamespaceTraverser();
148       break;
149     case Axis.NAMESPACEDECLS :
150       traverser = new NamespaceDeclsTraverser();
151       break;
152     case Axis.PARENT :
153       traverser = new ParentTraverser();
154       break;
155     case Axis.PRECEDING :
156       traverser = new PrecedingTraverser();
157       break;
158     case Axis.PRECEDINGSIBLING :
159       traverser = new PrecedingSiblingTraverser();
160       break;
161     case Axis.SELF :
162       traverser = new SelfTraverser();
163       break;
164     case Axis.ALL :
165       traverser = new AllFromRootTraverser();
166       break;
167     case Axis.ALLFROMNODE :
168       traverser = new AllFromNodeTraverser();
169       break;
170     case Axis.PRECEDINGANDANCESTOR :
171       traverser = new PrecedingAndAncestorTraverser();
172       break;
173     case Axis.DESCENDANTSFROMROOT :
174       traverser = new DescendantFromRootTraverser();
175       break;
176     case Axis.DESCENDANTSORSELFFROMROOT :
177       traverser = new DescendantOrSelfFromRootTraverser();
178       break;
179     case Axis.ROOT :
180       traverser = new RootTraverser();
181       break;
182     case Axis.FILTEREDLIST :
183       return null; // Don't want to throw an exception for this one.
184
default :
185       throw new DTMException(XMLMessages.createXMLMessage(XMLErrorResources.ER_UNKNOWN_AXIS_TYPE, new Object JavaDoc[]{Integer.toString(axis)})); //"Unknown axis traversal type: "+axis);
186
}
187
188     if (null == traverser)
189       throw new DTMException(XMLMessages.createXMLMessage(XMLErrorResources.ER_AXIS_TRAVERSER_NOT_SUPPORTED, new Object JavaDoc[]{Axis.names[axis]}));
190       // "Axis traverser not supported: "
191
// + Axis.names[axis]);
192

193     m_traversers[axis] = traverser;
194
195     return traverser;
196   }
197
198   /**
199    * Implements traversal of the Ancestor access, in reverse document order.
200    */

201   private class AncestorTraverser extends DTMAxisTraverser
202   {
203
204     /**
205      * Traverse to the next node after the current node.
206      *
207      * @param context The context node if this iteration.
208      * @param current The current node of the iteration.
209      *
210      * @return the next node in the iteration, or DTM.NULL.
211      */

212     public int next(int context, int current)
213     {
214             return getParent(current);
215     }
216
217     /**
218      * Traverse to the next node after the current node that is matched
219      * by the expanded type ID.
220      *
221      * @param context The context node of this iteration.
222      * @param current The current node of the iteration.
223      * @param expandedTypeID The expanded type ID that must match.
224      *
225      * @return the next node in the iteration, or DTM.NULL.
226      */

227     public int next(int context, int current, int expandedTypeID)
228     {
229             // Process using identities
230
current = makeNodeIdentity(current);
231
232       while (DTM.NULL != (current = m_parent.elementAt(current)))
233       {
234         if (m_exptype.elementAt(current) == expandedTypeID)
235           return makeNodeHandle(current);
236       }
237
238       return NULL;
239     }
240   }
241
242   /**
243    * Implements traversal of the Ancestor access, in reverse document order.
244    */

245   private class AncestorOrSelfTraverser extends AncestorTraverser
246   {
247
248     /**
249      * By the nature of the stateless traversal, the context node can not be
250      * returned or the iteration will go into an infinate loop. To see if
251      * the self node should be processed, use this function.
252      *
253      * @param context The context node of this traversal.
254      *
255      * @return the first node in the traversal.
256      */

257     public int first(int context)
258     {
259       return context;
260     }
261
262     /**
263      * By the nature of the stateless traversal, the context node can not be
264      * returned or the iteration will go into an infinate loop. To see if
265      * the self node should be processed, use this function. If the context
266      * node does not match the expanded type ID, this function will return
267      * false.
268      *
269      * @param context The context node of this traversal.
270      * @param expandedTypeID The expanded type ID that must match.
271      *
272      * @return the first node in the traversal.
273      */

274     public int first(int context, int expandedTypeID)
275     {
276             return (getExpandedTypeID(context) == expandedTypeID)
277              ? context : next(context, context, expandedTypeID);
278     }
279   }
280
281   /**
282    * Implements traversal of the Attribute access
283    */

284   private class AttributeTraverser extends DTMAxisTraverser
285   {
286
287     /**
288      * Traverse to the next node after the current node.
289      *
290      * @param context The context node of this iteration.
291      * @param current The current node of the iteration.
292      *
293      * @return the next node in the iteration, or DTM.NULL.
294      */

295     public int next(int context, int current)
296     {
297       return (context == current)
298              ? getFirstAttribute(context) : getNextAttribute(current);
299     }
300
301     /**
302      * Traverse to the next node after the current node that is matched
303      * by the expanded type ID.
304      *
305      * @param context The context node of this iteration.
306      * @param current The current node of the iteration.
307      * @param expandedTypeID The expanded type ID that must match.
308      *
309      * @return the next node in the iteration, or DTM.NULL.
310      */

311     public int next(int context, int current, int expandedTypeID)
312     {
313
314       current = (context == current)
315                 ? getFirstAttribute(context) : getNextAttribute(current);
316
317       do
318       {
319         if (getExpandedTypeID(current) == expandedTypeID)
320           return current;
321       }
322       while (DTM.NULL != (current = getNextAttribute(current)));
323
324       return NULL;
325     }
326   }
327
328   /**
329    * Implements traversal of the Ancestor access, in reverse document order.
330    */

331   private class ChildTraverser extends DTMAxisTraverser
332   {
333     
334     /**
335      * Get the next indexed node that matches the expanded type ID. Before
336      * calling this function, one should first call
337      * {@link #isIndexed(int) isIndexed} to make sure that the index can
338      * contain nodes that match the given expanded type ID.
339      *
340      * @param axisRoot The root identity of the axis.
341      * @param nextPotential The node found must match or occur after this node.
342      * @param expandedTypeID The expanded type ID for the request.
343      *
344      * @return The node ID or NULL if not found.
345      */

346     protected int getNextIndexed(int axisRoot, int nextPotential,
347                                  int expandedTypeID)
348     {
349
350       int nsIndex = m_expandedNameTable.getNamespaceID(expandedTypeID);
351       int lnIndex = m_expandedNameTable.getLocalNameID(expandedTypeID);
352
353       for (; ; )
354       {
355         int nextID = findElementFromIndex(nsIndex, lnIndex, nextPotential);
356
357         if (NOTPROCESSED != nextID)
358         {
359           int parentID = m_parent.elementAt(nextID);
360           
361           // Is it a child?
362
if(parentID == axisRoot)
363             return nextID;
364           
365           // If the parent occured before the subtree root, then
366
// we know it is past the child axis.
367
if(parentID < axisRoot)
368               return NULL;
369           
370           // Otherwise, it could be a descendant below the subtree root
371
// children, or it could be after the subtree root. So we have
372
// to climb up until the parent is less than the subtree root, in
373
// which case we return NULL, or until it is equal to the subtree
374
// root, in which case we continue to look.
375
do
376           {
377             parentID = m_parent.elementAt(parentID);
378             if(parentID < axisRoot)
379               return NULL;
380           }
381             while(parentID > axisRoot);
382           
383           // System.out.println("Found node via index: "+first);
384
nextPotential = nextID+1;
385           continue;
386         }
387
388         nextNode();
389         
390         if(!(m_nextsib.elementAt(axisRoot) == NOTPROCESSED))
391           break;
392       }
393
394       return DTM.NULL;
395     }
396         
397     /**
398      * By the nature of the stateless traversal, the context node can not be
399      * returned or the iteration will go into an infinate loop. So to traverse
400      * an axis, the first function must be used to get the first node.
401      *
402      * <p>This method needs to be overloaded only by those axis that process
403      * the self node. <\p>
404      *
405      * @param context The context node of this traversal. This is the point
406      * that the traversal starts from.
407      * @return the first node in the traversal.
408      */

409     public int first(int context)
410     {
411       return getFirstChild(context);
412     }
413   
414     /**
415      * By the nature of the stateless traversal, the context node can not be
416      * returned or the iteration will go into an infinate loop. So to traverse
417      * an axis, the first function must be used to get the first node.
418      *
419      * <p>This method needs to be overloaded only by those axis that process
420      * the self node. <\p>
421      *
422      * @param context The context node of this traversal. This is the point
423      * of origin for the traversal -- its "root node" or starting point.
424      * @param expandedTypeID The expanded type ID that must match.
425      *
426      * @return the first node in the traversal.
427      */

428     public int first(int context, int expandedTypeID)
429     {
430       if(true)
431       {
432         int identity = makeNodeIdentity(context);
433         
434         int firstMatch = getNextIndexed(identity, _firstch(identity),
435                                  expandedTypeID);
436        
437         return makeNodeHandle(firstMatch);
438       }
439       else
440       {
441                 // %REVIEW% Dead code. Eliminate?
442
for (int current = _firstch(makeNodeIdentity(context));
443              DTM.NULL != current;
444              current = _nextsib(current))
445         {
446           if (m_exptype.elementAt(current) == expandedTypeID)
447               return makeNodeHandle(current);
448         }
449         return NULL;
450       }
451     }
452
453     /**
454      * Traverse to the next node after the current node.
455      *
456      * @param context The context node of this iteration.
457      * @param current The current node of the iteration.
458      *
459      * @return the next node in the iteration, or DTM.NULL.
460      */

461     public int next(int context, int current)
462     {
463       return getNextSibling(current);
464     }
465
466     /**
467      * Traverse to the next node after the current node that is matched
468      * by the expanded type ID.
469      *
470      * @param context The context node of this iteration.
471      * @param current The current node of the iteration.
472      * @param expandedTypeID The expanded type ID that must match.
473      *
474      * @return the next node in the iteration, or DTM.NULL.
475      */

476     public int next(int context, int current, int expandedTypeID)
477     {
478             // Process in Identifier space
479
for (current = _nextsib(makeNodeIdentity(current));
480            DTM.NULL != current;
481            current = _nextsib(current))
482       {
483         if (m_exptype.elementAt(current) == expandedTypeID)
484             return makeNodeHandle(current);
485       }
486       
487       return NULL;
488     }
489   }
490
491   /**
492    * Super class for derived classes that want a convenient way to access
493    * the indexing mechanism.
494    */

495   private abstract class IndexedDTMAxisTraverser extends DTMAxisTraverser
496   {
497
498     /**
499      * Tell if the indexing is on and the given expanded type ID matches
500      * what is in the indexes. Derived classes should call this before
501      * calling {@link #getNextIndexed(int, int, int) getNextIndexed} method.
502      *
503      * @param expandedTypeID The expanded type ID being requested.
504      *
505      * @return true if it is OK to call the
506      * {@link #getNextIndexed(int, int, int) getNextIndexed} method.
507      */

508     protected final boolean isIndexed(int expandedTypeID)
509     {
510       return (m_indexing
511               && ExpandedNameTable.ELEMENT
512                  == m_expandedNameTable.getType(expandedTypeID));
513     }
514
515     /**
516      * Tell if a node is outside the axis being traversed. This method must be
517      * implemented by derived classes, and must be robust enough to handle any
518      * node that occurs after the axis root.
519      *
520      * @param axisRoot The root identity of the axis.
521      * @param identity The node in question.
522      *
523      * @return true if the given node falls outside the axis being traversed.
524      */

525     protected abstract boolean isAfterAxis(int axisRoot, int identity);
526
527     /**
528      * Tell if the axis has been fully processed to tell if a the wait for
529      * an arriving node should terminate. This method must be implemented
530      * be a derived class.
531      *
532      * @param axisRoot The root identity of the axis.
533      *
534      * @return true if the axis has been fully processed.
535      */

536     protected abstract boolean axisHasBeenProcessed(int axisRoot);
537
538     /**
539      * Get the next indexed node that matches the expanded type ID. Before
540      * calling this function, one should first call
541      * {@link #isIndexed(int) isIndexed} to make sure that the index can
542      * contain nodes that match the given expanded type ID.
543      *
544      * @param axisRoot The root identity of the axis.
545      * @param nextPotential The node found must match or occur after this node.
546      * @param expandedTypeID The expanded type ID for the request.
547      *
548      * @return The node ID or NULL if not found.
549      */

550     protected int getNextIndexed(int axisRoot, int nextPotential,
551                                  int expandedTypeID)
552     {
553
554       int nsIndex = m_expandedNameTable.getNamespaceID(expandedTypeID);
555       int lnIndex = m_expandedNameTable.getLocalNameID(expandedTypeID);
556
557       while(true)
558       {
559         int next = findElementFromIndex(nsIndex, lnIndex, nextPotential);
560
561         if (NOTPROCESSED != next)
562         {
563           if (isAfterAxis(axisRoot, next))
564             return NULL;
565
566           // System.out.println("Found node via index: "+first);
567
return next;
568         }
569         else if(axisHasBeenProcessed(axisRoot))
570           break;
571
572         nextNode();
573       }
574
575       return DTM.NULL;
576     }
577   }
578
579   /**
580    * Implements traversal of the Ancestor access, in reverse document order.
581    */

582   private class DescendantTraverser extends IndexedDTMAxisTraverser
583   {
584     /**
585      * Get the first potential identity that can be returned. This should
586      * be overridded by classes that need to return the self node.
587      *
588      * @param identity The node identity of the root context of the traversal.
589      *
590      * @return The first potential node that can be in the traversal.
591      */

592     protected int getFirstPotential(int identity)
593     {
594       return identity + 1;
595     }
596     
597     /**
598      * Tell if the axis has been fully processed to tell if a the wait for
599      * an arriving node should terminate.
600      *
601      * @param axisRoot The root identity of the axis.
602      *
603      * @return true if the axis has been fully processed.
604      */

605     protected boolean axisHasBeenProcessed(int axisRoot)
606     {
607       return !(m_nextsib.elementAt(axisRoot) == NOTPROCESSED);
608     }
609     
610     /**
611      * Get the subtree root identity from the handle that was passed in by
612      * the caller. Derived classes may override this to change the root
613      * context of the traversal.
614      *
615      * @param handle handle to the root context.
616      * @return identity of the root of the subtree.
617      */

618     protected int getSubtreeRoot(int handle)
619     {
620       return makeNodeIdentity(handle);
621     }
622
623     /**
624      * Tell if this node identity is a descendant. Assumes that
625      * the node info for the element has already been obtained.
626      *
627      * %REVIEW% This is really parentFollowsRootInDocumentOrder ...
628      * which fails if the parent starts after the root ends.
629      * May be sufficient for this class's logic, but misleadingly named!
630      *
631      * @param subtreeRootIdentity The root context of the subtree in question.
632      * @param identity The index number of the node in question.
633      * @return true if the index is a descendant of _startNode.
634      */

635     protected boolean isDescendant(int subtreeRootIdentity, int identity)
636     {
637       return _parent(identity) >= subtreeRootIdentity;
638     }
639
640     /**
641      * Tell if a node is outside the axis being traversed. This method must be
642      * implemented by derived classes, and must be robust enough to handle any
643      * node that occurs after the axis root.
644      *
645      * @param axisRoot The root identity of the axis.
646      * @param identity The node in question.
647      *
648      * @return true if the given node falls outside the axis being traversed.
649      */

650     protected boolean isAfterAxis(int axisRoot, int identity)
651     {
652       // %REVIEW% Is there *any* cheaper way to do this?
653
// Yes. In ID space, compare to axisRoot's successor
654
// (next-sib or ancestor's-next-sib). Probably shallower search.
655
do
656       {
657         if(identity == axisRoot)
658           return false;
659         identity = m_parent.elementAt(identity);
660       }
661         while(identity >= axisRoot);
662         
663       return true;
664     }
665
666     /**
667      * By the nature of the stateless traversal, the context node can not be
668      * returned or the iteration will go into an infinate loop. So to traverse
669      * an axis, the first function must be used to get the first node.
670      *
671      * <p>This method needs to be overloaded only by those axis that process
672      * the self node. <\p>
673      *
674      * @param context The context node of this traversal. This is the point
675      * of origin for the traversal -- its "root node" or starting point.
676      * @param expandedTypeID The expanded type ID that must match.
677      *
678      * @return the first node in the traversal.
679      */

680     public int first(int context, int expandedTypeID)
681     {
682
683       if (isIndexed(expandedTypeID))
684       {
685         int identity = getSubtreeRoot(context);
686         int firstPotential = getFirstPotential(identity);
687
688         return makeNodeHandle(getNextIndexed(identity, firstPotential, expandedTypeID));
689       }
690
691       return next(context, context, expandedTypeID);
692     }
693
694     /**
695      * Traverse to the next node after the current node.
696      *
697      * @param context The context node of this iteration.
698      * @param current The current node of the iteration.
699      *
700      * @return the next node in the iteration, or DTM.NULL.
701      */

702     public int next(int context, int current)
703     {
704
705       int subtreeRootIdent = getSubtreeRoot(context);
706
707       for (current = makeNodeIdentity(current) + 1; ; current++)
708       {
709         int type = _type(current); // may call nextNode()
710

711         if (!isDescendant(subtreeRootIdent, current))
712           return NULL;
713
714         if (ATTRIBUTE_NODE == type || NAMESPACE_NODE == type)
715           continue;
716
717         return makeNodeHandle(current); // make handle.
718
}
719     }
720
721     /**
722      * Traverse to the next node after the current node that is matched
723      * by the expanded type ID.
724      *
725      * @param context The context node of this iteration.
726      * @param current The current node of the iteration.
727      * @param expandedTypeID The expanded type ID that must match.
728      *
729      * @return the next node in the iteration, or DTM.NULL.
730      */

731     public int next(int context, int current, int expandedTypeID)
732     {
733
734       int subtreeRootIdent = getSubtreeRoot(context);
735
736       current = makeNodeIdentity(current) + 1;
737
738       if (isIndexed(expandedTypeID))
739       {
740         return makeNodeHandle(getNextIndexed(subtreeRootIdent, current, expandedTypeID));
741       }
742
743       for (; ; current++)
744       {
745         int exptype = _exptype(current); // may call nextNode()
746

747         if (!isDescendant(subtreeRootIdent, current))
748           return NULL;
749
750         if (exptype != expandedTypeID)
751           continue;
752
753         return makeNodeHandle(current); // make handle.
754
}
755     }
756   }
757
758   /**
759    * Implements traversal of the Ancestor access, in reverse document order.
760    */

761   private class DescendantOrSelfTraverser extends DescendantTraverser
762   {
763
764     /**
765      * Get the first potential identity that can be returned, which is the
766      * axis context, in this case.
767      *
768      * @param identity The node identity of the root context of the traversal.
769      *
770      * @return The axis context.
771      */

772     protected int getFirstPotential(int identity)
773     {
774       return identity;
775     }
776
777     /**
778      * By the nature of the stateless traversal, the context node can not be
779      * returned or the iteration will go into an infinate loop. To see if
780      * the self node should be processed, use this function.
781      *
782      * @param context The context node of this traversal.
783      *
784      * @return the first node in the traversal.
785      */

786     public int first(int context)
787     {
788       return context;
789     }
790   }
791
792   /**
793    * Implements traversal of the entire subtree, including the root node.
794    */

795   private class AllFromNodeTraverser extends DescendantOrSelfTraverser
796   {
797
798     /**
799      * Traverse to the next node after the current node.
800      *
801      * @param context The context node of this iteration.
802      * @param current The current node of the iteration.
803      *
804      * @return the next node in the iteration, or DTM.NULL.
805      */

806     public int next(int context, int current)
807     {
808
809       int subtreeRootIdent = makeNodeIdentity(context);
810
811       for (current = makeNodeIdentity(current) + 1; ; current++)
812       {
813         // Trickological code: _exptype() has the side-effect of
814
// running nextNode until the specified node has been loaded,
815
// and thus can be used to ensure that incremental construction of
816
// the DTM has gotten this far. Using it just for that side-effect
817
// is quite a kluge...
818
_exptype(current); // make sure it's here.
819

820         if (!isDescendant(subtreeRootIdent, current))
821           return NULL;
822
823         return makeNodeHandle(current); // make handle.
824
}
825     }
826   }
827
828   /**
829    * Implements traversal of the following access, in document order.
830    */

831   private class FollowingTraverser extends DescendantTraverser
832   {
833
834     /**
835      * Get the first of the following.
836      *
837      * @param context The context node of this traversal. This is the point
838      * that the traversal starts from.
839      * @return the first node in the traversal.
840      */

841     public int first(int context)
842     {
843             // Compute in ID space
844
context=makeNodeIdentity(context);
845
846       int first;
847       int type = _type(context);
848
849       if ((DTM.ATTRIBUTE_NODE == type) || (DTM.NAMESPACE_NODE == type))
850       {
851         context = _parent(context);
852         first = _firstch(context);
853
854         if (NULL != first)
855           return makeNodeHandle(first);
856       }
857
858       do
859       {
860         first = _nextsib(context);
861
862         if (NULL == first)
863           context = _parent(context);
864       }
865       while (NULL == first && NULL != context);
866
867       return makeNodeHandle(first);
868     }
869
870     /**
871      * Get the first of the following.
872      *
873      * @param context The context node of this traversal. This is the point
874      * of origin for the traversal -- its "root node" or starting point.
875      * @param expandedTypeID The expanded type ID that must match.
876      *
877      * @return the first node in the traversal.
878      */

879     public int first(int context, int expandedTypeID)
880     {
881             // %REVIEW% This looks like it might want shift into identity space
882
// to avoid repeated conversion in the individual functions
883
int first;
884       int type = getNodeType(context);
885
886       if ((DTM.ATTRIBUTE_NODE == type) || (DTM.NAMESPACE_NODE == type))
887       {
888         context = getParent(context);
889         first = getFirstChild(context);
890
891         if (NULL != first)
892         {
893           if (getExpandedTypeID(first) == expandedTypeID)
894             return first;
895           else
896             return next(context, first, expandedTypeID);
897         }
898       }
899
900       do
901       {
902         first = getNextSibling(context);
903
904         if (NULL == first)
905           context = getParent(context);
906         else
907         {
908           if (getExpandedTypeID(first) == expandedTypeID)
909             return first;
910           else
911             return next(context, first, expandedTypeID);
912         }
913       }
914       while (NULL == first && NULL != context);
915
916       return first;
917     }
918
919     /**
920      * Traverse to the next node after the current node.
921      *
922      * @param context The context node of this iteration.
923      * @param current The current node of the iteration.
924      *
925      * @return the next node in the iteration, or DTM.NULL.
926      */

927     public int next(int context, int current)
928     {
929             // Compute in identity space
930
current=makeNodeIdentity(current);
931
932       while (true)
933       {
934         current++; // Only works on IDs, not handles.
935

936                 // %REVIEW% Are we using handles or indexes?
937
int type = _type(current); // may call nextNode()
938

939         if (NULL == type)
940           return NULL;
941
942         if (ATTRIBUTE_NODE == type || NAMESPACE_NODE == type)
943           continue;
944
945         return makeNodeHandle(current); // make handle.
946
}
947     }
948
949     /**
950      * Traverse to the next node after the current node that is matched
951      * by the expanded type ID.
952      *
953      * @param context The context node of this iteration.
954      * @param current The current node of the iteration.
955      * @param expandedTypeID The expanded type ID that must match.
956      *
957      * @return the next node in the iteration, or DTM.NULL.
958      */

959     public int next(int context, int current, int expandedTypeID)
960     {
961             // Compute in ID space
962
current=makeNodeIdentity(current);
963
964       while (true)
965       {
966         current++;
967
968         int etype = _exptype(current); // may call nextNode()
969

970         if (NULL == etype)
971           return NULL;
972
973         if (etype != expandedTypeID)
974           continue;
975
976         return makeNodeHandle(current); // make handle.
977
}
978     }
979   }
980
981   /**
982    * Implements traversal of the Ancestor access, in reverse document order.
983    */

984   private class FollowingSiblingTraverser extends DTMAxisTraverser
985   {
986
987     /**
988      * Traverse to the next node after the current node.
989      *
990      * @param context The context node of this iteration.
991      * @param current The current node of the iteration.
992      *
993      * @return the next node in the iteration, or DTM.NULL.
994      */

995     public int next(int context, int current)
996     {
997       return getNextSibling(current);
998     }
999
1000    /**
1001     * Traverse to the next node after the current node that is matched
1002     * by the expanded type ID.
1003     *
1004     * @param context The context node of this iteration.
1005     * @param current The current node of the iteration.
1006     * @param expandedTypeID The expanded type ID that must match.
1007     *
1008     * @return the next node in the iteration, or DTM.NULL.
1009     */

1010    public int next(int context, int current, int expandedTypeID)
1011    {
1012
1013      while (DTM.NULL != (current = getNextSibling(current)))
1014      {
1015        if (getExpandedTypeID(current) == expandedTypeID)
1016          return current;
1017      }
1018
1019      return NULL;
1020    }
1021  }
1022
1023  /**
1024   * Implements traversal of the Ancestor access, in reverse document order.
1025   */

1026  private class NamespaceDeclsTraverser extends DTMAxisTraverser
1027  {
1028
1029    /**
1030     * Traverse to the next node after the current node.
1031     *
1032     * @param context The context node of this iteration.
1033     * @param current The current node of the iteration.
1034     *
1035     * @return the next node in the iteration, or DTM.NULL.
1036     */

1037    public int next(int context, int current)
1038    {
1039
1040      return (context == current)
1041             ? getFirstNamespaceNode(context, false)
1042             : getNextNamespaceNode(context, current, false);
1043    }
1044
1045    /**
1046     * Traverse to the next node after the current node that is matched
1047     * by the expanded type ID.
1048     *
1049     * @param context The context node of this iteration.
1050     * @param current The current node of the iteration.
1051     * @param expandedTypeID The expanded type ID that must match.
1052     *
1053     * @return the next node in the iteration, or DTM.NULL.
1054     */

1055    public int next(int context, int current, int expandedTypeID)
1056    {
1057
1058      current = (context == current)
1059                ? getFirstNamespaceNode(context, false)
1060                : getNextNamespaceNode(context, current, false);
1061
1062      do
1063      {
1064        if (getExpandedTypeID(current) == expandedTypeID)
1065          return current;
1066      }
1067      while (DTM.NULL
1068             != (current = getNextNamespaceNode(context, current, false)));
1069
1070      return NULL;
1071    }
1072  }
1073
1074  /**
1075   * Implements traversal of the Ancestor access, in reverse document order.
1076   */

1077  private class NamespaceTraverser extends DTMAxisTraverser
1078  {
1079
1080    /**
1081     * Traverse to the next node after the current node.
1082     *
1083     * @param context The context node of this iteration.
1084     * @param current The current node of the iteration.
1085     *
1086     * @return the next node in the iteration, or DTM.NULL.
1087     */

1088    public int next(int context, int current)
1089    {
1090
1091      return (context == current)
1092             ? getFirstNamespaceNode(context, true)
1093             : getNextNamespaceNode(context, current, true);
1094    }
1095
1096    /**
1097     * Traverse to the next node after the current node that is matched
1098     * by the expanded type ID.
1099     *
1100     * @param context The context node of this iteration.
1101     * @param current The current node of the iteration.
1102     * @param expandedTypeID The expanded type ID that must match.
1103     *
1104     * @return the next node in the iteration, or DTM.NULL.
1105     */

1106    public int next(int context, int current, int expandedTypeID)
1107    {
1108
1109      current = (context == current)
1110                ? getFirstNamespaceNode(context, true)
1111                : getNextNamespaceNode(context, current, true);
1112
1113      do
1114      {
1115        if (getExpandedTypeID(current) == expandedTypeID)
1116          return current;
1117      }
1118      while (DTM.NULL
1119             != (current = getNextNamespaceNode(context, current, true)));
1120
1121      return NULL;
1122    }
1123  }
1124
1125  /**
1126   * Implements traversal of the Ancestor access, in reverse document order.
1127   */

1128  private class ParentTraverser extends DTMAxisTraverser
1129  {
1130    /**
1131     * By the nature of the stateless traversal, the context node can not be
1132     * returned or the iteration will go into an infinate loop. So to traverse
1133     * an axis, the first function must be used to get the first node.
1134     *
1135     * <p>This method needs to be overloaded only by those axis that process
1136     * the self node. <\p>
1137     *
1138     * @param context The context node of this traversal. This is the point
1139     * that the traversal starts from.
1140     * @return the first node in the traversal.
1141     */

1142    public int first(int context)
1143    {
1144      return getParent(context);
1145    }
1146  
1147    /**
1148     * By the nature of the stateless traversal, the context node can not be
1149     * returned or the iteration will go into an infinate loop. So to traverse
1150     * an axis, the first function must be used to get the first node.
1151     *
1152     * <p>This method needs to be overloaded only by those axis that process
1153     * the self node. <\p>
1154     *
1155     * @param context The context node of this traversal. This is the point
1156     * of origin for the traversal -- its "root node" or starting point.
1157     * @param expandedTypeID The expanded type ID that must match.
1158     *
1159     * @return the first node in the traversal.
1160     */

1161    public int first(int current, int expandedTypeID)
1162    {
1163            // Compute in ID space
1164
current = makeNodeIdentity(current);
1165
1166      while (NULL != (current = m_parent.elementAt(current)))
1167      {
1168        if (m_exptype.elementAt(current) == expandedTypeID)
1169          return makeNodeHandle(current);
1170      }
1171
1172      return NULL;
1173    }
1174
1175
1176    /**
1177     * Traverse to the next node after the current node.
1178     *
1179     * @param context The context node of this iteration.
1180     * @param current The current node of the iteration.
1181     *
1182     * @return the next node in the iteration, or DTM.NULL.
1183     */

1184    public int next(int context, int current)
1185    {
1186
1187      return NULL;
1188    }
1189    
1190
1191
1192    /**
1193     * Traverse to the next node after the current node that is matched
1194     * by the expanded type ID.
1195     *
1196     * @param context The context node of this iteration.
1197     * @param current The current node of the iteration.
1198     * @param expandedTypeID The expanded type ID that must match.
1199     *
1200     * @return the next node in the iteration, or DTM.NULL.
1201     */

1202    public int next(int context, int current, int expandedTypeID)
1203    {
1204
1205      return NULL;
1206    }
1207  }
1208
1209  /**
1210   * Implements traversal of the Ancestor access, in reverse document order.
1211   */

1212  private class PrecedingTraverser extends DTMAxisTraverser
1213  {
1214
1215    /**
1216     * Tell if the current identity is an ancestor of the context identity.
1217     * This is an expensive operation, made worse by the stateless traversal.
1218     * But the preceding axis is used fairly infrequently.
1219     *
1220     * @param contextIdent The context node of the axis traversal.
1221     * @param currentIdent The node in question.
1222     * @return true if the currentIdent node is an ancestor of contextIdent.
1223     */

1224    protected boolean isAncestor(int contextIdent, int currentIdent)
1225    {
1226            // %REVIEW% See comments in IsAfterAxis; using the "successor" of
1227
// contextIdent is probably more efficient.
1228
for (contextIdent = m_parent.elementAt(contextIdent); DTM.NULL != contextIdent;
1229              contextIdent = m_parent.elementAt(contextIdent))
1230      {
1231        if (contextIdent == currentIdent)
1232          return true;
1233      }
1234
1235      return false;
1236    }
1237
1238    /**
1239     * Traverse to the next node after the current node.
1240     *
1241     * @param context The context node of this iteration.
1242     * @param current The current node of the iteration.
1243     *
1244     * @return the next node in the iteration, or DTM.NULL.
1245     */

1246    public int next(int context, int current)
1247    {
1248            // compute in ID space
1249
int subtreeRootIdent = makeNodeIdentity(context);
1250
1251      for (current = makeNodeIdentity(current) - 1; current >= 0; current--)
1252      {
1253        short type = _type(current);
1254
1255        if (ATTRIBUTE_NODE == type || NAMESPACE_NODE == type
1256                || isAncestor(subtreeRootIdent, current))
1257          continue;
1258
1259        return makeNodeHandle(current); // make handle.
1260
}
1261
1262      return NULL;
1263    }
1264
1265    /**
1266     * Traverse to the next node after the current node that is matched
1267     * by the expanded type ID.
1268     *
1269     * @param context The context node of this iteration.
1270     * @param current The current node of the iteration.
1271     * @param expandedTypeID The expanded type ID that must match.
1272     *
1273     * @return the next node in the iteration, or DTM.NULL.
1274     */

1275    public int next(int context, int current, int expandedTypeID)
1276    {
1277            // Compute in ID space
1278
int subtreeRootIdent = makeNodeIdentity(context);
1279
1280      for (current = makeNodeIdentity(current) - 1; current >= 0; current--)
1281      {
1282        int exptype = m_exptype.elementAt(current);
1283
1284        if (exptype != expandedTypeID
1285                || isAncestor(subtreeRootIdent, current))
1286          continue;
1287
1288        return makeNodeHandle(current); // make handle.
1289
}
1290
1291      return NULL;
1292    }
1293  }
1294
1295  /**
1296   * Implements traversal of the Ancestor and the Preceding axis,
1297   * in reverse document order.
1298   */

1299  private class PrecedingAndAncestorTraverser extends DTMAxisTraverser
1300  {
1301
1302    /**
1303     * Traverse to the next node after the current node.
1304     *
1305     * @param context The context node of this iteration.
1306     * @param current The current node of the iteration.
1307     *
1308     * @return the next node in the iteration, or DTM.NULL.
1309     */

1310    public int next(int context, int current)
1311    {
1312            // Compute in ID space
1313
int subtreeRootIdent = makeNodeIdentity(context );
1314
1315      for (current = makeNodeIdentity(current) - 1; current >= 0; current--)
1316      {
1317        short type = _type(current);
1318
1319        if (ATTRIBUTE_NODE == type || NAMESPACE_NODE == type)
1320          continue;
1321
1322        return makeNodeHandle(current); // make handle.
1323
}
1324
1325      return NULL;
1326    }
1327
1328    /**
1329     * Traverse to the next node after the current node that is matched
1330     * by the expanded type ID.
1331     *
1332     * @param context The context node of this iteration.
1333     * @param current The current node of the iteration.
1334     * @param expandedTypeID The expanded type ID that must match.
1335     *
1336     * @return the next node in the iteration, or DTM.NULL.
1337     */

1338    public int next(int context, int current, int expandedTypeID)
1339    {
1340            // Compute in ID space
1341
int subtreeRootIdent = makeNodeIdentity(context);
1342
1343      for (current = makeNodeIdentity(current) - 1; current >= 0; current--)
1344      {
1345        int exptype = m_exptype.elementAt(current);
1346
1347        if (exptype != expandedTypeID)
1348          continue;
1349
1350        return makeNodeHandle(current); // make handle.
1351
}
1352
1353      return NULL;
1354    }
1355  }
1356
1357  /**
1358   * Implements traversal of the Ancestor access, in reverse document order.
1359   */

1360  private class PrecedingSiblingTraverser extends DTMAxisTraverser
1361  {
1362
1363    /**
1364     * Traverse to the next node after the current node.
1365     *
1366     * @param context The context node of this iteration.
1367     * @param current The current node of the iteration.
1368     *
1369     * @return the next node in the iteration, or DTM.NULL.
1370     */

1371    public int next(int context, int current)
1372    {
1373      return getPreviousSibling(current);
1374    }
1375
1376    /**
1377     * Traverse to the next node after the current node that is matched
1378     * by the expanded type ID.
1379     *
1380     * @param context The context node of this iteration.
1381     * @param current The current node of the iteration.
1382     * @param expandedTypeID The expanded type ID that must match.
1383     *
1384     * @return the next node in the iteration, or DTM.NULL.
1385     */

1386    public int next(int context, int current, int expandedTypeID)
1387    {
1388
1389      while (DTM.NULL != (current = getPreviousSibling(current)))
1390      {
1391        if (getExpandedTypeID(current) == expandedTypeID)
1392          return current;
1393      }
1394
1395      return NULL;
1396    }
1397  }
1398
1399  /**
1400   * Implements traversal of the Self axis.
1401   */

1402  private class SelfTraverser extends DTMAxisTraverser
1403  {
1404
1405    /**
1406     * By the nature of the stateless traversal, the context node can not be
1407     * returned or the iteration will go into an infinate loop. To see if
1408     * the self node should be processed, use this function.
1409     *
1410     * @param context The context node of this traversal.
1411     *
1412     * @return the first node in the traversal.
1413     */

1414    public int first(int context)
1415    {
1416      return context;
1417    }
1418
1419    /**
1420     * By the nature of the stateless traversal, the context node can not be
1421     * returned or the iteration will go into an infinate loop. To see if
1422     * the self node should be processed, use this function. If the context
1423     * node does not match the expanded type ID, this function will return
1424     * false.
1425     *
1426     * @param context The context node of this traversal.
1427     * @param expandedTypeID The expanded type ID that must match.
1428     *
1429     * @return the first node in the traversal.
1430     */

1431    public int first(int context, int expandedTypeID)
1432    {
1433      return (getExpandedTypeID(context) == expandedTypeID) ? context : NULL;
1434    }
1435
1436    /**
1437     * Traverse to the next node after the current node.
1438     *
1439     * @param context The context node of this iteration.
1440     * @param current The current node of the iteration.
1441     *
1442     * @return Always return NULL for this axis.
1443     */

1444    public int next(int context, int current)
1445    {
1446      return NULL;
1447    }
1448
1449    /**
1450     * Traverse to the next node after the current node that is matched
1451     * by the expanded type ID.
1452     *
1453     * @param context The context node of this iteration.
1454     * @param current The current node of the iteration.
1455     * @param expandedTypeID The expanded type ID that must match.
1456     *
1457     * @return the next node in the iteration, or DTM.NULL.
1458     */

1459    public int next(int context, int current, int expandedTypeID)
1460    {
1461      return NULL;
1462    }
1463  }
1464
1465  /**
1466   * Implements traversal of the Ancestor access, in reverse document order.
1467   */

1468  private class AllFromRootTraverser extends AllFromNodeTraverser
1469  {
1470
1471    /**
1472     * Return the root.
1473     *
1474     * @param context The context node of this traversal.
1475     *
1476     * @return the first node in the traversal.
1477     */

1478    public int first(int context)
1479    {
1480      return getDocumentRoot(context);
1481    }
1482
1483    /**
1484     * Return the root if it matches the expanded type ID.
1485     *
1486     * @param context The context node of this traversal.
1487     * @param expandedTypeID The expanded type ID that must match.
1488     *
1489     * @return the first node in the traversal.
1490     */

1491    public int first(int context, int expandedTypeID)
1492    {
1493      return (getExpandedTypeID(getDocumentRoot(context)) == expandedTypeID)
1494             ? context : next(context, context, expandedTypeID);
1495    }
1496
1497    /**
1498     * Traverse to the next node after the current node.
1499     *
1500     * @param context The context node of this iteration.
1501     * @param current The current node of the iteration.
1502     *
1503     * @return the next node in the iteration, or DTM.NULL.
1504     */

1505    public int next(int context, int current)
1506    {
1507            // Compute in ID space
1508
int subtreeRootIdent = makeNodeIdentity(context);
1509
1510      for (current = makeNodeIdentity(current) + 1; ; current++)
1511      {
1512                // Kluge test: Just make sure +1 yielded a real node
1513
int type = _type(current); // may call nextNode()
1514
if (type == NULL)
1515          return NULL;
1516
1517        return makeNodeHandle(current); // make handle.
1518
}
1519    }
1520
1521    /**
1522     * Traverse to the next node after the current node that is matched
1523     * by the expanded type ID.
1524     *
1525     * @param context The context node of this iteration.
1526     * @param current The current node of the iteration.
1527     * @param expandedTypeID The expanded type ID that must match.
1528     *
1529     * @return the next node in the iteration, or DTM.NULL.
1530     */

1531    public int next(int context, int current, int expandedTypeID)
1532    {
1533            // Compute in ID space
1534
int subtreeRootIdent = makeNodeIdentity(context);
1535
1536      for (current = makeNodeIdentity(current) + 1; ; current++)
1537      {
1538        int exptype = _exptype(current); // may call nextNode()
1539

1540        if (exptype == NULL)
1541          return NULL;
1542
1543        if (exptype != expandedTypeID)
1544          continue;
1545
1546        return makeNodeHandle(current); // make handle.
1547
}
1548    }
1549  }
1550
1551  /**
1552   * Implements traversal of the Self axis.
1553   */

1554  private class RootTraverser extends AllFromRootTraverser
1555  {
1556    /**
1557     * Return the root if it matches the expanded type ID,
1558     * else return null (nothing found)
1559     *
1560     * @param context The context node of this traversal.
1561     * @param expandedTypeID The expanded type ID that must match.
1562     *
1563     * @return the first node in the traversal.
1564     */

1565    public int first(int context, int expandedTypeID)
1566    {
1567      int root=getDocumentRoot(context);
1568      return (getExpandedTypeID(root) == expandedTypeID)
1569    ? root : NULL;
1570    }
1571
1572    /**
1573     * Traverse to the next node after the current node.
1574     *
1575     * @param context The context node of this iteration.
1576     * @param current The current node of the iteration.
1577     *
1578     * @return Always return NULL for this axis.
1579     */

1580    public int next(int context, int current)
1581    {
1582      return NULL;
1583    }
1584
1585    /**
1586     * Traverse to the next node after the current node that is matched
1587     * by the expanded type ID.
1588     *
1589     * @param context The context node of this iteration.
1590     * @param current The current node of the iteration.
1591     * @param expandedTypeID The expanded type ID that must match.
1592     *
1593     * @return the next node in the iteration, or DTM.NULL.
1594     */

1595    public int next(int context, int current, int expandedTypeID)
1596    {
1597      return NULL;
1598    }
1599  }
1600
1601  /**
1602   * A non-xpath axis, returns all nodes that aren't namespaces or attributes,
1603   * from and including the root.
1604   */

1605  private class DescendantOrSelfFromRootTraverser extends DescendantTraverser
1606  {
1607
1608    /**
1609     * Get the first potential identity that can be returned, which is the axis
1610     * root context in this case.
1611     *
1612     * @param identity The node identity of the root context of the traversal.
1613     *
1614     * @return The identity argument.
1615     */

1616    protected int getFirstPotential(int identity)
1617    {
1618      return identity;
1619    }
1620
1621    /**
1622     * Get the first potential identity that can be returned.
1623     * @param handle handle to the root context.
1624     * @return identity of the root of the subtree.
1625     */

1626    protected int getSubtreeRoot(int handle)
1627    {
1628            // %REVIEW% Shouldn't this always be 0?
1629
return makeNodeIdentity(getDocument());
1630    }
1631
1632    /**
1633     * Return the root.
1634     *
1635     * @param context The context node of this traversal.
1636     *
1637     * @return the first node in the traversal.
1638     */

1639    public int first(int context)
1640    {
1641      return getDocumentRoot(context);
1642    }
1643    
1644    /**
1645     * By the nature of the stateless traversal, the context node can not be
1646     * returned or the iteration will go into an infinate loop. So to traverse
1647     * an axis, the first function must be used to get the first node.
1648     *
1649     * <p>This method needs to be overloaded only by those axis that process
1650     * the self node. <\p>
1651     *
1652     * @param context The context node of this traversal. This is the point
1653     * of origin for the traversal -- its "root node" or starting point.
1654     * @param expandedTypeID The expanded type ID that must match.
1655     *
1656     * @return the first node in the traversal.
1657     */

1658    public int first(int context, int expandedTypeID)
1659    {
1660      if (isIndexed(expandedTypeID))
1661      {
1662        int identity = 0;
1663        int firstPotential = getFirstPotential(identity);
1664
1665        return makeNodeHandle(getNextIndexed(identity, firstPotential, expandedTypeID));
1666      }
1667
1668      int root = first(context);
1669      return next(root, root, expandedTypeID);
1670    }
1671  }
1672  
1673  /**
1674   * A non-xpath axis, returns all nodes that aren't namespaces or attributes,
1675   * from but not including the root.
1676   */

1677  private class DescendantFromRootTraverser extends DescendantTraverser
1678  {
1679
1680    /**
1681     * Get the first potential identity that can be returned, which is the axis
1682     * root context in this case.
1683     *
1684     * @param identity The node identity of the root context of the traversal.
1685     *
1686     * @return The identity argument.
1687     */

1688    protected int getFirstPotential(int identity)
1689    {
1690      return _firstch(0);
1691    }
1692
1693    /**
1694     * Get the first potential identity that can be returned.
1695     * @param handle handle to the root context.
1696     * @return identity of the root of the subtree.
1697     */

1698    protected int getSubtreeRoot(int handle)
1699    {
1700      return 0;
1701    }
1702
1703    /**
1704     * Return the root.
1705     *
1706     * @param context The context node of this traversal.
1707     *
1708     * @return the first node in the traversal.
1709     */

1710    public int first(int context)
1711    {
1712      return makeNodeHandle(_firstch(0));
1713    }
1714    
1715    /**
1716     * By the nature of the stateless traversal, the context node can not be
1717     * returned or the iteration will go into an infinate loop. So to traverse
1718     * an axis, the first function must be used to get the first node.
1719     *
1720     * <p>This method needs to be overloaded only by those axis that process
1721     * the self node. <\p>
1722     *
1723     * @param context The context node of this traversal. This is the point
1724     * of origin for the traversal -- its "root node" or starting point.
1725     * @param expandedTypeID The expanded type ID that must match.
1726     *
1727     * @return the first node in the traversal.
1728     */

1729    public int first(int context, int expandedTypeID)
1730    {
1731      if (isIndexed(expandedTypeID))
1732      {
1733        int identity = 0;
1734        int firstPotential = getFirstPotential(identity);
1735
1736        return makeNodeHandle(getNextIndexed(identity, firstPotential, expandedTypeID));
1737      }
1738
1739      int root = getDocumentRoot(context);
1740      return next(root, root, expandedTypeID);
1741    }
1742    
1743  }
1744
1745}
1746
Popular Tags