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