Home | History | Annotate | Download | only in ref
      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  */
     21 package org.apache.xml.dtm.ref;
     22 
     23 import org.apache.xml.dtm.*;
     24 
     25 import javax.xml.transform.Source;
     26 
     27 import org.apache.xml.utils.XMLStringFactory;
     28 
     29 import org.apache.xml.res.XMLErrorResources;
     30 import 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  * */
     40 public 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