1/*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the  "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 *     http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 */
18/*
19 * $Id: DTMDefaultBaseTraversers.java 468653 2006-10-28 07:07:05Z minchau $
20 */
21package org.apache.xml.dtm.ref;
22
23import org.apache.xml.dtm.*;
24
25import javax.xml.transform.Source;
26
27import org.apache.xml.utils.XMLStringFactory;
28
29import org.apache.xml.res.XMLErrorResources;
30import org.apache.xml.res.XMLMessages;
31
32/**
33 * This class implements the traversers for DTMDefaultBase.
34 *
35 * PLEASE NOTE that the public interface for all traversers should be
36 * in terms of DTM Node Handles... but they may use the internal node
37 * identity indices within their logic, for efficiency's sake. Be very
38 * careful to avoid confusing these when maintaining this code.
39 * */
40public abstract class DTMDefaultBaseTraversers extends DTMDefaultBase
41{
42
43  /**
44   * Construct a DTMDefaultBaseTraversers object from a DOM node.
45   *
46   * @param mgr The DTMManager who owns this DTM.
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 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 source The object that is used to specify the construction source.
70   * @param dtmIdentity The DTM identity ID for this DTM.
71   * @param whiteSpaceFilter The white space filter for this DTM, which may
72   *                         be null.
73   * @param xstringfactory The factory to use for creating XMLStrings.
74   * @param doIndexing true if the caller considers it worth it to use
75   *                   indexing schemes.
76   * @param blocksize The block size of the DTM.
77   * @param usePrevsib true if we want to build the previous sibling node array.
78   * @param newNameTable true if we want to use a new ExpandedNameTable for this DTM.
79   */
80  public DTMDefaultBaseTraversers(DTMManager mgr, Source source,
81                                  int dtmIdentity,
82                                  DTMWSFilter whiteSpaceFilter,
83                                  XMLStringFactory xstringfactory,
84                                  boolean doIndexing,
85                                  int blocksize,
86                                  boolean usePrevsib,
87                                  boolean newNameTable)
88  {
89    super(mgr, source, dtmIdentity, whiteSpaceFilter, xstringfactory,
90          doIndexing, blocksize, usePrevsib, newNameTable);
91  }
92
93  /**
94   * This returns a stateless "traverser", that can navigate
95   * over an XPath axis, though perhaps not in document order.
96   *
97   * @param axis One of Axes.ANCESTORORSELF, etc.
98   *
99   * @return A DTMAxisTraverser, or null if the given axis isn't supported.
100   */
101  public DTMAxisTraverser getAxisTraverser(final int axis)
102  {
103
104    DTMAxisTraverser traverser;
105
106    if (null == m_traversers)  // Cache of stateless traversers for this DTM
107    {
108      m_traversers = new DTMAxisTraverser[Axis.getNamesLength()];
109      traverser = null;
110    }
111    else
112    {
113      traverser = m_traversers[axis];  // Share/reuse existing traverser
114
115      if (traverser != null)
116        return traverser;
117    }
118
119    switch (axis)  // Generate new traverser
120    {
121    case Axis.ANCESTOR :
122      traverser = new AncestorTraverser();
123      break;
124    case Axis.ANCESTORORSELF :
125      traverser = new AncestorOrSelfTraverser();
126      break;
127    case Axis.ATTRIBUTE :
128      traverser = new AttributeTraverser();
129      break;
130    case Axis.CHILD :
131      traverser = new ChildTraverser();
132      break;
133    case Axis.DESCENDANT :
134      traverser = new DescendantTraverser();
135      break;
136    case Axis.DESCENDANTORSELF :
137      traverser = new DescendantOrSelfTraverser();
138      break;
139    case Axis.FOLLOWING :
140      traverser = new FollowingTraverser();
141      break;
142    case Axis.FOLLOWINGSIBLING :
143      traverser = new FollowingSiblingTraverser();
144      break;
145    case Axis.NAMESPACE :
146      traverser = new NamespaceTraverser();
147      break;
148    case Axis.NAMESPACEDECLS :
149      traverser = new NamespaceDeclsTraverser();
150      break;
151    case Axis.PARENT :
152      traverser = new ParentTraverser();
153      break;
154    case Axis.PRECEDING :
155      traverser = new PrecedingTraverser();
156      break;
157    case Axis.PRECEDINGSIBLING :
158      traverser = new PrecedingSiblingTraverser();
159      break;
160    case Axis.SELF :
161      traverser = new SelfTraverser();
162      break;
163    case Axis.ALL :
164      traverser = new AllFromRootTraverser();
165      break;
166    case Axis.ALLFROMNODE :
167      traverser = new AllFromNodeTraverser();
168      break;
169    case Axis.PRECEDINGANDANCESTOR :
170      traverser = new PrecedingAndAncestorTraverser();
171      break;
172    case Axis.DESCENDANTSFROMROOT :
173      traverser = new DescendantFromRootTraverser();
174      break;
175    case Axis.DESCENDANTSORSELFFROMROOT :
176      traverser = new DescendantOrSelfFromRootTraverser();
177      break;
178    case Axis.ROOT :
179      traverser = new RootTraverser();
180      break;
181    case Axis.FILTEREDLIST :
182      return null; // Don't want to throw an exception for this one.
183    default :
184      throw new DTMException(XMLMessages.createXMLMessage(XMLErrorResources.ER_UNKNOWN_AXIS_TYPE, new Object[]{Integer.toString(axis)})); //"Unknown axis traversal type: "+axis);
185    }
186
187    if (null == traverser)
188      throw new DTMException(XMLMessages.createXMLMessage(XMLErrorResources.ER_AXIS_TRAVERSER_NOT_SUPPORTED, new Object[]{Axis.getNames(axis)}));
189      // "Axis traverser not supported: "
190      //                       + Axis.names[axis]);
191
192    m_traversers[axis] = traverser;
193
194    return traverser;
195  }
196
197  /**
198   * Implements traversal of the Ancestor access, in reverse document order.
199   */
200  private class AncestorTraverser extends DTMAxisTraverser
201  {
202
203    /**
204     * Traverse to the next node after the current node.
205     *
206     * @param context The context node if this iteration.
207     * @param current The current node of the iteration.
208     *
209     * @return the next node in the iteration, or DTM.NULL.
210     */
211    public int next(int context, int current)
212    {
213			return getParent(current);
214    }
215
216    /**
217     * Traverse to the next node after the current node that is matched
218     * by the expanded type ID.
219     *
220     * @param context The context node of this iteration.
221     * @param current The current node of the iteration.
222     * @param expandedTypeID The expanded type ID that must match.
223     *
224     * @return the next node in the iteration, or DTM.NULL.
225     */
226    public int next(int context, int current, int expandedTypeID)
227    {
228			// Process using identities
229      current = makeNodeIdentity(current);
230
231      while (DTM.NULL != (current = m_parent.elementAt(current)))
232      {
233        if (m_exptype.elementAt(current) == expandedTypeID)
234          return makeNodeHandle(current);
235      }
236
237      return NULL;
238    }
239  }
240
241  /**
242   * Implements traversal of the Ancestor access, in reverse document order.
243   */
244  private class AncestorOrSelfTraverser extends AncestorTraverser
245  {
246
247    /**
248     * By the nature of the stateless traversal, the context node can not be
249     * returned or the iteration will go into an infinate loop.  To see if
250     * the self node should be processed, use this function.
251     *
252     * @param context The context node of this traversal.
253     *
254     * @return the first node in the traversal.
255     */
256    public int first(int context)
257    {
258      return context;
259    }
260
261    /**
262     * By the nature of the stateless traversal, the context node can not be
263     * returned or the iteration will go into an infinate loop.  To see if
264     * the self node should be processed, use this function.  If the context
265     * node does not match the expanded type ID, this function will return
266     * false.
267     *
268     * @param context The context node of this traversal.
269     * @param expandedTypeID The expanded type ID that must match.
270     *
271     * @return the first node in the traversal.
272     */
273    public int first(int context, int expandedTypeID)
274    {
275			return (getExpandedTypeID(context) == expandedTypeID)
276             ? context : next(context, context, expandedTypeID);
277    }
278  }
279
280  /**
281   * Implements traversal of the Attribute access
282   */
283  private class AttributeTraverser extends DTMAxisTraverser
284  {
285
286    /**
287     * Traverse to the next node after the current node.
288     *
289     * @param context The context node of this iteration.
290     * @param current The current node of the iteration.
291     *
292     * @return the next node in the iteration, or DTM.NULL.
293     */
294    public int next(int context, int current)
295    {
296      return (context == current)
297             ? getFirstAttribute(context) : getNextAttribute(current);
298    }
299
300    /**
301     * Traverse to the next node after the current node that is matched
302     * by the expanded type ID.
303     *
304     * @param context The context node of this iteration.
305     * @param current The current node of the iteration.
306     * @param expandedTypeID The expanded type ID that must match.
307     *
308     * @return the next node in the iteration, or DTM.NULL.
309     */
310    public int next(int context, int current, int expandedTypeID)
311    {
312
313      current = (context == current)
314                ? getFirstAttribute(context) : getNextAttribute(current);
315
316      do
317      {
318        if (getExpandedTypeID(current) == expandedTypeID)
319          return current;
320      }
321      while (DTM.NULL != (current = getNextAttribute(current)));
322
323      return NULL;
324    }
325  }
326
327  /**
328   * Implements traversal of the Ancestor access, in reverse document order.
329   */
330  private class ChildTraverser extends DTMAxisTraverser
331  {
332
333    /**
334     * Get the next indexed node that matches the expanded type ID.  Before
335     * calling this function, one should first call
336     * {@link #isIndexed(int) isIndexed} to make sure that the index can
337     * contain nodes that match the given expanded type ID.
338     *
339     * @param axisRoot The root identity of the axis.
340     * @param nextPotential The node found must match or occur after this node.
341     * @param expandedTypeID The expanded type ID for the request.
342     *
343     * @return The node ID or NULL if not found.
344     */
345    protected int getNextIndexed(int axisRoot, int nextPotential,
346                                 int expandedTypeID)
347    {
348
349      int nsIndex = m_expandedNameTable.getNamespaceID(expandedTypeID);
350      int lnIndex = m_expandedNameTable.getLocalNameID(expandedTypeID);
351
352      for (; ; )
353      {
354        int nextID = findElementFromIndex(nsIndex, lnIndex, nextPotential);
355
356        if (NOTPROCESSED != nextID)
357        {
358          int parentID = m_parent.elementAt(nextID);
359
360          // Is it a child?
361          if(parentID == axisRoot)
362            return nextID;
363
364          // If the parent occured before the subtree root, then
365          // we know it is past the child axis.
366          if(parentID < axisRoot)
367              return NULL;
368
369          // Otherwise, it could be a descendant below the subtree root
370          // children, or it could be after the subtree root.  So we have
371          // to climb up until the parent is less than the subtree root, in
372          // which case we return NULL, or until it is equal to the subtree
373          // root, in which case we continue to look.
374          do
375          {
376            parentID = m_parent.elementAt(parentID);
377            if(parentID < axisRoot)
378              return NULL;
379          }
380            while(parentID > axisRoot);
381
382          // System.out.println("Found node via index: "+first);
383          nextPotential = nextID+1;
384          continue;
385        }
386
387        nextNode();
388
389        if(!(m_nextsib.elementAt(axisRoot) == NOTPROCESSED))
390          break;
391      }
392
393      return DTM.NULL;
394    }
395
396    /**
397     * By the nature of the stateless traversal, the context node can not be
398     * returned or the iteration will go into an infinate loop.  So to traverse
399     * an axis, the first function must be used to get the first node.
400     *
401     * <p>This method needs to be overloaded only by those axis that process
402     * the self node. <\p>
403     *
404     * @param context The context node of this traversal. This is the point
405     * that the traversal starts from.
406     * @return the first node in the traversal.
407     */
408    public int first(int context)
409    {
410      return getFirstChild(context);
411    }
412
413    /**
414     * By the nature of the stateless traversal, the context node can not be
415     * returned or the iteration will go into an infinate loop.  So to traverse
416     * an axis, the first function must be used to get the first node.
417     *
418     * <p>This method needs to be overloaded only by those axis that process
419     * the self node. <\p>
420     *
421     * @param context The context node of this traversal. This is the point
422     * of origin for the traversal -- its "root node" or starting point.
423     * @param expandedTypeID The expanded type ID that must match.
424     *
425     * @return the first node in the traversal.
426     */
427    public int first(int context, int expandedTypeID)
428    {
429      if(true)
430      {
431        int identity = makeNodeIdentity(context);
432
433        int firstMatch = getNextIndexed(identity, _firstch(identity),
434                                 expandedTypeID);
435
436        return makeNodeHandle(firstMatch);
437      }
438      else
439      {
440				// %REVIEW% Dead code. Eliminate?
441        for (int current = _firstch(makeNodeIdentity(context));
442             DTM.NULL != current;
443             current = _nextsib(current))
444        {
445          if (m_exptype.elementAt(current) == expandedTypeID)
446              return makeNodeHandle(current);
447        }
448        return NULL;
449      }
450    }
451
452    /**
453     * Traverse to the next node after the current node.
454     *
455     * @param context The context node of this iteration.
456     * @param current The current node of the iteration.
457     *
458     * @return the next node in the iteration, or DTM.NULL.
459     */
460    public int next(int context, int current)
461    {
462      return getNextSibling(current);
463    }
464
465    /**
466     * Traverse to the next node after the current node that is matched
467     * by the expanded type ID.
468     *
469     * @param context The context node of this iteration.
470     * @param current The current node of the iteration.
471     * @param expandedTypeID The expanded type ID that must match.
472     *
473     * @return the next node in the iteration, or DTM.NULL.
474     */
475    public int next(int context, int current, int expandedTypeID)
476    {
477			// Process in Identifier space
478      for (current = _nextsib(makeNodeIdentity(current));
479           DTM.NULL != current;
480           current = _nextsib(current))
481      {
482        if (m_exptype.elementAt(current) == expandedTypeID)
483            return makeNodeHandle(current);
484      }
485
486      return NULL;
487    }
488  }
489
490  /**
491   * Super class for derived classes that want a convenient way to access
492   * the indexing mechanism.
493   */
494  private abstract class IndexedDTMAxisTraverser extends DTMAxisTraverser
495  {
496
497    /**
498     * Tell if the indexing is on and the given expanded type ID matches
499     * what is in the indexes.  Derived classes should call this before
500     * calling {@link #getNextIndexed(int, int, int) getNextIndexed} method.
501     *
502     * @param expandedTypeID The expanded type ID being requested.
503     *
504     * @return true if it is OK to call the
505     *         {@link #getNextIndexed(int, int, int) getNextIndexed} method.
506     */
507    protected final boolean isIndexed(int expandedTypeID)
508    {
509      return (m_indexing
510              && ExpandedNameTable.ELEMENT
511                 == m_expandedNameTable.getType(expandedTypeID));
512    }
513
514    /**
515     * Tell if a node is outside the axis being traversed.  This method must be
516     * implemented by derived classes, and must be robust enough to handle any
517     * node that occurs after the axis root.
518     *
519     * @param axisRoot The root identity of the axis.
520     * @param identity The node in question.
521     *
522     * @return true if the given node falls outside the axis being traversed.
523     */
524    protected abstract boolean isAfterAxis(int axisRoot, int identity);
525
526    /**
527     * Tell if the axis has been fully processed to tell if a the wait for
528     * an arriving node should terminate.  This method must be implemented
529     * be a derived class.
530     *
531     * @param axisRoot The root identity of the axis.
532     *
533     * @return true if the axis has been fully processed.
534     */
535    protected abstract boolean axisHasBeenProcessed(int axisRoot);
536
537    /**
538     * Get the next indexed node that matches the expanded type ID.  Before
539     * calling this function, one should first call
540     * {@link #isIndexed(int) isIndexed} to make sure that the index can
541     * contain nodes that match the given expanded type ID.
542     *
543     * @param axisRoot The root identity of the axis.
544     * @param nextPotential The node found must match or occur after this node.
545     * @param expandedTypeID The expanded type ID for the request.
546     *
547     * @return The node ID or NULL if not found.
548     */
549    protected int getNextIndexed(int axisRoot, int nextPotential,
550                                 int expandedTypeID)
551    {
552
553      int nsIndex = m_expandedNameTable.getNamespaceID(expandedTypeID);
554      int lnIndex = m_expandedNameTable.getLocalNameID(expandedTypeID);
555
556      while(true)
557      {
558        int next = findElementFromIndex(nsIndex, lnIndex, nextPotential);
559
560        if (NOTPROCESSED != next)
561        {
562          if (isAfterAxis(axisRoot, next))
563            return NULL;
564
565          // System.out.println("Found node via index: "+first);
566          return next;
567        }
568        else if(axisHasBeenProcessed(axisRoot))
569          break;
570
571        nextNode();
572      }
573
574      return DTM.NULL;
575    }
576  }
577
578  /**
579   * Implements traversal of the Ancestor access, in reverse document order.
580   */
581  private class DescendantTraverser extends IndexedDTMAxisTraverser
582  {
583    /**
584     * Get the first potential identity that can be returned.  This should
585     * be overridded by classes that need to return the self node.
586     *
587     * @param identity The node identity of the root context of the traversal.
588     *
589     * @return The first potential node that can be in the traversal.
590     */
591    protected int getFirstPotential(int identity)
592    {
593      return identity + 1;
594    }
595
596    /**
597     * Tell if the axis has been fully processed to tell if a the wait for
598     * an arriving node should terminate.
599     *
600     * @param axisRoot The root identity of the axis.
601     *
602     * @return true if the axis has been fully processed.
603     */
604    protected boolean axisHasBeenProcessed(int axisRoot)
605    {
606      return !(m_nextsib.elementAt(axisRoot) == NOTPROCESSED);
607    }
608
609    /**
610     * Get the subtree root identity from the handle that was passed in by
611     * the caller.  Derived classes may override this to change the root
612     * context of the traversal.
613     *
614     * @param handle handle to the root context.
615     * @return identity of the root of the subtree.
616     */
617    protected int getSubtreeRoot(int handle)
618    {
619      return makeNodeIdentity(handle);
620    }
621
622    /**
623     * Tell if this node identity is a descendant.  Assumes that
624     * the node info for the element has already been obtained.
625     *
626     * %REVIEW% This is really parentFollowsRootInDocumentOrder ...
627     * which fails if the parent starts after the root ends.
628     * May be sufficient for this class's logic, but misleadingly named!
629     *
630     * @param subtreeRootIdentity The root context of the subtree in question.
631     * @param identity The index number of the node in question.
632     * @return true if the index is a descendant of _startNode.
633     */
634    protected boolean isDescendant(int subtreeRootIdentity, int identity)
635    {
636      return _parent(identity) >= subtreeRootIdentity;
637    }
638
639    /**
640     * Tell if a node is outside the axis being traversed.  This method must be
641     * implemented by derived classes, and must be robust enough to handle any
642     * node that occurs after the axis root.
643     *
644     * @param axisRoot The root identity of the axis.
645     * @param identity The node in question.
646     *
647     * @return true if the given node falls outside the axis being traversed.
648     */
649    protected boolean isAfterAxis(int axisRoot, int identity)
650    {
651      // %REVIEW% Is there *any* cheaper way to do this?
652			// Yes. In ID space, compare to axisRoot's successor
653			// (next-sib or ancestor's-next-sib). Probably shallower search.
654      do
655      {
656        if(identity == axisRoot)
657          return false;
658        identity = m_parent.elementAt(identity);
659      }
660        while(identity >= axisRoot);
661
662      return true;
663    }
664
665    /**
666     * By the nature of the stateless traversal, the context node can not be
667     * returned or the iteration will go into an infinate loop.  So to traverse
668     * an axis, the first function must be used to get the first node.
669     *
670     * <p>This method needs to be overloaded only by those axis that process
671     * the self node. <\p>
672     *
673     * @param context The context node of this traversal. This is the point
674     * of origin for the traversal -- its "root node" or starting point.
675     * @param expandedTypeID The expanded type ID that must match.
676     *
677     * @return the first node in the traversal.
678     */
679    public int first(int context, int expandedTypeID)
680    {
681
682      if (isIndexed(expandedTypeID))
683      {
684        int identity = getSubtreeRoot(context);
685        int firstPotential = getFirstPotential(identity);
686
687        return makeNodeHandle(getNextIndexed(identity, firstPotential, expandedTypeID));
688      }
689
690      return next(context, context, expandedTypeID);
691    }
692
693    /**
694     * Traverse to the next node after the current node.
695     *
696     * @param context The context node of this iteration.
697     * @param current The current node of the iteration.
698     *
699     * @return the next node in the iteration, or DTM.NULL.
700     */
701    public int next(int context, int current)
702    {
703
704      int subtreeRootIdent = getSubtreeRoot(context);
705
706      for (current = makeNodeIdentity(current) + 1; ; current++)
707      {
708        int type = _type(current);  // may call nextNode()
709
710        if (!isDescendant(subtreeRootIdent, current))
711          return NULL;
712
713        if (ATTRIBUTE_NODE == type || NAMESPACE_NODE == type)
714          continue;
715
716        return makeNodeHandle(current);  // make handle.
717      }
718    }
719
720    /**
721     * Traverse to the next node after the current node that is matched
722     * by the expanded type ID.
723     *
724     * @param context The context node of this iteration.
725     * @param current The current node of the iteration.
726     * @param expandedTypeID The expanded type ID that must match.
727     *
728     * @return the next node in the iteration, or DTM.NULL.
729     */
730    public int next(int context, int current, int expandedTypeID)
731    {
732
733      int subtreeRootIdent = getSubtreeRoot(context);
734
735      current = makeNodeIdentity(current) + 1;
736
737      if (isIndexed(expandedTypeID))
738      {
739        return makeNodeHandle(getNextIndexed(subtreeRootIdent, current, expandedTypeID));
740      }
741
742      for (; ; current++)
743      {
744        int exptype = _exptype(current);  // may call nextNode()
745
746        if (!isDescendant(subtreeRootIdent, current))
747          return NULL;
748
749        if (exptype != expandedTypeID)
750          continue;
751
752        return makeNodeHandle(current);  // make handle.
753      }
754    }
755  }
756
757  /**
758   * Implements traversal of the Ancestor access, in reverse document order.
759   */
760  private class DescendantOrSelfTraverser extends DescendantTraverser
761  {
762
763    /**
764     * Get the first potential identity that can be returned, which is the
765     * axis context, in this case.
766     *
767     * @param identity The node identity of the root context of the traversal.
768     *
769     * @return The axis context.
770     */
771    protected int getFirstPotential(int identity)
772    {
773      return identity;
774    }
775
776    /**
777     * By the nature of the stateless traversal, the context node can not be
778     * returned or the iteration will go into an infinate loop.  To see if
779     * the self node should be processed, use this function.
780     *
781     * @param context The context node of this traversal.
782     *
783     * @return the first node in the traversal.
784     */
785    public int first(int context)
786    {
787      return context;
788    }
789  }
790
791  /**
792   * Implements traversal of the entire subtree, including the root node.
793   */
794  private class AllFromNodeTraverser extends DescendantOrSelfTraverser
795  {
796
797    /**
798     * Traverse to the next node after the current node.
799     *
800     * @param context The context node of this iteration.
801     * @param current The current node of the iteration.
802     *
803     * @return the next node in the iteration, or DTM.NULL.
804     */
805    public int next(int context, int current)
806    {
807
808      int subtreeRootIdent = makeNodeIdentity(context);
809
810      for (current = makeNodeIdentity(current) + 1; ; current++)
811      {
812        // Trickological code: _exptype() has the side-effect of
813        // running nextNode until the specified node has been loaded,
814        // and thus can be used to ensure that incremental construction of
815        // the DTM has gotten this far. Using it just for that side-effect
816        // is quite a kluge...
817        _exptype(current);  // make sure it's here.
818
819        if (!isDescendant(subtreeRootIdent, current))
820          return NULL;
821
822        return makeNodeHandle(current);  // make handle.
823      }
824    }
825  }
826
827  /**
828   * Implements traversal of the following access, in document order.
829   */
830  private class FollowingTraverser extends DescendantTraverser
831  {
832
833    /**
834     * Get the first of the following.
835     *
836     * @param context The context node of this traversal. This is the point
837     * that the traversal starts from.
838     * @return the first node in the traversal.
839     */
840    public int first(int context)
841    {
842			// Compute in ID space
843			context=makeNodeIdentity(context);
844
845      int first;
846      int type = _type(context);
847
848      if ((DTM.ATTRIBUTE_NODE == type) || (DTM.NAMESPACE_NODE == type))
849      {
850        context = _parent(context);
851        first = _firstch(context);
852
853        if (NULL != first)
854          return makeNodeHandle(first);
855      }
856
857      do
858      {
859        first = _nextsib(context);
860
861        if (NULL == first)
862          context = _parent(context);
863      }
864      while (NULL == first && NULL != context);
865
866      return makeNodeHandle(first);
867    }
868
869    /**
870     * Get the first of the following.
871     *
872     * @param context The context node of this traversal. This is the point
873     * of origin for the traversal -- its "root node" or starting point.
874     * @param expandedTypeID The expanded type ID that must match.
875     *
876     * @return the first node in the traversal.
877     */
878    public int first(int context, int expandedTypeID)
879    {
880			// %REVIEW% This looks like it might want shift into identity space
881			// to avoid repeated conversion in the individual functions
882      int first;
883      int type = getNodeType(context);
884
885      if ((DTM.ATTRIBUTE_NODE == type) || (DTM.NAMESPACE_NODE == type))
886      {
887        context = getParent(context);
888        first = getFirstChild(context);
889
890        if (NULL != first)
891        {
892          if (getExpandedTypeID(first) == expandedTypeID)
893            return first;
894          else
895            return next(context, first, expandedTypeID);
896        }
897      }
898
899      do
900      {
901        first = getNextSibling(context);
902
903        if (NULL == first)
904          context = getParent(context);
905        else
906        {
907          if (getExpandedTypeID(first) == expandedTypeID)
908            return first;
909          else
910            return next(context, first, expandedTypeID);
911        }
912      }
913      while (NULL == first && NULL != context);
914
915      return first;
916    }
917
918    /**
919     * Traverse to the next node after the current node.
920     *
921     * @param context The context node of this iteration.
922     * @param current The current node of the iteration.
923     *
924     * @return the next node in the iteration, or DTM.NULL.
925     */
926    public int next(int context, int current)
927    {
928			// Compute in identity space
929			current=makeNodeIdentity(current);
930
931      while (true)
932      {
933        current++; // Only works on IDs, not handles.
934
935				// %REVIEW% Are we using handles or indexes?
936        int type = _type(current);  // may call nextNode()
937
938        if (NULL == type)
939          return NULL;
940
941        if (ATTRIBUTE_NODE == type || NAMESPACE_NODE == type)
942          continue;
943
944        return makeNodeHandle(current);  // make handle.
945      }
946    }
947
948    /**
949     * Traverse to the next node after the current node that is matched
950     * by the expanded type ID.
951     *
952     * @param context The context node of this iteration.
953     * @param current The current node of the iteration.
954     * @param expandedTypeID The expanded type ID that must match.
955     *
956     * @return the next node in the iteration, or DTM.NULL.
957     */
958    public int next(int context, int current, int expandedTypeID)
959    {
960			// Compute in ID space
961			current=makeNodeIdentity(current);
962
963      while (true)
964      {
965        current++;
966
967        int etype = _exptype(current);  // may call nextNode()
968
969        if (NULL == etype)
970          return NULL;
971
972        if (etype != expandedTypeID)
973          continue;
974
975        return makeNodeHandle(current);  // make handle.
976      }
977    }
978  }
979
980  /**
981   * Implements traversal of the Ancestor access, in reverse document order.
982   */
983  private class FollowingSiblingTraverser extends DTMAxisTraverser
984  {
985
986    /**
987     * Traverse to the next node after the current node.
988     *
989     * @param context The context node of this iteration.
990     * @param current The current node of the iteration.
991     *
992     * @return the next node in the iteration, or DTM.NULL.
993     */
994    public int next(int context, int current)
995    {
996      return getNextSibling(current);
997    }
998
999    /**
1000     * Traverse to the next node after the current node that is matched
1001     * by the expanded type ID.
1002     *
1003     * @param context The context node of this iteration.
1004     * @param current The current node of the iteration.
1005     * @param expandedTypeID The expanded type ID that must match.
1006     *
1007     * @return the next node in the iteration, or DTM.NULL.
1008     */
1009    public int next(int context, int current, int expandedTypeID)
1010    {
1011
1012      while (DTM.NULL != (current = getNextSibling(current)))
1013      {
1014        if (getExpandedTypeID(current) == expandedTypeID)
1015          return current;
1016      }
1017
1018      return NULL;
1019    }
1020  }
1021
1022  /**
1023   * Implements traversal of the Ancestor access, in reverse document order.
1024   */
1025  private class NamespaceDeclsTraverser extends DTMAxisTraverser
1026  {
1027
1028    /**
1029     * Traverse to the next node after the current node.
1030     *
1031     * @param context The context node of this iteration.
1032     * @param current The current node of the iteration.
1033     *
1034     * @return the next node in the iteration, or DTM.NULL.
1035     */
1036    public int next(int context, int current)
1037    {
1038
1039      return (context == current)
1040             ? getFirstNamespaceNode(context, false)
1041             : getNextNamespaceNode(context, current, false);
1042    }
1043
1044    /**
1045     * Traverse to the next node after the current node that is matched
1046     * by the expanded type ID.
1047     *
1048     * @param context The context node of this iteration.
1049     * @param current The current node of the iteration.
1050     * @param expandedTypeID The expanded type ID that must match.
1051     *
1052     * @return the next node in the iteration, or DTM.NULL.
1053     */
1054    public int next(int context, int current, int expandedTypeID)
1055    {
1056
1057      current = (context == current)
1058                ? getFirstNamespaceNode(context, false)
1059                : getNextNamespaceNode(context, current, false);
1060
1061      do
1062      {
1063        if (getExpandedTypeID(current) == expandedTypeID)
1064          return current;
1065      }
1066      while (DTM.NULL
1067             != (current = getNextNamespaceNode(context, current, false)));
1068
1069      return NULL;
1070    }
1071  }
1072
1073  /**
1074   * Implements traversal of the Ancestor access, in reverse document order.
1075   */
1076  private class NamespaceTraverser extends DTMAxisTraverser
1077  {
1078
1079    /**
1080     * Traverse to the next node after the current node.
1081     *
1082     * @param context The context node of this iteration.
1083     * @param current The current node of the iteration.
1084     *
1085     * @return the next node in the iteration, or DTM.NULL.
1086     */
1087    public int next(int context, int current)
1088    {
1089
1090      return (context == current)
1091             ? getFirstNamespaceNode(context, true)
1092             : getNextNamespaceNode(context, current, true);
1093    }
1094
1095    /**
1096     * Traverse to the next node after the current node that is matched
1097     * by the expanded type ID.
1098     *
1099     * @param context The context node of this iteration.
1100     * @param current The current node of the iteration.
1101     * @param expandedTypeID The expanded type ID that must match.
1102     *
1103     * @return the next node in the iteration, or DTM.NULL.
1104     */
1105    public int next(int context, int current, int expandedTypeID)
1106    {
1107
1108      current = (context == current)
1109                ? getFirstNamespaceNode(context, true)
1110                : getNextNamespaceNode(context, current, true);
1111
1112      do
1113      {
1114        if (getExpandedTypeID(current) == expandedTypeID)
1115          return current;
1116      }
1117      while (DTM.NULL
1118             != (current = getNextNamespaceNode(context, current, true)));
1119
1120      return NULL;
1121    }
1122  }
1123
1124  /**
1125   * Implements traversal of the Ancestor access, in reverse document order.
1126   */
1127  private class ParentTraverser extends DTMAxisTraverser
1128  {
1129    /**
1130     * By the nature of the stateless traversal, the context node can not be
1131     * returned or the iteration will go into an infinate loop.  So to traverse
1132     * an axis, the first function must be used to get the first node.
1133     *
1134     * <p>This method needs to be overloaded only by those axis that process
1135     * the self node. <\p>
1136     *
1137     * @param context The context node of this traversal. This is the point
1138     * that the traversal starts from.
1139     * @return the first node in the traversal.
1140     */
1141    public int first(int context)
1142    {
1143      return getParent(context);
1144    }
1145
1146    /**
1147     * By the nature of the stateless traversal, the context node can not be
1148     * returned or the iteration will go into an infinate loop.  So to traverse
1149     * an axis, the first function must be used to get the first node.
1150     *
1151     * <p>This method needs to be overloaded only by those axis that process
1152     * the self node. <\p>
1153     *
1154     * @param context The context node of this traversal. This is the point
1155     * of origin for the traversal -- its "root node" or starting point.
1156     * @param expandedTypeID The expanded type ID that must match.
1157     *
1158     * @return the first node in the traversal.
1159     */
1160    public int first(int current, int expandedTypeID)
1161    {
1162			// Compute in ID space
1163      current = makeNodeIdentity(current);
1164
1165      while (NULL != (current = m_parent.elementAt(current)))
1166      {
1167        if (m_exptype.elementAt(current) == expandedTypeID)
1168          return makeNodeHandle(current);
1169      }
1170
1171      return NULL;
1172    }
1173
1174
1175    /**
1176     * Traverse to the next node after the current node.
1177     *
1178     * @param context The context node of this iteration.
1179     * @param current The current node of the iteration.
1180     *
1181     * @return the next node in the iteration, or DTM.NULL.
1182     */
1183    public int next(int context, int current)
1184    {
1185
1186      return NULL;
1187    }
1188
1189
1190
1191    /**
1192     * Traverse to the next node after the current node that is matched
1193     * by the expanded type ID.
1194     *
1195     * @param context The context node of this iteration.
1196     * @param current The current node of the iteration.
1197     * @param expandedTypeID The expanded type ID that must match.
1198     *
1199     * @return the next node in the iteration, or DTM.NULL.
1200     */
1201    public int next(int context, int current, int expandedTypeID)
1202    {
1203
1204      return NULL;
1205    }
1206  }
1207
1208  /**
1209   * Implements traversal of the Ancestor access, in reverse document order.
1210   */
1211  private class PrecedingTraverser extends DTMAxisTraverser
1212  {
1213
1214    /**
1215     * Tell if the current identity is an ancestor of the context identity.
1216     * This is an expensive operation, made worse by the stateless traversal.
1217     * But the preceding axis is used fairly infrequently.
1218     *
1219     * @param contextIdent The context node of the axis traversal.
1220     * @param currentIdent The node in question.
1221     * @return true if the currentIdent node is an ancestor of contextIdent.
1222     */
1223    protected boolean isAncestor(int contextIdent, int currentIdent)
1224    {
1225			// %REVIEW% See comments in IsAfterAxis; using the "successor" of
1226			// contextIdent is probably more efficient.
1227      for (contextIdent = m_parent.elementAt(contextIdent); DTM.NULL != contextIdent;
1228              contextIdent = m_parent.elementAt(contextIdent))
1229      {
1230        if (contextIdent == currentIdent)
1231          return true;
1232      }
1233
1234      return false;
1235    }
1236
1237    /**
1238     * Traverse to the next node after the current node.
1239     *
1240     * @param context The context node of this iteration.
1241     * @param current The current node of the iteration.
1242     *
1243     * @return the next node in the iteration, or DTM.NULL.
1244     */
1245    public int next(int context, int current)
1246    {
1247			// compute in ID space
1248      int subtreeRootIdent = makeNodeIdentity(context);
1249
1250      for (current = makeNodeIdentity(current) - 1; current >= 0; current--)
1251      {
1252        short type = _type(current);
1253
1254        if (ATTRIBUTE_NODE == type || NAMESPACE_NODE == type
1255                || isAncestor(subtreeRootIdent, current))
1256          continue;
1257
1258        return makeNodeHandle(current);  // make handle.
1259      }
1260
1261      return NULL;
1262    }
1263
1264    /**
1265     * Traverse to the next node after the current node that is matched
1266     * by the expanded type ID.
1267     *
1268     * @param context The context node of this iteration.
1269     * @param current The current node of the iteration.
1270     * @param expandedTypeID The expanded type ID that must match.
1271     *
1272     * @return the next node in the iteration, or DTM.NULL.
1273     */
1274    public int next(int context, int current, int expandedTypeID)
1275    {
1276			// Compute in ID space
1277      int subtreeRootIdent = makeNodeIdentity(context);
1278
1279      for (current = makeNodeIdentity(current) - 1; current >= 0; current--)
1280      {
1281        int exptype = m_exptype.elementAt(current);
1282
1283        if (exptype != expandedTypeID
1284                || isAncestor(subtreeRootIdent, current))
1285          continue;
1286
1287        return makeNodeHandle(current);  // make handle.
1288      }
1289
1290      return NULL;
1291    }
1292  }
1293
1294  /**
1295   * Implements traversal of the Ancestor and the Preceding axis,
1296   * in reverse document order.
1297   */
1298  private class PrecedingAndAncestorTraverser extends DTMAxisTraverser
1299  {
1300
1301    /**
1302     * Traverse to the next node after the current node.
1303     *
1304     * @param context The context node of this iteration.
1305     * @param current The current node of the iteration.
1306     *
1307     * @return the next node in the iteration, or DTM.NULL.
1308     */
1309    public int next(int context, int current)
1310    {
1311			// Compute in ID space
1312      int subtreeRootIdent = makeNodeIdentity(context );
1313
1314      for (current = makeNodeIdentity(current) - 1; current >= 0; current--)
1315      {
1316        short type = _type(current);
1317
1318        if (ATTRIBUTE_NODE == type || NAMESPACE_NODE == type)
1319          continue;
1320
1321        return makeNodeHandle(current);  // make handle.
1322      }
1323
1324      return NULL;
1325    }
1326
1327    /**
1328     * Traverse to the next node after the current node that is matched
1329     * by the expanded type ID.
1330     *
1331     * @param context The context node of this iteration.
1332     * @param current The current node of the iteration.
1333     * @param expandedTypeID The expanded type ID that must match.
1334     *
1335     * @return the next node in the iteration, or DTM.NULL.
1336     */
1337    public int next(int context, int current, int expandedTypeID)
1338    {
1339			// Compute in ID space
1340      int subtreeRootIdent = makeNodeIdentity(context);
1341
1342      for (current = makeNodeIdentity(current) - 1; current >= 0; current--)
1343      {
1344        int exptype = m_exptype.elementAt(current);
1345
1346        if (exptype != expandedTypeID)
1347          continue;
1348
1349        return makeNodeHandle(current);  // make handle.
1350      }
1351
1352      return NULL;
1353    }
1354  }
1355
1356  /**
1357   * Implements traversal of the Ancestor access, in reverse document order.
1358   */
1359  private class PrecedingSiblingTraverser extends DTMAxisTraverser
1360  {
1361
1362    /**
1363     * Traverse to the next node after the current node.
1364     *
1365     * @param context The context node of this iteration.
1366     * @param current The current node of the iteration.
1367     *
1368     * @return the next node in the iteration, or DTM.NULL.
1369     */
1370    public int next(int context, int current)
1371    {
1372      return getPreviousSibling(current);
1373    }
1374
1375    /**
1376     * Traverse to the next node after the current node that is matched
1377     * by the expanded type ID.
1378     *
1379     * @param context The context node of this iteration.
1380     * @param current The current node of the iteration.
1381     * @param expandedTypeID The expanded type ID that must match.
1382     *
1383     * @return the next node in the iteration, or DTM.NULL.
1384     */
1385    public int next(int context, int current, int expandedTypeID)
1386    {
1387
1388      while (DTM.NULL != (current = getPreviousSibling(current)))
1389      {
1390        if (getExpandedTypeID(current) == expandedTypeID)
1391          return current;
1392      }
1393
1394      return NULL;
1395    }
1396  }
1397
1398  /**
1399   * Implements traversal of the Self axis.
1400   */
1401  private class SelfTraverser extends DTMAxisTraverser
1402  {
1403
1404    /**
1405     * By the nature of the stateless traversal, the context node can not be
1406     * returned or the iteration will go into an infinate loop.  To see if
1407     * the self node should be processed, use this function.
1408     *
1409     * @param context The context node of this traversal.
1410     *
1411     * @return the first node in the traversal.
1412     */
1413    public int first(int context)
1414    {
1415      return context;
1416    }
1417
1418    /**
1419     * By the nature of the stateless traversal, the context node can not be
1420     * returned or the iteration will go into an infinate loop.  To see if
1421     * the self node should be processed, use this function.  If the context
1422     * node does not match the expanded type ID, this function will return
1423     * false.
1424     *
1425     * @param context The context node of this traversal.
1426     * @param expandedTypeID The expanded type ID that must match.
1427     *
1428     * @return the first node in the traversal.
1429     */
1430    public int first(int context, int expandedTypeID)
1431    {
1432      return (getExpandedTypeID(context) == expandedTypeID) ? context : NULL;
1433    }
1434
1435    /**
1436     * Traverse to the next node after the current node.
1437     *
1438     * @param context The context node of this iteration.
1439     * @param current The current node of the iteration.
1440     *
1441     * @return Always return NULL for this axis.
1442     */
1443    public int next(int context, int current)
1444    {
1445      return NULL;
1446    }
1447
1448    /**
1449     * Traverse to the next node after the current node that is matched
1450     * by the expanded type ID.
1451     *
1452     * @param context The context node of this iteration.
1453     * @param current The current node of the iteration.
1454     * @param expandedTypeID The expanded type ID that must match.
1455     *
1456     * @return the next node in the iteration, or DTM.NULL.
1457     */
1458    public int next(int context, int current, int expandedTypeID)
1459    {
1460      return NULL;
1461    }
1462  }
1463
1464  /**
1465   * Implements traversal of the Ancestor access, in reverse document order.
1466   */
1467  private class AllFromRootTraverser extends AllFromNodeTraverser
1468  {
1469
1470    /**
1471     * Return the root.
1472     *
1473     * @param context The context node of this traversal.
1474     *
1475     * @return the first node in the traversal.
1476     */
1477    public int first(int context)
1478    {
1479      return getDocumentRoot(context);
1480    }
1481
1482    /**
1483     * Return the root if it matches the expanded type ID.
1484     *
1485     * @param context The context node of this traversal.
1486     * @param expandedTypeID The expanded type ID that must match.
1487     *
1488     * @return the first node in the traversal.
1489     */
1490    public int first(int context, int expandedTypeID)
1491    {
1492      return (getExpandedTypeID(getDocumentRoot(context)) == expandedTypeID)
1493             ? context : next(context, context, expandedTypeID);
1494    }
1495
1496    /**
1497     * Traverse to the next node after the current node.
1498     *
1499     * @param context The context node of this iteration.
1500     * @param current The current node of the iteration.
1501     *
1502     * @return the next node in the iteration, or DTM.NULL.
1503     */
1504    public int next(int context, int current)
1505    {
1506			// Compute in ID space
1507      int subtreeRootIdent = makeNodeIdentity(context);
1508
1509      for (current = makeNodeIdentity(current) + 1; ; current++)
1510      {
1511				// Kluge test: Just make sure +1 yielded a real node
1512        int type = _type(current);  // may call nextNode()
1513        if (type == NULL)
1514          return NULL;
1515
1516        return makeNodeHandle(current);  // make handle.
1517      }
1518    }
1519
1520    /**
1521     * Traverse to the next node after the current node that is matched
1522     * by the expanded type ID.
1523     *
1524     * @param context The context node of this iteration.
1525     * @param current The current node of the iteration.
1526     * @param expandedTypeID The expanded type ID that must match.
1527     *
1528     * @return the next node in the iteration, or DTM.NULL.
1529     */
1530    public int next(int context, int current, int expandedTypeID)
1531    {
1532			// Compute in ID space
1533      int subtreeRootIdent = makeNodeIdentity(context);
1534
1535      for (current = makeNodeIdentity(current) + 1; ; current++)
1536      {
1537        int exptype = _exptype(current);  // may call nextNode()
1538
1539        if (exptype == NULL)
1540          return NULL;
1541
1542        if (exptype != expandedTypeID)
1543          continue;
1544
1545        return makeNodeHandle(current);  // make handle.
1546      }
1547    }
1548  }
1549
1550  /**
1551   * Implements traversal of the Self axis.
1552   */
1553  private class RootTraverser extends AllFromRootTraverser
1554  {
1555    /**
1556     * Return the root if it matches the expanded type ID,
1557     * else return null (nothing found)
1558     *
1559     * @param context The context node of this traversal.
1560     * @param expandedTypeID The expanded type ID that must match.
1561     *
1562     * @return the first node in the traversal.
1563     */
1564    public int first(int context, int expandedTypeID)
1565    {
1566      int root=getDocumentRoot(context);
1567      return (getExpandedTypeID(root) == expandedTypeID)
1568	? root : NULL;
1569    }
1570
1571    /**
1572     * Traverse to the next node after the current node.
1573     *
1574     * @param context The context node of this iteration.
1575     * @param current The current node of the iteration.
1576     *
1577     * @return Always return NULL for this axis.
1578     */
1579    public int next(int context, int current)
1580    {
1581      return NULL;
1582    }
1583
1584    /**
1585     * Traverse to the next node after the current node that is matched
1586     * by the expanded type ID.
1587     *
1588     * @param context The context node of this iteration.
1589     * @param current The current node of the iteration.
1590     * @param expandedTypeID The expanded type ID that must match.
1591     *
1592     * @return the next node in the iteration, or DTM.NULL.
1593     */
1594    public int next(int context, int current, int expandedTypeID)
1595    {
1596      return NULL;
1597    }
1598  }
1599
1600  /**
1601   * A non-xpath axis, returns all nodes that aren't namespaces or attributes,
1602   * from and including the root.
1603   */
1604  private class DescendantOrSelfFromRootTraverser extends DescendantTraverser
1605  {
1606
1607    /**
1608     * Get the first potential identity that can be returned, which is the axis
1609     * root context in this case.
1610     *
1611     * @param identity The node identity of the root context of the traversal.
1612     *
1613     * @return The identity argument.
1614     */
1615    protected int getFirstPotential(int identity)
1616    {
1617      return identity;
1618    }
1619
1620    /**
1621     * Get the first potential identity that can be returned.
1622     * @param handle handle to the root context.
1623     * @return identity of the root of the subtree.
1624     */
1625    protected int getSubtreeRoot(int handle)
1626    {
1627			// %REVIEW% Shouldn't this always be 0?
1628      return makeNodeIdentity(getDocument());
1629    }
1630
1631    /**
1632     * Return the root.
1633     *
1634     * @param context The context node of this traversal.
1635     *
1636     * @return the first node in the traversal.
1637     */
1638    public int first(int context)
1639    {
1640      return getDocumentRoot(context);
1641    }
1642
1643    /**
1644     * By the nature of the stateless traversal, the context node can not be
1645     * returned or the iteration will go into an infinate loop.  So to traverse
1646     * an axis, the first function must be used to get the first node.
1647     *
1648     * <p>This method needs to be overloaded only by those axis that process
1649     * the self node. <\p>
1650     *
1651     * @param context The context node of this traversal. This is the point
1652     * of origin for the traversal -- its "root node" or starting point.
1653     * @param expandedTypeID The expanded type ID that must match.
1654     *
1655     * @return the first node in the traversal.
1656     */
1657    public int first(int context, int expandedTypeID)
1658    {
1659      if (isIndexed(expandedTypeID))
1660      {
1661        int identity = 0;
1662        int firstPotential = getFirstPotential(identity);
1663
1664        return makeNodeHandle(getNextIndexed(identity, firstPotential, expandedTypeID));
1665      }
1666
1667      int root = first(context);
1668      return next(root, root, expandedTypeID);
1669    }
1670  }
1671
1672  /**
1673   * A non-xpath axis, returns all nodes that aren't namespaces or attributes,
1674   * from but not including the root.
1675   */
1676  private class DescendantFromRootTraverser extends DescendantTraverser
1677  {
1678
1679    /**
1680     * Get the first potential identity that can be returned, which is the axis
1681     * root context in this case.
1682     *
1683     * @param identity The node identity of the root context of the traversal.
1684     *
1685     * @return The identity argument.
1686     */
1687    protected int getFirstPotential(int identity)
1688    {
1689      return _firstch(0);
1690    }
1691
1692    /**
1693     * Get the first potential identity that can be returned.
1694     * @param handle handle to the root context.
1695     * @return identity of the root of the subtree.
1696     */
1697    protected int getSubtreeRoot(int handle)
1698    {
1699      return 0;
1700    }
1701
1702    /**
1703     * Return the root.
1704     *
1705     * @param context The context node of this traversal.
1706     *
1707     * @return the first node in the traversal.
1708     */
1709    public int first(int context)
1710    {
1711      return makeNodeHandle(_firstch(0));
1712    }
1713
1714    /**
1715     * By the nature of the stateless traversal, the context node can not be
1716     * returned or the iteration will go into an infinate loop.  So to traverse
1717     * an axis, the first function must be used to get the first node.
1718     *
1719     * <p>This method needs to be overloaded only by those axis that process
1720     * the self node. <\p>
1721     *
1722     * @param context The context node of this traversal. This is the point
1723     * of origin for the traversal -- its "root node" or starting point.
1724     * @param expandedTypeID The expanded type ID that must match.
1725     *
1726     * @return the first node in the traversal.
1727     */
1728    public int first(int context, int expandedTypeID)
1729    {
1730      if (isIndexed(expandedTypeID))
1731      {
1732        int identity = 0;
1733        int firstPotential = getFirstPotential(identity);
1734
1735        return makeNodeHandle(getNextIndexed(identity, firstPotential, expandedTypeID));
1736      }
1737
1738      int root = getDocumentRoot(context);
1739      return next(root, root, expandedTypeID);
1740    }
1741
1742  }
1743
1744}
1745