Home | History | Annotate | Download | only in sax2dtm
      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: SAX2DTM2.java 468653 2006-10-28 07:07:05Z minchau $
     20  */
     21 package org.apache.xml.dtm.ref.sax2dtm;
     22 
     23 import org.apache.xml.dtm.*;
     24 import org.apache.xml.dtm.ref.*;
     25 import org.apache.xml.utils.FastStringBuffer;
     26 import org.apache.xml.utils.XMLString;
     27 import org.apache.xml.utils.XMLStringDefault;
     28 import org.apache.xml.utils.XMLStringFactory;
     29 import org.apache.xml.res.XMLMessages;
     30 import org.apache.xml.res.XMLErrorResources;
     31 import org.apache.xml.serializer.SerializationHandler;
     32 
     33 import javax.xml.transform.Source;
     34 import java.util.Vector;
     35 import org.apache.xml.utils.SuballocatedIntVector;
     36 import org.xml.sax.*;
     37 
     38 /**
     39  * SAX2DTM2 is an optimized version of SAX2DTM which is used in non-incremental situation.
     40  * It is used as the super class of the XSLTC SAXImpl. Many of the interfaces in SAX2DTM
     41  * and DTMDefaultBase are overridden in SAX2DTM2 in order to allow fast, efficient
     42  * access to the DTM model. Some nested iterators in DTMDefaultBaseIterators
     43  * are also overridden in SAX2DTM2 for performance reasons.
     44  * <p>
     45  * Performance is the biggest consideration in the design of SAX2DTM2. To make the code most
     46  * efficient, the incremental support is dropped in SAX2DTM2, which means that you should not
     47  * use it in incremental situation. To reduce the overhead of pulling data from the DTM model,
     48  * a few core interfaces in SAX2DTM2 have direct access to the internal arrays of the
     49  * SuballocatedIntVectors.
     50  * <p>
     51  * The design of SAX2DTM2 may limit its extensibilty. If you have a reason to extend the
     52  * SAX2DTM model, please extend from SAX2DTM instead of this class.
     53  * <p>
     54  * TODO: This class is currently only used by XSLTC. We need to investigate the possibility
     55  * of also using it in Xalan-J Interpretive. Xalan's performance is likely to get an instant
     56  * boost if we use SAX2DTM2 instead of SAX2DTM in non-incremental case.
     57  * <p>
     58  * %MK% The code in this class is critical to the XSLTC_DTM performance. Be very careful
     59  * when making changes here!
     60  */
     61 public class SAX2DTM2 extends SAX2DTM
     62 {
     63 
     64   /****************************************************************
     65    *       Optimized version of the nested iterators
     66    ****************************************************************/
     67 
     68   /**
     69    * Iterator that returns all immediate children of a given node
     70    */
     71   public final class ChildrenIterator extends InternalAxisIteratorBase
     72   {
     73 
     74     /**
     75      * Setting start to END should 'close' the iterator,
     76      * i.e. subsequent call to next() should return END.
     77      * <p>
     78      * If the iterator is not restartable, this has no effect.
     79      * %REVIEW% Should it return/throw something in that case,
     80      * or set current node to END, to indicate request-not-honored?
     81      *
     82      * @param node Sets the root of the iteration.
     83      *
     84      * @return A DTMAxisIterator set to the start of the iteration.
     85      */
     86     public DTMAxisIterator setStartNode(int node)
     87     {
     88 //%HZ%: Added reference to DTMDefaultBase.ROOTNODE back in, temporarily
     89       if (node == DTMDefaultBase.ROOTNODE)
     90         node = getDocument();
     91       if (_isRestartable)
     92       {
     93         _startNode = node;
     94         _currentNode = (node == DTM.NULL) ? DTM.NULL
     95                                           : _firstch2(makeNodeIdentity(node));
     96 
     97         return resetPosition();
     98       }
     99 
    100       return this;
    101     }
    102 
    103     /**
    104      * Get the next node in the iteration.
    105      *
    106      * @return The next node handle in the iteration, or END if no more
    107      * are available.
    108      */
    109     public int next()
    110     {
    111       if (_currentNode != NULL) {
    112         int node = _currentNode;
    113         _currentNode = _nextsib2(node);
    114         return returnNode(makeNodeHandle(node));
    115       }
    116 
    117       return END;
    118     }
    119   }  // end of ChildrenIterator
    120 
    121   /**
    122    * Iterator that returns the parent of a given node. Note that
    123    * this delivers only a single node; if you want all the ancestors,
    124    * see AncestorIterator.
    125    */
    126   public final class ParentIterator extends InternalAxisIteratorBase
    127   {
    128 
    129     /** The extended type ID that was requested. */
    130     private int _nodeType = DTM.NULL;
    131 
    132     /**
    133      * Set start to END should 'close' the iterator,
    134      * i.e. subsequent call to next() should return END.
    135      *
    136      * @param node Sets the root of the iteration.
    137      *
    138      * @return A DTMAxisIterator set to the start of the iteration.
    139      */
    140     public DTMAxisIterator setStartNode(int node)
    141     {
    142 //%HZ%: Added reference to DTMDefaultBase.ROOTNODE back in, temporarily
    143       if (node == DTMDefaultBase.ROOTNODE)
    144         node = getDocument();
    145       if (_isRestartable)
    146       {
    147         _startNode = node;
    148 
    149         if (node != DTM.NULL)
    150           _currentNode = _parent2(makeNodeIdentity(node));
    151         else
    152           _currentNode = DTM.NULL;
    153 
    154         return resetPosition();
    155       }
    156 
    157       return this;
    158     }
    159 
    160     /**
    161      * Set the node type of the parent that we're looking for.
    162      * Note that this does _not_ mean "find the nearest ancestor of
    163      * this type", but "yield the parent if it is of this type".
    164      *
    165      *
    166      * @param type extended type ID.
    167      *
    168      * @return ParentIterator configured with the type filter set.
    169      */
    170     public DTMAxisIterator setNodeType(final int type)
    171     {
    172 
    173       _nodeType = type;
    174 
    175       return this;
    176     }
    177 
    178     /**
    179      * Get the next node in the iteration. In this case, we return
    180      * only the immediate parent, _if_ it matches the requested nodeType.
    181      *
    182      * @return The next node handle in the iteration, or END.
    183      */
    184     public int next()
    185     {
    186       int result = _currentNode;
    187       if (result == END)
    188         return DTM.NULL;
    189 
    190       // %OPT% The most common case is handled first.
    191       if (_nodeType == NULL) {
    192         _currentNode = END;
    193         return returnNode(makeNodeHandle(result));
    194       }
    195       else if (_nodeType >= DTM.NTYPES) {
    196         if (_nodeType == _exptype2(result)) {
    197           _currentNode = END;
    198 	  return returnNode(makeNodeHandle(result));
    199         }
    200       }
    201       else {
    202         if (_nodeType == _type2(result)) {
    203 	  _currentNode = END;
    204 	  return returnNode(makeNodeHandle(result));
    205         }
    206       }
    207 
    208       return DTM.NULL;
    209     }
    210   }  // end of ParentIterator
    211 
    212   /**
    213    * Iterator that returns children of a given type for a given node.
    214    * The functionality chould be achieved by putting a filter on top
    215    * of a basic child iterator, but a specialised iterator is used
    216    * for efficiency (both speed and size of translet).
    217    */
    218   public final class TypedChildrenIterator extends InternalAxisIteratorBase
    219   {
    220 
    221     /** The extended type ID that was requested. */
    222     private final int _nodeType;
    223 
    224     /**
    225      * Constructor TypedChildrenIterator
    226      *
    227      *
    228      * @param nodeType The extended type ID being requested.
    229      */
    230     public TypedChildrenIterator(int nodeType)
    231     {
    232       _nodeType = nodeType;
    233     }
    234 
    235     /**
    236      * Set start to END should 'close' the iterator,
    237      * i.e. subsequent call to next() should return END.
    238      *
    239      * @param node Sets the root of the iteration.
    240      *
    241      * @return A DTMAxisIterator set to the start of the iteration.
    242      */
    243     public DTMAxisIterator setStartNode(int node)
    244     {
    245 //%HZ%: Added reference to DTMDefaultBase.ROOTNODE back in, temporarily
    246       if (node == DTMDefaultBase.ROOTNODE)
    247         node = getDocument();
    248       if (_isRestartable)
    249       {
    250         _startNode = node;
    251         _currentNode = (node == DTM.NULL)
    252                                    ? DTM.NULL
    253                                    : _firstch2(makeNodeIdentity(_startNode));
    254 
    255         return resetPosition();
    256       }
    257 
    258       return this;
    259     }
    260 
    261     /**
    262      * Get the next node in the iteration.
    263      *
    264      * @return The next node handle in the iteration, or END.
    265      */
    266     public int next()
    267     {
    268       int node = _currentNode;
    269       if (node == DTM.NULL)
    270         return DTM.NULL;
    271 
    272       final int nodeType = _nodeType;
    273 
    274       if (nodeType != DTM.ELEMENT_NODE) {
    275         while (node != DTM.NULL && _exptype2(node) != nodeType) {
    276           node = _nextsib2(node);
    277         }
    278       }
    279       // %OPT% If the nodeType is element (matching child::*), we only
    280       // need to compare the expType with DTM.NTYPES. A child node of
    281       // an element can be either an element, text, comment or
    282       // processing instruction node. Only element node has an extended
    283       // type greater than or equal to DTM.NTYPES.
    284       else {
    285       	int eType;
    286       	while (node != DTM.NULL) {
    287       	  eType = _exptype2(node);
    288       	  if (eType >= DTM.NTYPES)
    289       	    break;
    290       	  else
    291       	    node = _nextsib2(node);
    292       	}
    293       }
    294 
    295       if (node == DTM.NULL) {
    296         _currentNode = DTM.NULL;
    297         return DTM.NULL;
    298       } else {
    299         _currentNode = _nextsib2(node);
    300         return returnNode(makeNodeHandle(node));
    301       }
    302 
    303     }
    304 
    305     /**
    306      * Return the node at the given position.
    307      */
    308     public int getNodeByPosition(int position)
    309     {
    310       if (position <= 0)
    311         return DTM.NULL;
    312 
    313       int node = _currentNode;
    314       int pos = 0;
    315 
    316       final int nodeType = _nodeType;
    317       if (nodeType != DTM.ELEMENT_NODE) {
    318         while (node != DTM.NULL) {
    319           if (_exptype2(node) == nodeType) {
    320             pos++;
    321             if (pos == position)
    322               return makeNodeHandle(node);
    323           }
    324 
    325           node = _nextsib2(node);
    326         }
    327         return NULL;
    328       }
    329       else {
    330       	while (node != DTM.NULL) {
    331       	  if (_exptype2(node) >= DTM.NTYPES) {
    332       	    pos++;
    333       	    if (pos == position)
    334       	      return makeNodeHandle(node);
    335       	  }
    336       	  node = _nextsib2(node);
    337       	}
    338       	return NULL;
    339       }
    340     }
    341 
    342   }  // end of TypedChildrenIterator
    343 
    344   /**
    345    * Iterator that returns the namespace nodes as defined by the XPath data model
    346    * for a given node, filtered by extended type ID.
    347    */
    348   public class TypedRootIterator extends RootIterator
    349   {
    350 
    351     /** The extended type ID that was requested. */
    352     private final int _nodeType;
    353 
    354     /**
    355      * Constructor TypedRootIterator
    356      *
    357      * @param nodeType The extended type ID being requested.
    358      */
    359     public TypedRootIterator(int nodeType)
    360     {
    361       super();
    362       _nodeType = nodeType;
    363     }
    364 
    365     /**
    366      * Get the next node in the iteration.
    367      *
    368      * @return The next node handle in the iteration, or END.
    369      */
    370     public int next()
    371     {
    372       if(_startNode == _currentNode)
    373         return NULL;
    374 
    375       final int node = _startNode;
    376       int expType = _exptype2(makeNodeIdentity(node));
    377 
    378       _currentNode = node;
    379 
    380       if (_nodeType >= DTM.NTYPES) {
    381         if (_nodeType == expType) {
    382           return returnNode(node);
    383         }
    384       }
    385       else {
    386         if (expType < DTM.NTYPES) {
    387           if (expType == _nodeType) {
    388             return returnNode(node);
    389           }
    390         }
    391         else {
    392           if (m_extendedTypes[expType].getNodeType() == _nodeType) {
    393             return returnNode(node);
    394           }
    395         }
    396       }
    397 
    398       return NULL;
    399     }
    400   }  // end of TypedRootIterator
    401 
    402   /**
    403    * Iterator that returns all siblings of a given node.
    404    */
    405   public class FollowingSiblingIterator extends InternalAxisIteratorBase
    406   {
    407 
    408     /**
    409      * Set start to END should 'close' the iterator,
    410      * i.e. subsequent call to next() should return END.
    411      *
    412      * @param node Sets the root of the iteration.
    413      *
    414      * @return A DTMAxisIterator set to the start of the iteration.
    415      */
    416     public DTMAxisIterator setStartNode(int node)
    417     {
    418 //%HZ%: Added reference to DTMDefaultBase.ROOTNODE back in, temporarily
    419       if (node == DTMDefaultBase.ROOTNODE)
    420         node = getDocument();
    421       if (_isRestartable)
    422       {
    423         _startNode = node;
    424         _currentNode = makeNodeIdentity(node);
    425 
    426         return resetPosition();
    427       }
    428 
    429       return this;
    430     }
    431 
    432     /**
    433      * Get the next node in the iteration.
    434      *
    435      * @return The next node handle in the iteration, or END.
    436      */
    437     public int next()
    438     {
    439       _currentNode = (_currentNode == DTM.NULL) ? DTM.NULL
    440                                                 : _nextsib2(_currentNode);
    441       return returnNode(makeNodeHandle(_currentNode));
    442     }
    443   }  // end of FollowingSiblingIterator
    444 
    445   /**
    446    * Iterator that returns all following siblings of a given node.
    447    */
    448   public final class TypedFollowingSiblingIterator
    449           extends FollowingSiblingIterator
    450   {
    451 
    452     /** The extended type ID that was requested. */
    453     private final int _nodeType;
    454 
    455     /**
    456      * Constructor TypedFollowingSiblingIterator
    457      *
    458      *
    459      * @param type The extended type ID being requested.
    460      */
    461     public TypedFollowingSiblingIterator(int type)
    462     {
    463       _nodeType = type;
    464     }
    465 
    466     /**
    467      * Get the next node in the iteration.
    468      *
    469      * @return The next node handle in the iteration, or END.
    470      */
    471     public int next()
    472     {
    473       if (_currentNode == DTM.NULL) {
    474         return DTM.NULL;
    475       }
    476 
    477       int node = _currentNode;
    478       final int nodeType = _nodeType;
    479 
    480       if (nodeType != DTM.ELEMENT_NODE) {
    481         while ((node = _nextsib2(node)) != DTM.NULL && _exptype2(node) != nodeType) {}
    482       }
    483       else {
    484         while ((node = _nextsib2(node)) != DTM.NULL && _exptype2(node) < DTM.NTYPES) {}
    485       }
    486 
    487       _currentNode = node;
    488 
    489       return (node == DTM.NULL)
    490                       ? DTM.NULL
    491                       : returnNode(makeNodeHandle(node));
    492     }
    493 
    494   }  // end of TypedFollowingSiblingIterator
    495 
    496   /**
    497    * Iterator that returns attribute nodes (of what nodes?)
    498    */
    499   public final class AttributeIterator extends InternalAxisIteratorBase
    500   {
    501 
    502     // assumes caller will pass element nodes
    503 
    504     /**
    505      * Set start to END should 'close' the iterator,
    506      * i.e. subsequent call to next() should return END.
    507      *
    508      * @param node Sets the root of the iteration.
    509      *
    510      * @return A DTMAxisIterator set to the start of the iteration.
    511      */
    512     public DTMAxisIterator setStartNode(int node)
    513     {
    514 //%HZ%: Added reference to DTMDefaultBase.ROOTNODE back in, temporarily
    515       if (node == DTMDefaultBase.ROOTNODE)
    516         node = getDocument();
    517       if (_isRestartable)
    518       {
    519         _startNode = node;
    520         _currentNode = getFirstAttributeIdentity(makeNodeIdentity(node));
    521 
    522         return resetPosition();
    523       }
    524 
    525       return this;
    526     }
    527 
    528     /**
    529      * Get the next node in the iteration.
    530      *
    531      * @return The next node handle in the iteration, or END.
    532      */
    533     public int next()
    534     {
    535 
    536       final int node = _currentNode;
    537 
    538       if (node != NULL) {
    539         _currentNode = getNextAttributeIdentity(node);
    540         return returnNode(makeNodeHandle(node));
    541       }
    542 
    543       return NULL;
    544     }
    545   }  // end of AttributeIterator
    546 
    547   /**
    548    * Iterator that returns attribute nodes of a given type
    549    */
    550   public final class TypedAttributeIterator extends InternalAxisIteratorBase
    551   {
    552 
    553     /** The extended type ID that was requested. */
    554     private final int _nodeType;
    555 
    556     /**
    557      * Constructor TypedAttributeIterator
    558      *
    559      *
    560      * @param nodeType The extended type ID that is requested.
    561      */
    562     public TypedAttributeIterator(int nodeType)
    563     {
    564       _nodeType = nodeType;
    565     }
    566 
    567     // assumes caller will pass element nodes
    568 
    569     /**
    570      * Set start to END should 'close' the iterator,
    571      * i.e. subsequent call to next() should return END.
    572      *
    573      * @param node Sets the root of the iteration.
    574      *
    575      * @return A DTMAxisIterator set to the start of the iteration.
    576      */
    577     public DTMAxisIterator setStartNode(int node)
    578     {
    579       if (_isRestartable)
    580       {
    581         _startNode = node;
    582 
    583         _currentNode = getTypedAttribute(node, _nodeType);
    584 
    585         return resetPosition();
    586       }
    587 
    588       return this;
    589     }
    590 
    591     /**
    592      * Get the next node in the iteration.
    593      *
    594      * @return The next node handle in the iteration, or END.
    595      */
    596     public int next()
    597     {
    598 
    599       final int node = _currentNode;
    600 
    601       // singleton iterator, since there can only be one attribute of
    602       // a given type.
    603       _currentNode = NULL;
    604 
    605       return returnNode(node);
    606     }
    607   }  // end of TypedAttributeIterator
    608 
    609   /**
    610    * Iterator that returns preceding siblings of a given node
    611    */
    612   public class PrecedingSiblingIterator extends InternalAxisIteratorBase
    613   {
    614 
    615     /**
    616      * The node identity of _startNode for this iterator
    617      */
    618     protected int _startNodeID;
    619 
    620     /**
    621      * True if this iterator has a reversed axis.
    622      *
    623      * @return true.
    624      */
    625     public boolean isReverse()
    626     {
    627       return true;
    628     }
    629 
    630     /**
    631      * Set start to END should 'close' the iterator,
    632      * i.e. subsequent call to next() should return END.
    633      *
    634      * @param node Sets the root of the iteration.
    635      *
    636      * @return A DTMAxisIterator set to the start of the iteration.
    637      */
    638     public DTMAxisIterator setStartNode(int node)
    639     {
    640 //%HZ%: Added reference to DTMDefaultBase.ROOTNODE back in, temporarily
    641       if (node == DTMDefaultBase.ROOTNODE)
    642         node = getDocument();
    643       if (_isRestartable)
    644       {
    645         _startNode = node;
    646         node = _startNodeID = makeNodeIdentity(node);
    647 
    648         if(node == NULL)
    649         {
    650           _currentNode = node;
    651           return resetPosition();
    652         }
    653 
    654         int type = _type2(node);
    655         if(ExpandedNameTable.ATTRIBUTE == type
    656            || ExpandedNameTable.NAMESPACE == type )
    657         {
    658           _currentNode = node;
    659         }
    660         else
    661         {
    662           // Be careful to handle the Document node properly
    663           _currentNode = _parent2(node);
    664           if(NULL!=_currentNode)
    665             _currentNode = _firstch2(_currentNode);
    666           else
    667             _currentNode = node;
    668         }
    669 
    670         return resetPosition();
    671       }
    672 
    673       return this;
    674     }
    675 
    676     /**
    677      * Get the next node in the iteration.
    678      *
    679      * @return The next node handle in the iteration, or END.
    680      */
    681     public int next()
    682     {
    683 
    684       if (_currentNode == _startNodeID || _currentNode == DTM.NULL)
    685       {
    686         return NULL;
    687       }
    688       else
    689       {
    690         final int node = _currentNode;
    691         _currentNode = _nextsib2(node);
    692 
    693         return returnNode(makeNodeHandle(node));
    694       }
    695     }
    696   }  // end of PrecedingSiblingIterator
    697 
    698   /**
    699    * Iterator that returns preceding siblings of a given type for
    700    * a given node
    701    */
    702   public final class TypedPrecedingSiblingIterator
    703           extends PrecedingSiblingIterator
    704   {
    705 
    706     /** The extended type ID that was requested. */
    707     private final int _nodeType;
    708 
    709     /**
    710      * Constructor TypedPrecedingSiblingIterator
    711      *
    712      *
    713      * @param type The extended type ID being requested.
    714      */
    715     public TypedPrecedingSiblingIterator(int type)
    716     {
    717       _nodeType = type;
    718     }
    719 
    720     /**
    721      * Get the next node in the iteration.
    722      *
    723      * @return The next node handle in the iteration, or END.
    724      */
    725     public int next()
    726     {
    727       int node = _currentNode;
    728 
    729       final int nodeType = _nodeType;
    730       final int startNodeID = _startNodeID;
    731 
    732       if (nodeType != DTM.ELEMENT_NODE) {
    733         while (node != NULL && node != startNodeID && _exptype2(node) != nodeType) {
    734           node = _nextsib2(node);
    735         }
    736       }
    737       else {
    738         while (node != NULL && node != startNodeID && _exptype2(node) < DTM.NTYPES) {
    739           node = _nextsib2(node);
    740         }
    741       }
    742 
    743       if (node == DTM.NULL || node == startNodeID) {
    744         _currentNode = NULL;
    745         return NULL;
    746       }
    747       else {
    748         _currentNode = _nextsib2(node);
    749         return returnNode(makeNodeHandle(node));
    750       }
    751     }
    752 
    753     /**
    754      * Return the index of the last node in this iterator.
    755      */
    756     public int getLast()
    757     {
    758       if (_last != -1)
    759         return _last;
    760 
    761       setMark();
    762 
    763       int node = _currentNode;
    764       final int nodeType = _nodeType;
    765       final int startNodeID = _startNodeID;
    766 
    767       int last = 0;
    768       if (nodeType != DTM.ELEMENT_NODE) {
    769         while (node != NULL && node != startNodeID) {
    770           if (_exptype2(node) == nodeType) {
    771             last++;
    772           }
    773           node = _nextsib2(node);
    774         }
    775       }
    776       else {
    777         while (node != NULL && node != startNodeID) {
    778           if (_exptype2(node) >= DTM.NTYPES) {
    779             last++;
    780           }
    781           node = _nextsib2(node);
    782         }
    783       }
    784 
    785       gotoMark();
    786 
    787       return (_last = last);
    788     }
    789   }  // end of TypedPrecedingSiblingIterator
    790 
    791   /**
    792    * Iterator that returns preceding nodes of a given node.
    793    * This includes the node set {root+1, start-1}, but excludes
    794    * all ancestors, attributes, and namespace nodes.
    795    */
    796   public class PrecedingIterator extends InternalAxisIteratorBase
    797   {
    798 
    799     /** The max ancestors, but it can grow... */
    800     private final int _maxAncestors = 8;
    801 
    802     /**
    803      * The stack of start node + ancestors up to the root of the tree,
    804      *  which we must avoid.
    805      */
    806     protected int[] _stack = new int[_maxAncestors];
    807 
    808     /** (not sure yet... -sb) */
    809     protected int _sp, _oldsp;
    810 
    811     protected int _markedsp, _markedNode, _markedDescendant;
    812 
    813     /* _currentNode precedes candidates.  This is the identity, not the handle! */
    814 
    815     /**
    816      * True if this iterator has a reversed axis.
    817      *
    818      * @return true since this iterator is a reversed axis.
    819      */
    820     public boolean isReverse()
    821     {
    822       return true;
    823     }
    824 
    825     /**
    826      * Returns a deep copy of this iterator.   The cloned iterator is not reset.
    827      *
    828      * @return a deep copy of this iterator.
    829      */
    830     public DTMAxisIterator cloneIterator()
    831     {
    832       _isRestartable = false;
    833 
    834       try
    835       {
    836         final PrecedingIterator clone = (PrecedingIterator) super.clone();
    837         final int[] stackCopy = new int[_stack.length];
    838         System.arraycopy(_stack, 0, stackCopy, 0, _stack.length);
    839 
    840         clone._stack = stackCopy;
    841 
    842         // return clone.reset();
    843         return clone;
    844       }
    845       catch (CloneNotSupportedException e)
    846       {
    847         throw new DTMException(XMLMessages.createXMLMessage(XMLErrorResources.ER_ITERATOR_CLONE_NOT_SUPPORTED, null)); //"Iterator clone not supported.");
    848       }
    849     }
    850 
    851     /**
    852      * Set start to END should 'close' the iterator,
    853      * i.e. subsequent call to next() should return END.
    854      *
    855      * @param node Sets the root of the iteration.
    856      *
    857      * @return A DTMAxisIterator set to the start of the iteration.
    858      */
    859     public DTMAxisIterator setStartNode(int node)
    860     {
    861 //%HZ%: Added reference to DTMDefaultBase.ROOTNODE back in, temporarily
    862       if (node == DTMDefaultBase.ROOTNODE)
    863         node = getDocument();
    864       if (_isRestartable)
    865       {
    866         node = makeNodeIdentity(node);
    867 
    868         // iterator is not a clone
    869         int parent, index;
    870 
    871        if (_type2(node) == DTM.ATTRIBUTE_NODE)
    872          node = _parent2(node);
    873 
    874         _startNode = node;
    875         _stack[index = 0] = node;
    876 
    877        	parent=node;
    878 	while ((parent = _parent2(parent)) != NULL)
    879 	{
    880 	  if (++index == _stack.length)
    881 	  {
    882 	    final int[] stack = new int[index*2];
    883 	    System.arraycopy(_stack, 0, stack, 0, index);
    884 	    _stack = stack;
    885 	  }
    886 	  _stack[index] = parent;
    887         }
    888 
    889         if(index>0)
    890 	  --index; // Pop actual root node (if not start) back off the stack
    891 
    892         _currentNode=_stack[index]; // Last parent before root node
    893 
    894         _oldsp = _sp = index;
    895 
    896         return resetPosition();
    897       }
    898 
    899       return this;
    900     }
    901 
    902     /**
    903      * Get the next node in the iteration.
    904      *
    905      * @return The next node handle in the iteration, or END.
    906      */
    907     public int next()
    908     {
    909     	// Bugzilla 8324: We were forgetting to skip Attrs and NS nodes.
    910     	// Also recoded the loop controls for clarity and to flatten out
    911     	// the tail-recursion.
    912    	for(++_currentNode; _sp>=0; ++_currentNode)
    913    	{
    914    	  if(_currentNode < _stack[_sp])
    915    	  {
    916    	    int type = _type2(_currentNode);
    917    	    if(type != ATTRIBUTE_NODE && type != NAMESPACE_NODE)
    918    	      return returnNode(makeNodeHandle(_currentNode));
    919    	  }
    920    	  else
    921    	    --_sp;
    922    	}
    923    	return NULL;
    924     }
    925 
    926     // redefine DTMAxisIteratorBase's reset
    927 
    928     /**
    929      * Resets the iterator to the last start node.
    930      *
    931      * @return A DTMAxisIterator, which may or may not be the same as this
    932      *         iterator.
    933      */
    934     public DTMAxisIterator reset()
    935     {
    936 
    937       _sp = _oldsp;
    938 
    939       return resetPosition();
    940     }
    941 
    942     public void setMark() {
    943         _markedsp = _sp;
    944         _markedNode = _currentNode;
    945         _markedDescendant = _stack[0];
    946     }
    947 
    948     public void gotoMark() {
    949         _sp = _markedsp;
    950         _currentNode = _markedNode;
    951     }
    952   }  // end of PrecedingIterator
    953 
    954   /**
    955    * Iterator that returns preceding nodes of agiven type for a
    956    * given node. This includes the node set {root+1, start-1}, but
    957    * excludes all ancestors.
    958    */
    959   public final class TypedPrecedingIterator extends PrecedingIterator
    960   {
    961 
    962     /** The extended type ID that was requested. */
    963     private final int _nodeType;
    964 
    965     /**
    966      * Constructor TypedPrecedingIterator
    967      *
    968      *
    969      * @param type The extended type ID being requested.
    970      */
    971     public TypedPrecedingIterator(int type)
    972     {
    973       _nodeType = type;
    974     }
    975 
    976     /**
    977      * Get the next node in the iteration.
    978      *
    979      * @return The next node handle in the iteration, or END.
    980      */
    981     public int next()
    982     {
    983       int node = _currentNode;
    984       final int nodeType = _nodeType;
    985 
    986       if (nodeType >= DTM.NTYPES) {
    987         while (true) {
    988           node++;
    989 
    990           if (_sp < 0) {
    991             node = NULL;
    992             break;
    993           }
    994           else if (node >= _stack[_sp]) {
    995             if (--_sp < 0) {
    996               node = NULL;
    997               break;
    998             }
    999           }
   1000           else if (_exptype2(node) == nodeType) {
   1001             break;
   1002           }
   1003         }
   1004       }
   1005       else {
   1006         int expType;
   1007 
   1008         while (true) {
   1009           node++;
   1010 
   1011           if (_sp < 0) {
   1012             node = NULL;
   1013             break;
   1014           }
   1015           else if (node >= _stack[_sp]) {
   1016             if (--_sp < 0) {
   1017               node = NULL;
   1018               break;
   1019             }
   1020           }
   1021           else {
   1022             expType = _exptype2(node);
   1023             if (expType < DTM.NTYPES) {
   1024               if (expType == nodeType) {
   1025                 break;
   1026               }
   1027             }
   1028             else {
   1029               if (m_extendedTypes[expType].getNodeType() == nodeType) {
   1030                 break;
   1031               }
   1032             }
   1033           }
   1034         }
   1035       }
   1036 
   1037       _currentNode = node;
   1038 
   1039       return (node == NULL) ? NULL : returnNode(makeNodeHandle(node));
   1040     }
   1041   }  // end of TypedPrecedingIterator
   1042 
   1043   /**
   1044    * Iterator that returns following nodes of for a given node.
   1045    */
   1046   public class FollowingIterator extends InternalAxisIteratorBase
   1047   {
   1048     //DTMAxisTraverser m_traverser; // easier for now
   1049 
   1050     public FollowingIterator()
   1051     {
   1052       //m_traverser = getAxisTraverser(Axis.FOLLOWING);
   1053     }
   1054 
   1055     /**
   1056      * Set start to END should 'close' the iterator,
   1057      * i.e. subsequent call to next() should return END.
   1058      *
   1059      * @param node Sets the root of the iteration.
   1060      *
   1061      * @return A DTMAxisIterator set to the start of the iteration.
   1062      */
   1063     public DTMAxisIterator setStartNode(int node)
   1064     {
   1065 //%HZ%: Added reference to DTMDefaultBase.ROOTNODE back in, temporarily
   1066       if (node == DTMDefaultBase.ROOTNODE)
   1067         node = getDocument();
   1068       if (_isRestartable)
   1069       {
   1070         _startNode = node;
   1071 
   1072         //_currentNode = m_traverser.first(node);
   1073 
   1074         node = makeNodeIdentity(node);
   1075 
   1076         int first;
   1077         int type = _type2(node);
   1078 
   1079         if ((DTM.ATTRIBUTE_NODE == type) || (DTM.NAMESPACE_NODE == type))
   1080         {
   1081           node = _parent2(node);
   1082           first = _firstch2(node);
   1083 
   1084           if (NULL != first) {
   1085             _currentNode = makeNodeHandle(first);
   1086             return resetPosition();
   1087           }
   1088         }
   1089 
   1090         do
   1091         {
   1092           first = _nextsib2(node);
   1093 
   1094           if (NULL == first)
   1095             node = _parent2(node);
   1096         }
   1097         while (NULL == first && NULL != node);
   1098 
   1099         _currentNode = makeNodeHandle(first);
   1100 
   1101         // _currentNode precedes possible following(node) nodes
   1102         return resetPosition();
   1103       }
   1104 
   1105       return this;
   1106     }
   1107 
   1108     /**
   1109      * Get the next node in the iteration.
   1110      *
   1111      * @return The next node handle in the iteration, or END.
   1112      */
   1113     public int next()
   1114     {
   1115 
   1116       int node = _currentNode;
   1117 
   1118       //_currentNode = m_traverser.next(_startNode, _currentNode);
   1119       int current = makeNodeIdentity(node);
   1120 
   1121       while (true)
   1122       {
   1123         current++;
   1124 
   1125         int type = _type2(current);
   1126         if (NULL == type) {
   1127           _currentNode = NULL;
   1128           return returnNode(node);
   1129         }
   1130 
   1131         if (ATTRIBUTE_NODE == type || NAMESPACE_NODE == type)
   1132           continue;
   1133 
   1134         _currentNode = makeNodeHandle(current);
   1135         return returnNode(node);
   1136       }
   1137     }
   1138 
   1139   }  // end of FollowingIterator
   1140 
   1141   /**
   1142    * Iterator that returns following nodes of a given type for a given node.
   1143    */
   1144   public final class TypedFollowingIterator extends FollowingIterator
   1145   {
   1146 
   1147     /** The extended type ID that was requested. */
   1148     private final int _nodeType;
   1149 
   1150     /**
   1151      * Constructor TypedFollowingIterator
   1152      *
   1153      *
   1154      * @param type The extended type ID being requested.
   1155      */
   1156     public TypedFollowingIterator(int type)
   1157     {
   1158       _nodeType = type;
   1159     }
   1160 
   1161     /**
   1162      * Get the next node in the iteration.
   1163      *
   1164      * @return The next node handle in the iteration, or END.
   1165      */
   1166     public int next()
   1167     {
   1168       int current;
   1169       int node;
   1170       int type;
   1171 
   1172       final int nodeType = _nodeType;
   1173       int currentNodeID = makeNodeIdentity(_currentNode);
   1174 
   1175       if (nodeType >= DTM.NTYPES) {
   1176         do {
   1177           node = currentNodeID;
   1178 	  current = node;
   1179 
   1180           do {
   1181             current++;
   1182             type = _type2(current);
   1183           }
   1184           while (type != NULL && (ATTRIBUTE_NODE == type || NAMESPACE_NODE == type));
   1185 
   1186           currentNodeID = (type != NULL) ? current : NULL;
   1187         }
   1188         while (node != DTM.NULL && _exptype2(node) != nodeType);
   1189       }
   1190       else {
   1191         do {
   1192           node = currentNodeID;
   1193 	  current = node;
   1194 
   1195           do {
   1196             current++;
   1197             type = _type2(current);
   1198           }
   1199           while (type != NULL && (ATTRIBUTE_NODE == type || NAMESPACE_NODE == type));
   1200 
   1201           currentNodeID = (type != NULL) ? current : NULL;
   1202         }
   1203         while (node != DTM.NULL
   1204                && (_exptype2(node) != nodeType && _type2(node) != nodeType));
   1205       }
   1206 
   1207       _currentNode = makeNodeHandle(currentNodeID);
   1208       return (node == DTM.NULL ? DTM.NULL :returnNode(makeNodeHandle(node)));
   1209     }
   1210   }  // end of TypedFollowingIterator
   1211 
   1212   /**
   1213    * Iterator that returns the ancestors of a given node in document
   1214    * order.  (NOTE!  This was changed from the XSLTC code!)
   1215    */
   1216   public class AncestorIterator extends InternalAxisIteratorBase
   1217   {
   1218     // The initial size of the ancestor array
   1219     private static final int m_blocksize = 32;
   1220 
   1221     // The array for ancestor nodes. This array will grow dynamically.
   1222     int[] m_ancestors = new int[m_blocksize];
   1223 
   1224     // Number of ancestor nodes in the array
   1225     int m_size = 0;
   1226 
   1227     int m_ancestorsPos;
   1228 
   1229     int m_markedPos;
   1230 
   1231     /** The real start node for this axes, since _startNode will be adjusted. */
   1232     int m_realStartNode;
   1233 
   1234     /**
   1235      * Get start to END should 'close' the iterator,
   1236      * i.e. subsequent call to next() should return END.
   1237      *
   1238      * @return The root node of the iteration.
   1239      */
   1240     public int getStartNode()
   1241     {
   1242       return m_realStartNode;
   1243     }
   1244 
   1245     /**
   1246      * True if this iterator has a reversed axis.
   1247      *
   1248      * @return true since this iterator is a reversed axis.
   1249      */
   1250     public final boolean isReverse()
   1251     {
   1252       return true;
   1253     }
   1254 
   1255     /**
   1256      * Returns a deep copy of this iterator.  The cloned iterator is not reset.
   1257      *
   1258      * @return a deep copy of this iterator.
   1259      */
   1260     public DTMAxisIterator cloneIterator()
   1261     {
   1262       _isRestartable = false;  // must set to false for any clone
   1263 
   1264       try
   1265       {
   1266         final AncestorIterator clone = (AncestorIterator) super.clone();
   1267 
   1268         clone._startNode = _startNode;
   1269 
   1270         // return clone.reset();
   1271         return clone;
   1272       }
   1273       catch (CloneNotSupportedException e)
   1274       {
   1275         throw new DTMException(XMLMessages.createXMLMessage(XMLErrorResources.ER_ITERATOR_CLONE_NOT_SUPPORTED, null)); //"Iterator clone not supported.");
   1276       }
   1277     }
   1278 
   1279     /**
   1280      * Set start to END should 'close' the iterator,
   1281      * i.e. subsequent call to next() should return END.
   1282      *
   1283      * @param node Sets the root of the iteration.
   1284      *
   1285      * @return A DTMAxisIterator set to the start of the iteration.
   1286      */
   1287     public DTMAxisIterator setStartNode(int node)
   1288     {
   1289 //%HZ%: Added reference to DTMDefaultBase.ROOTNODE back in, temporarily
   1290       if (node == DTMDefaultBase.ROOTNODE)
   1291         node = getDocument();
   1292       m_realStartNode = node;
   1293 
   1294       if (_isRestartable)
   1295       {
   1296         int nodeID = makeNodeIdentity(node);
   1297         m_size = 0;
   1298 
   1299         if (nodeID == DTM.NULL) {
   1300           _currentNode = DTM.NULL;
   1301           m_ancestorsPos = 0;
   1302           return this;
   1303         }
   1304 
   1305         // Start from the current node's parent if
   1306         // _includeSelf is false.
   1307         if (!_includeSelf) {
   1308           nodeID = _parent2(nodeID);
   1309           node = makeNodeHandle(nodeID);
   1310         }
   1311 
   1312         _startNode = node;
   1313 
   1314         while (nodeID != END) {
   1315           //m_ancestors.addElement(node);
   1316           if (m_size >= m_ancestors.length)
   1317           {
   1318             int[] newAncestors = new int[m_size * 2];
   1319             System.arraycopy(m_ancestors, 0, newAncestors, 0, m_ancestors.length);
   1320             m_ancestors = newAncestors;
   1321           }
   1322 
   1323           m_ancestors[m_size++] = node;
   1324           nodeID = _parent2(nodeID);
   1325           node = makeNodeHandle(nodeID);
   1326         }
   1327 
   1328         m_ancestorsPos = m_size - 1;
   1329 
   1330         _currentNode = (m_ancestorsPos>=0)
   1331                                ? m_ancestors[m_ancestorsPos]
   1332                                : DTM.NULL;
   1333 
   1334         return resetPosition();
   1335       }
   1336 
   1337       return this;
   1338     }
   1339 
   1340     /**
   1341      * Resets the iterator to the last start node.
   1342      *
   1343      * @return A DTMAxisIterator, which may or may not be the same as this
   1344      *         iterator.
   1345      */
   1346     public DTMAxisIterator reset()
   1347     {
   1348 
   1349       m_ancestorsPos = m_size - 1;
   1350 
   1351       _currentNode = (m_ancestorsPos >= 0) ? m_ancestors[m_ancestorsPos]
   1352                                          : DTM.NULL;
   1353 
   1354       return resetPosition();
   1355     }
   1356 
   1357     /**
   1358      * Get the next node in the iteration.
   1359      *
   1360      * @return The next node handle in the iteration, or END.
   1361      */
   1362     public int next()
   1363     {
   1364 
   1365       int next = _currentNode;
   1366 
   1367       int pos = --m_ancestorsPos;
   1368 
   1369       _currentNode = (pos >= 0) ? m_ancestors[m_ancestorsPos]
   1370                                 : DTM.NULL;
   1371 
   1372       return returnNode(next);
   1373     }
   1374 
   1375     public void setMark() {
   1376         m_markedPos = m_ancestorsPos;
   1377     }
   1378 
   1379     public void gotoMark() {
   1380         m_ancestorsPos = m_markedPos;
   1381         _currentNode = m_ancestorsPos>=0 ? m_ancestors[m_ancestorsPos]
   1382                                          : DTM.NULL;
   1383     }
   1384   }  // end of AncestorIterator
   1385 
   1386   /**
   1387    * Typed iterator that returns the ancestors of a given node.
   1388    */
   1389   public final class TypedAncestorIterator extends AncestorIterator
   1390   {
   1391 
   1392     /** The extended type ID that was requested. */
   1393     private final int _nodeType;
   1394 
   1395     /**
   1396      * Constructor TypedAncestorIterator
   1397      *
   1398      *
   1399      * @param type The extended type ID being requested.
   1400      */
   1401     public TypedAncestorIterator(int type)
   1402     {
   1403       _nodeType = type;
   1404     }
   1405 
   1406     /**
   1407      * Set start to END should 'close' the iterator,
   1408      * i.e. subsequent call to next() should return END.
   1409      *
   1410      * @param node Sets the root of the iteration.
   1411      *
   1412      * @return A DTMAxisIterator set to the start of the iteration.
   1413      */
   1414     public DTMAxisIterator setStartNode(int node)
   1415     {
   1416 //%HZ%: Added reference to DTMDefaultBase.ROOTNODE back in, temporarily
   1417       if (node == DTMDefaultBase.ROOTNODE)
   1418         node = getDocument();
   1419       m_realStartNode = node;
   1420 
   1421       if (_isRestartable)
   1422       {
   1423         int nodeID = makeNodeIdentity(node);
   1424         m_size = 0;
   1425 
   1426         if (nodeID == DTM.NULL) {
   1427           _currentNode = DTM.NULL;
   1428           m_ancestorsPos = 0;
   1429           return this;
   1430         }
   1431 
   1432         final int nodeType = _nodeType;
   1433 
   1434         if (!_includeSelf) {
   1435           nodeID = _parent2(nodeID);
   1436           node = makeNodeHandle(nodeID);
   1437         }
   1438 
   1439         _startNode = node;
   1440 
   1441         if (nodeType >= DTM.NTYPES) {
   1442           while (nodeID != END) {
   1443             int eType = _exptype2(nodeID);
   1444 
   1445             if (eType == nodeType) {
   1446               if (m_size >= m_ancestors.length)
   1447               {
   1448               	int[] newAncestors = new int[m_size * 2];
   1449               	System.arraycopy(m_ancestors, 0, newAncestors, 0, m_ancestors.length);
   1450               	m_ancestors = newAncestors;
   1451               }
   1452               m_ancestors[m_size++] = makeNodeHandle(nodeID);
   1453             }
   1454             nodeID = _parent2(nodeID);
   1455           }
   1456         }
   1457         else {
   1458           while (nodeID != END) {
   1459             int eType = _exptype2(nodeID);
   1460 
   1461             if ((eType < DTM.NTYPES && eType == nodeType)
   1462                 || (eType >= DTM.NTYPES
   1463                     && m_extendedTypes[eType].getNodeType() == nodeType)) {
   1464               if (m_size >= m_ancestors.length)
   1465               {
   1466               	int[] newAncestors = new int[m_size * 2];
   1467               	System.arraycopy(m_ancestors, 0, newAncestors, 0, m_ancestors.length);
   1468               	m_ancestors = newAncestors;
   1469               }
   1470               m_ancestors[m_size++] = makeNodeHandle(nodeID);
   1471             }
   1472             nodeID = _parent2(nodeID);
   1473           }
   1474         }
   1475         m_ancestorsPos = m_size - 1;
   1476 
   1477         _currentNode = (m_ancestorsPos>=0)
   1478                                ? m_ancestors[m_ancestorsPos]
   1479                                : DTM.NULL;
   1480 
   1481         return resetPosition();
   1482       }
   1483 
   1484       return this;
   1485     }
   1486 
   1487     /**
   1488      * Return the node at the given position.
   1489      */
   1490     public int getNodeByPosition(int position)
   1491     {
   1492       if (position > 0 && position <= m_size) {
   1493         return m_ancestors[position-1];
   1494       }
   1495       else
   1496         return DTM.NULL;
   1497     }
   1498 
   1499     /**
   1500      * Returns the position of the last node within the iteration, as
   1501      * defined by XPath.
   1502      */
   1503     public int getLast() {
   1504       return m_size;
   1505     }
   1506   }  // end of TypedAncestorIterator
   1507 
   1508   /**
   1509    * Iterator that returns the descendants of a given node.
   1510    */
   1511   public class DescendantIterator extends InternalAxisIteratorBase
   1512   {
   1513 
   1514     /**
   1515      * Set start to END should 'close' the iterator,
   1516      * i.e. subsequent call to next() should return END.
   1517      *
   1518      * @param node Sets the root of the iteration.
   1519      *
   1520      * @return A DTMAxisIterator set to the start of the iteration.
   1521      */
   1522     public DTMAxisIterator setStartNode(int node)
   1523     {
   1524 //%HZ%: Added reference to DTMDefaultBase.ROOTNODE back in, temporarily
   1525       if (node == DTMDefaultBase.ROOTNODE)
   1526         node = getDocument();
   1527       if (_isRestartable)
   1528       {
   1529         node = makeNodeIdentity(node);
   1530         _startNode = node;
   1531 
   1532         if (_includeSelf)
   1533           node--;
   1534 
   1535         _currentNode = node;
   1536 
   1537         return resetPosition();
   1538       }
   1539 
   1540       return this;
   1541     }
   1542 
   1543     /**
   1544      * Tell if this node identity is a descendant.  Assumes that
   1545      * the node info for the element has already been obtained.
   1546      *
   1547      * This one-sided test works only if the parent has been
   1548      * previously tested and is known to be a descendent. It fails if
   1549      * the parent is the _startNode's next sibling, or indeed any node
   1550      * that follows _startNode in document order.  That may suffice
   1551      * for this iterator, but it's not really an isDescendent() test.
   1552      * %REVIEW% rename?
   1553      *
   1554      * @param identity The index number of the node in question.
   1555      * @return true if the index is a descendant of _startNode.
   1556      */
   1557     protected final boolean isDescendant(int identity)
   1558     {
   1559       return (_parent2(identity) >= _startNode) || (_startNode == identity);
   1560     }
   1561 
   1562     /**
   1563      * Get the next node in the iteration.
   1564      *
   1565      * @return The next node handle in the iteration, or END.
   1566      */
   1567     public int next()
   1568     {
   1569       final int startNode = _startNode;
   1570       if (startNode == NULL) {
   1571         return NULL;
   1572       }
   1573 
   1574       if (_includeSelf && (_currentNode + 1) == startNode)
   1575           return returnNode(makeNodeHandle(++_currentNode)); // | m_dtmIdent);
   1576 
   1577       int node = _currentNode;
   1578       int type;
   1579 
   1580       // %OPT% If the startNode is the root node, do not need
   1581       // to do the isDescendant() check.
   1582       if (startNode == ROOTNODE) {
   1583         int eType;
   1584         do {
   1585           node++;
   1586           eType = _exptype2(node);
   1587 
   1588           if (NULL == eType) {
   1589             _currentNode = NULL;
   1590             return END;
   1591           }
   1592         } while (eType == TEXT_NODE
   1593                  || (type = m_extendedTypes[eType].getNodeType()) == ATTRIBUTE_NODE
   1594                  || type == NAMESPACE_NODE);
   1595       }
   1596       else {
   1597         do {
   1598           node++;
   1599           type = _type2(node);
   1600 
   1601           if (NULL == type ||!isDescendant(node)) {
   1602             _currentNode = NULL;
   1603             return END;
   1604           }
   1605         } while(ATTRIBUTE_NODE == type || TEXT_NODE == type
   1606                  || NAMESPACE_NODE == type);
   1607       }
   1608 
   1609       _currentNode = node;
   1610       return returnNode(makeNodeHandle(node));  // make handle.
   1611     }
   1612 
   1613     /**
   1614      * Reset.
   1615      *
   1616      */
   1617   public DTMAxisIterator reset()
   1618   {
   1619 
   1620     final boolean temp = _isRestartable;
   1621 
   1622     _isRestartable = true;
   1623 
   1624     setStartNode(makeNodeHandle(_startNode));
   1625 
   1626     _isRestartable = temp;
   1627 
   1628     return this;
   1629   }
   1630 
   1631   }  // end of DescendantIterator
   1632 
   1633   /**
   1634    * Typed iterator that returns the descendants of a given node.
   1635    */
   1636   public final class TypedDescendantIterator extends DescendantIterator
   1637   {
   1638 
   1639     /** The extended type ID that was requested. */
   1640     private final int _nodeType;
   1641 
   1642     /**
   1643      * Constructor TypedDescendantIterator
   1644      *
   1645      *
   1646      * @param nodeType Extended type ID being requested.
   1647      */
   1648     public TypedDescendantIterator(int nodeType)
   1649     {
   1650       _nodeType = nodeType;
   1651     }
   1652 
   1653     /**
   1654      * Get the next node in the iteration.
   1655      *
   1656      * @return The next node handle in the iteration, or END.
   1657      */
   1658     public int next()
   1659     {
   1660       final int startNode = _startNode;
   1661       if (_startNode == NULL) {
   1662         return NULL;
   1663       }
   1664 
   1665       int node = _currentNode;
   1666 
   1667       int expType;
   1668       final int nodeType = _nodeType;
   1669 
   1670       if (nodeType != DTM.ELEMENT_NODE)
   1671       {
   1672         do
   1673         {
   1674           node++;
   1675 	  expType = _exptype2(node);
   1676 
   1677           if (NULL == expType || _parent2(node) < startNode && startNode != node) {
   1678             _currentNode = NULL;
   1679             return END;
   1680           }
   1681         }
   1682         while (expType != nodeType);
   1683       }
   1684       // %OPT% If the start node is root (e.g. in the case of //node),
   1685       // we can save the isDescendant() check, because all nodes are
   1686       // descendants of root.
   1687       else if (startNode == DTMDefaultBase.ROOTNODE)
   1688       {
   1689 	do
   1690 	{
   1691 	  node++;
   1692 	  expType = _exptype2(node);
   1693 
   1694 	  if (NULL == expType) {
   1695 	    _currentNode = NULL;
   1696 	    return END;
   1697 	  }
   1698 	} while (expType < DTM.NTYPES
   1699 	        || m_extendedTypes[expType].getNodeType() != DTM.ELEMENT_NODE);
   1700       }
   1701       else
   1702       {
   1703         do
   1704         {
   1705           node++;
   1706 	  expType = _exptype2(node);
   1707 
   1708           if (NULL == expType || _parent2(node) < startNode && startNode != node) {
   1709             _currentNode = NULL;
   1710             return END;
   1711           }
   1712         }
   1713         while (expType < DTM.NTYPES
   1714 	       || m_extendedTypes[expType].getNodeType() != DTM.ELEMENT_NODE);
   1715       }
   1716 
   1717       _currentNode = node;
   1718       return returnNode(makeNodeHandle(node));
   1719     }
   1720   }  // end of TypedDescendantIterator
   1721 
   1722   /**
   1723    * Iterator that returns a given node only if it is of a given type.
   1724    */
   1725   public final class TypedSingletonIterator extends SingletonIterator
   1726   {
   1727 
   1728     /** The extended type ID that was requested. */
   1729     private final int _nodeType;
   1730 
   1731     /**
   1732      * Constructor TypedSingletonIterator
   1733      *
   1734      *
   1735      * @param nodeType The extended type ID being requested.
   1736      */
   1737     public TypedSingletonIterator(int nodeType)
   1738     {
   1739       _nodeType = nodeType;
   1740     }
   1741 
   1742     /**
   1743      * Get the next node in the iteration.
   1744      *
   1745      * @return The next node handle in the iteration, or END.
   1746      */
   1747     public int next()
   1748     {
   1749 
   1750       final int result = _currentNode;
   1751       if (result == END)
   1752         return DTM.NULL;
   1753 
   1754       _currentNode = END;
   1755 
   1756       if (_nodeType >= DTM.NTYPES) {
   1757         if (_exptype2(makeNodeIdentity(result)) == _nodeType) {
   1758           return returnNode(result);
   1759         }
   1760       }
   1761       else {
   1762         if (_type2(makeNodeIdentity(result)) == _nodeType) {
   1763           return returnNode(result);
   1764         }
   1765       }
   1766 
   1767       return NULL;
   1768     }
   1769   }  // end of TypedSingletonIterator
   1770 
   1771   /*******************************************************************
   1772    *                End of nested iterators
   1773    *******************************************************************/
   1774 
   1775 
   1776   // %OPT% Array references which are used to cache the map0 arrays in
   1777   // SuballocatedIntVectors. Using the cached arrays reduces the level
   1778   // of indirection and results in better performance than just calling
   1779   // SuballocatedIntVector.elementAt().
   1780   private int[] m_exptype_map0;
   1781   private int[] m_nextsib_map0;
   1782   private int[] m_firstch_map0;
   1783   private int[] m_parent_map0;
   1784 
   1785   // Double array references to the map arrays in SuballocatedIntVectors.
   1786   private int[][] m_exptype_map;
   1787   private int[][] m_nextsib_map;
   1788   private int[][] m_firstch_map;
   1789   private int[][] m_parent_map;
   1790 
   1791   // %OPT% Cache the array of extended types in this class
   1792   protected ExtendedType[] m_extendedTypes;
   1793 
   1794   // A Vector which is used to store the values of attribute, namespace,
   1795   // comment and PI nodes.
   1796   //
   1797   // %OPT% These values are unlikely to be equal. Storing
   1798   // them in a plain Vector is more efficient than storing in the
   1799   // DTMStringPool because we can save the cost for hash calculation.
   1800   //
   1801   // %REVISIT% Do we need a custom class (e.g. StringVector) here?
   1802   protected Vector m_values;
   1803 
   1804   // The current index into the m_values Vector.
   1805   private int m_valueIndex = 0;
   1806 
   1807   // The maximum value of the current node index.
   1808   private int m_maxNodeIndex;
   1809 
   1810   // Cache the shift and mask values for the SuballocatedIntVectors.
   1811   protected int m_SHIFT;
   1812   protected int m_MASK;
   1813   protected int m_blocksize;
   1814 
   1815   /** %OPT% If the offset and length of a Text node are within certain limits,
   1816    * we store a bitwise encoded value into an int, using 10 bits (max. 1024)
   1817    * for length and 21 bits for offset. We can save two SuballocatedIntVector
   1818    * calls for each getStringValueX() and dispatchCharacterEvents() call by
   1819    * doing this.
   1820    */
   1821   // The number of bits for the length of a Text node.
   1822   protected final static int TEXT_LENGTH_BITS = 10;
   1823 
   1824   // The number of bits for the offset of a Text node.
   1825   protected final static int TEXT_OFFSET_BITS = 21;
   1826 
   1827   // The maximum length value
   1828   protected final static int TEXT_LENGTH_MAX = (1<<TEXT_LENGTH_BITS) - 1;
   1829 
   1830   // The maximum offset value
   1831   protected final static int TEXT_OFFSET_MAX = (1<<TEXT_OFFSET_BITS) - 1;
   1832 
   1833   // True if we want to build the ID index table.
   1834   protected boolean m_buildIdIndex = true;
   1835 
   1836   // Constant for empty String
   1837   private static final String EMPTY_STR = "";
   1838 
   1839   // Constant for empty XMLString
   1840   private static final XMLString EMPTY_XML_STR = new XMLStringDefault("");
   1841 
   1842   /**
   1843    * Construct a SAX2DTM2 object using the default block size.
   1844    */
   1845   public SAX2DTM2(DTMManager mgr, Source source, int dtmIdentity,
   1846                  DTMWSFilter whiteSpaceFilter,
   1847                  XMLStringFactory xstringfactory,
   1848                  boolean doIndexing)
   1849   {
   1850 
   1851     this(mgr, source, dtmIdentity, whiteSpaceFilter,
   1852           xstringfactory, doIndexing, DEFAULT_BLOCKSIZE, true, true, false);
   1853   }
   1854 
   1855   /**
   1856    * Construct a SAX2DTM2 object using the given block size.
   1857    */
   1858   public SAX2DTM2(DTMManager mgr, Source source, int dtmIdentity,
   1859                  DTMWSFilter whiteSpaceFilter,
   1860                  XMLStringFactory xstringfactory,
   1861                  boolean doIndexing,
   1862                  int blocksize,
   1863                  boolean usePrevsib,
   1864                  boolean buildIdIndex,
   1865                  boolean newNameTable)
   1866   {
   1867 
   1868     super(mgr, source, dtmIdentity, whiteSpaceFilter,
   1869           xstringfactory, doIndexing, blocksize, usePrevsib, newNameTable);
   1870 
   1871     // Initialize the values of m_SHIFT and m_MASK.
   1872     int shift;
   1873     for(shift=0; (blocksize>>>=1) != 0; ++shift);
   1874 
   1875     m_blocksize = 1<<shift;
   1876     m_SHIFT = shift;
   1877     m_MASK = m_blocksize - 1;
   1878 
   1879     m_buildIdIndex = buildIdIndex;
   1880 
   1881     // Some documents do not have attribute nodes. That is why
   1882     // we set the initial size of this Vector to be small and set
   1883     // the increment to a bigger number.
   1884     m_values = new Vector(32, 512);
   1885 
   1886     m_maxNodeIndex = 1 << DTMManager.IDENT_DTM_NODE_BITS;
   1887 
   1888     // Set the map0 values in the constructor.
   1889     m_exptype_map0 = m_exptype.getMap0();
   1890     m_nextsib_map0 = m_nextsib.getMap0();
   1891     m_firstch_map0 = m_firstch.getMap0();
   1892     m_parent_map0  = m_parent.getMap0();
   1893   }
   1894 
   1895   /**
   1896    * Override DTMDefaultBase._exptype() by dropping the incremental code.
   1897    *
   1898    * <p>This one is less efficient than _exptype2. It is only used during
   1899    * DTM building. _exptype2 is used after the document is fully built.
   1900    */
   1901   public final int _exptype(int identity)
   1902   {
   1903     return m_exptype.elementAt(identity);
   1904   }
   1905 
   1906   /************************************************************************
   1907    *             DTM base accessor interfaces
   1908    *
   1909    * %OPT% The code in the following interfaces (e.g. _exptype2, etc.) are
   1910    * very important to the DTM performance. To have the best performace,
   1911    * these several interfaces have direct access to the internal arrays of
   1912    * the SuballocatedIntVectors. The final modifier also has a noticeable
   1913    * impact on performance.
   1914    ***********************************************************************/
   1915 
   1916   /**
   1917    * The optimized version of DTMDefaultBase._exptype().
   1918    *
   1919    * @param identity A node identity, which <em>must not</em> be equal to
   1920    *        <code>DTM.NULL</code>
   1921    */
   1922   public final int _exptype2(int identity)
   1923   {
   1924     //return m_exptype.elementAt(identity);
   1925 
   1926     if (identity < m_blocksize)
   1927       return m_exptype_map0[identity];
   1928     else
   1929       return m_exptype_map[identity>>>m_SHIFT][identity&m_MASK];
   1930   }
   1931 
   1932   /**
   1933    * The optimized version of DTMDefaultBase._nextsib().
   1934    *
   1935    * @param identity A node identity, which <em>must not</em> be equal to
   1936    *        <code>DTM.NULL</code>
   1937    */
   1938   public final int _nextsib2(int identity)
   1939   {
   1940     //return m_nextsib.elementAt(identity);
   1941 
   1942     if (identity < m_blocksize)
   1943       return m_nextsib_map0[identity];
   1944     else
   1945       return m_nextsib_map[identity>>>m_SHIFT][identity&m_MASK];
   1946   }
   1947 
   1948   /**
   1949    * The optimized version of DTMDefaultBase._firstch().
   1950    *
   1951    * @param identity A node identity, which <em>must not</em> be equal to
   1952    *        <code>DTM.NULL</code>
   1953    */
   1954   public final int _firstch2(int identity)
   1955   {
   1956     //return m_firstch.elementAt(identity);
   1957 
   1958     if (identity < m_blocksize)
   1959       return m_firstch_map0[identity];
   1960     else
   1961       return m_firstch_map[identity>>>m_SHIFT][identity&m_MASK];
   1962   }
   1963 
   1964   /**
   1965    * The optimized version of DTMDefaultBase._parent().
   1966    *
   1967    * @param identity A node identity, which <em>must not</em> be equal to
   1968    *        <code>DTM.NULL</code>
   1969    */
   1970   public final int _parent2(int identity)
   1971   {
   1972     //return m_parent.elementAt(identity);
   1973 
   1974     if (identity < m_blocksize)
   1975       return m_parent_map0[identity];
   1976     else
   1977       return m_parent_map[identity>>>m_SHIFT][identity&m_MASK];
   1978   }
   1979 
   1980   /**
   1981    * The optimized version of DTMDefaultBase._type().
   1982    *
   1983    * @param identity A node identity, which <em>must not</em> be equal to
   1984    *        <code>DTM.NULL</code>
   1985    */
   1986   public final int _type2(int identity)
   1987   {
   1988     //int eType = _exptype2(identity);
   1989     int eType;
   1990     if (identity < m_blocksize)
   1991       eType = m_exptype_map0[identity];
   1992     else
   1993       eType = m_exptype_map[identity>>>m_SHIFT][identity&m_MASK];
   1994 
   1995     if (NULL != eType)
   1996       return m_extendedTypes[eType].getNodeType();
   1997     else
   1998       return NULL;
   1999   }
   2000 
   2001   /**
   2002    * The optimized version of DTMDefaultBase.getExpandedTypeID(int).
   2003    *
   2004    * <p>This one is only used by DOMAdapter.getExpandedTypeID(int), which
   2005    * is mostly called from the compiled translets.
   2006    */
   2007   public final int getExpandedTypeID2(int nodeHandle)
   2008   {
   2009     int nodeID = makeNodeIdentity(nodeHandle);
   2010 
   2011     //return (nodeID != NULL) ? _exptype2(nodeID) : NULL;
   2012 
   2013     if (nodeID != NULL) {
   2014       if (nodeID < m_blocksize)
   2015         return m_exptype_map0[nodeID];
   2016       else
   2017         return m_exptype_map[nodeID>>>m_SHIFT][nodeID&m_MASK];
   2018     }
   2019     else
   2020       return NULL;
   2021   }
   2022 
   2023   /*************************************************************************
   2024    *                 END of DTM base accessor interfaces
   2025    *************************************************************************/
   2026 
   2027 
   2028   /**
   2029    * Return the node type from the expanded type
   2030    */
   2031   public final int _exptype2Type(int exptype)
   2032   {
   2033     if (NULL != exptype)
   2034       return m_extendedTypes[exptype].getNodeType();
   2035     else
   2036       return NULL;
   2037   }
   2038 
   2039   /**
   2040    * Get a prefix either from the uri mapping, or just make
   2041    * one up!
   2042    *
   2043    * @param uri The namespace URI, which may be null.
   2044    *
   2045    * @return The prefix if there is one, or null.
   2046    */
   2047   public int getIdForNamespace(String uri)
   2048   {
   2049      int index = m_values.indexOf(uri);
   2050      if (index < 0)
   2051      {
   2052        m_values.addElement(uri);
   2053        return m_valueIndex++;
   2054      }
   2055      else
   2056        return index;
   2057   }
   2058 
   2059   /**
   2060    * Override SAX2DTM.startElement()
   2061    *
   2062    * <p>Receive notification of the start of an element.
   2063    *
   2064    * <p>By default, do nothing.  Application writers may override this
   2065    * method in a subclass to take specific actions at the start of
   2066    * each element (such as allocating a new tree node or writing
   2067    * output to a file).</p>
   2068    *
   2069    * @param uri The Namespace URI, or the empty string if the
   2070    *        element has no Namespace URI or if Namespace
   2071    *        processing is not being performed.
   2072    * @param localName The local name (without prefix), or the
   2073    *        empty string if Namespace processing is not being
   2074    *        performed.
   2075    * @param qName The qualified name (with prefix), or the
   2076    *        empty string if qualified names are not available.
   2077    * @param attributes The specified or defaulted attributes.
   2078    * @throws SAXException Any SAX exception, possibly
   2079    *            wrapping another exception.
   2080    * @see org.xml.sax.ContentHandler#startElement
   2081    */
   2082   public void startElement(String uri, String localName, String qName, Attributes attributes)
   2083       throws SAXException
   2084   {
   2085 
   2086     charactersFlush();
   2087 
   2088     int exName = m_expandedNameTable.getExpandedTypeID(uri, localName, DTM.ELEMENT_NODE);
   2089 
   2090     int prefixIndex = (qName.length() != localName.length())
   2091                       ? m_valuesOrPrefixes.stringToIndex(qName) : 0;
   2092 
   2093     int elemNode = addNode(DTM.ELEMENT_NODE, exName,
   2094                            m_parents.peek(), m_previous, prefixIndex, true);
   2095 
   2096     if(m_indexing)
   2097       indexNode(exName, elemNode);
   2098 
   2099     m_parents.push(elemNode);
   2100 
   2101     int startDecls = m_contextIndexes.peek();
   2102     int nDecls = m_prefixMappings.size();
   2103     String prefix;
   2104 
   2105     if(!m_pastFirstElement)
   2106     {
   2107       // SPECIAL CASE: Implied declaration at root element
   2108       prefix="xml";
   2109       String declURL = "http://www.w3.org/XML/1998/namespace";
   2110       exName = m_expandedNameTable.getExpandedTypeID(null, prefix, DTM.NAMESPACE_NODE);
   2111       m_values.addElement(declURL);
   2112       int val = m_valueIndex++;
   2113       addNode(DTM.NAMESPACE_NODE, exName, elemNode,
   2114                      DTM.NULL, val, false);
   2115       m_pastFirstElement=true;
   2116     }
   2117 
   2118     for (int i = startDecls; i < nDecls; i += 2)
   2119     {
   2120       prefix = (String) m_prefixMappings.elementAt(i);
   2121 
   2122       if (prefix == null)
   2123         continue;
   2124 
   2125       String declURL = (String) m_prefixMappings.elementAt(i + 1);
   2126 
   2127       exName = m_expandedNameTable.getExpandedTypeID(null, prefix, DTM.NAMESPACE_NODE);
   2128 
   2129       m_values.addElement(declURL);
   2130       int val = m_valueIndex++;
   2131 
   2132       addNode(DTM.NAMESPACE_NODE, exName, elemNode, DTM.NULL, val, false);
   2133     }
   2134 
   2135     int n = attributes.getLength();
   2136 
   2137     for (int i = 0; i < n; i++)
   2138     {
   2139       String attrUri = attributes.getURI(i);
   2140       String attrQName = attributes.getQName(i);
   2141       String valString = attributes.getValue(i);
   2142 
   2143       int nodeType;
   2144 
   2145       String attrLocalName = attributes.getLocalName(i);
   2146 
   2147       if ((null != attrQName)
   2148               && (attrQName.equals("xmlns")
   2149                   || attrQName.startsWith("xmlns:")))
   2150       {
   2151         prefix = getPrefix(attrQName, attrUri);
   2152         if (declAlreadyDeclared(prefix))
   2153           continue;  // go to the next attribute.
   2154 
   2155         nodeType = DTM.NAMESPACE_NODE;
   2156       }
   2157       else
   2158       {
   2159         nodeType = DTM.ATTRIBUTE_NODE;
   2160 
   2161         if (m_buildIdIndex && attributes.getType(i).equalsIgnoreCase("ID"))
   2162           setIDAttribute(valString, elemNode);
   2163       }
   2164 
   2165       // Bit of a hack... if somehow valString is null, stringToIndex will
   2166       // return -1, which will make things very unhappy.
   2167       if(null == valString)
   2168         valString = "";
   2169 
   2170       m_values.addElement(valString);
   2171       int val = m_valueIndex++;
   2172 
   2173       if (attrLocalName.length() != attrQName.length())
   2174       {
   2175 
   2176         prefixIndex = m_valuesOrPrefixes.stringToIndex(attrQName);
   2177 
   2178         int dataIndex = m_data.size();
   2179 
   2180         m_data.addElement(prefixIndex);
   2181         m_data.addElement(val);
   2182 
   2183         val = -dataIndex;
   2184       }
   2185 
   2186       exName = m_expandedNameTable.getExpandedTypeID(attrUri, attrLocalName, nodeType);
   2187       addNode(nodeType, exName, elemNode, DTM.NULL, val,
   2188                      false);
   2189     }
   2190 
   2191     if (null != m_wsfilter)
   2192     {
   2193       short wsv = m_wsfilter.getShouldStripSpace(makeNodeHandle(elemNode), this);
   2194       boolean shouldStrip = (DTMWSFilter.INHERIT == wsv)
   2195                             ? getShouldStripWhitespace()
   2196                             : (DTMWSFilter.STRIP == wsv);
   2197 
   2198       pushShouldStripWhitespace(shouldStrip);
   2199     }
   2200 
   2201     m_previous = DTM.NULL;
   2202 
   2203     m_contextIndexes.push(m_prefixMappings.size());  // for the children.
   2204   }
   2205 
   2206   /**
   2207    * Receive notification of the end of an element.
   2208    *
   2209    * <p>By default, do nothing.  Application writers may override this
   2210    * method in a subclass to take specific actions at the end of
   2211    * each element (such as finalising a tree node or writing
   2212    * output to a file).</p>
   2213    *
   2214    * @param uri The Namespace URI, or the empty string if the
   2215    *        element has no Namespace URI or if Namespace
   2216    *        processing is not being performed.
   2217    * @param localName The local name (without prefix), or the
   2218    *        empty string if Namespace processing is not being
   2219    *        performed.
   2220    * @param qName The qualified XML 1.0 name (with prefix), or the
   2221    *        empty string if qualified names are not available.
   2222    * @throws SAXException Any SAX exception, possibly
   2223    *            wrapping another exception.
   2224    * @see org.xml.sax.ContentHandler#endElement
   2225    */
   2226   public void endElement(String uri, String localName, String qName)
   2227           throws SAXException
   2228   {
   2229     charactersFlush();
   2230 
   2231     // If no one noticed, startPrefixMapping is a drag.
   2232     // Pop the context for the last child (the one pushed by startElement)
   2233     m_contextIndexes.quickPop(1);
   2234 
   2235     // Do it again for this one (the one pushed by the last endElement).
   2236     int topContextIndex = m_contextIndexes.peek();
   2237     if (topContextIndex != m_prefixMappings.size()) {
   2238       m_prefixMappings.setSize(topContextIndex);
   2239     }
   2240 
   2241     m_previous = m_parents.pop();
   2242 
   2243     popShouldStripWhitespace();
   2244   }
   2245 
   2246   /**
   2247    * Report an XML comment anywhere in the document.
   2248    *
   2249    * <p>This callback will be used for comments inside or outside the
   2250    * document element, including comments in the external DTD
   2251    * subset (if read).</p>
   2252    *
   2253    * @param ch An array holding the characters in the comment.
   2254    * @param start The starting position in the array.
   2255    * @param length The number of characters to use from the array.
   2256    * @throws SAXException The application may raise an exception.
   2257    */
   2258   public void comment(char ch[], int start, int length) throws SAXException
   2259   {
   2260 
   2261     if (m_insideDTD)      // ignore comments if we're inside the DTD
   2262       return;
   2263 
   2264     charactersFlush();
   2265 
   2266     // %OPT% Saving the comment string in a Vector has a lower cost than
   2267     // saving it in DTMStringPool.
   2268     m_values.addElement(new String(ch, start, length));
   2269     int dataIndex = m_valueIndex++;
   2270 
   2271     m_previous = addNode(DTM.COMMENT_NODE, DTM.COMMENT_NODE,
   2272                          m_parents.peek(), m_previous, dataIndex, false);
   2273   }
   2274 
   2275   /**
   2276    * Receive notification of the beginning of the document.
   2277    *
   2278    * @throws SAXException Any SAX exception, possibly
   2279    *            wrapping another exception.
   2280    * @see org.xml.sax.ContentHandler#startDocument
   2281    */
   2282   public void startDocument() throws SAXException
   2283   {
   2284 
   2285     int doc = addNode(DTM.DOCUMENT_NODE,
   2286                       DTM.DOCUMENT_NODE,
   2287                       DTM.NULL, DTM.NULL, 0, true);
   2288 
   2289     m_parents.push(doc);
   2290     m_previous = DTM.NULL;
   2291 
   2292     m_contextIndexes.push(m_prefixMappings.size());  // for the next element.
   2293   }
   2294 
   2295   /**
   2296    * Receive notification of the end of the document.
   2297    *
   2298    * @throws SAXException Any SAX exception, possibly
   2299    *            wrapping another exception.
   2300    * @see org.xml.sax.ContentHandler#endDocument
   2301    */
   2302   public void endDocument() throws SAXException
   2303   {
   2304     super.endDocument();
   2305 
   2306     // Add a NULL entry to the end of the node arrays as
   2307     // the end indication.
   2308     m_exptype.addElement(NULL);
   2309     m_parent.addElement(NULL);
   2310     m_nextsib.addElement(NULL);
   2311     m_firstch.addElement(NULL);
   2312 
   2313     // Set the cached references after the document is built.
   2314     m_extendedTypes = m_expandedNameTable.getExtendedTypes();
   2315     m_exptype_map = m_exptype.getMap();
   2316     m_nextsib_map = m_nextsib.getMap();
   2317     m_firstch_map = m_firstch.getMap();
   2318     m_parent_map  = m_parent.getMap();
   2319   }
   2320 
   2321   /**
   2322    * Construct the node map from the node.
   2323    *
   2324    * @param type raw type ID, one of DTM.XXX_NODE.
   2325    * @param expandedTypeID The expended type ID.
   2326    * @param parentIndex The current parent index.
   2327    * @param previousSibling The previous sibling index.
   2328    * @param dataOrPrefix index into m_data table, or string handle.
   2329    * @param canHaveFirstChild true if the node can have a first child, false
   2330    *                          if it is atomic.
   2331    *
   2332    * @return The index identity of the node that was added.
   2333    */
   2334   protected final int addNode(int type, int expandedTypeID,
   2335                         int parentIndex, int previousSibling,
   2336                         int dataOrPrefix, boolean canHaveFirstChild)
   2337   {
   2338     // Common to all nodes:
   2339     int nodeIndex = m_size++;
   2340 
   2341     // Have we overflowed a DTM Identity's addressing range?
   2342     //if(m_dtmIdent.size() == (nodeIndex>>>DTMManager.IDENT_DTM_NODE_BITS))
   2343     if (nodeIndex == m_maxNodeIndex)
   2344     {
   2345       addNewDTMID(nodeIndex);
   2346       m_maxNodeIndex += (1 << DTMManager.IDENT_DTM_NODE_BITS);
   2347     }
   2348 
   2349     m_firstch.addElement(DTM.NULL);
   2350     m_nextsib.addElement(DTM.NULL);
   2351     m_parent.addElement(parentIndex);
   2352     m_exptype.addElement(expandedTypeID);
   2353     m_dataOrQName.addElement(dataOrPrefix);
   2354 
   2355     if (m_prevsib != null) {
   2356       m_prevsib.addElement(previousSibling);
   2357     }
   2358 
   2359     if (m_locator != null && m_useSourceLocationProperty) {
   2360       setSourceLocation();
   2361     }
   2362 
   2363     // Note that nextSibling is not processed until charactersFlush()
   2364     // is called, to handle successive characters() events.
   2365 
   2366     // Special handling by type: Declare namespaces, attach first child
   2367     switch(type)
   2368     {
   2369     case DTM.NAMESPACE_NODE:
   2370       declareNamespaceInContext(parentIndex,nodeIndex);
   2371       break;
   2372     case DTM.ATTRIBUTE_NODE:
   2373       break;
   2374     default:
   2375       if (DTM.NULL != previousSibling) {
   2376         m_nextsib.setElementAt(nodeIndex,previousSibling);
   2377       }
   2378       else if (DTM.NULL != parentIndex) {
   2379         m_firstch.setElementAt(nodeIndex,parentIndex);
   2380       }
   2381       break;
   2382     }
   2383 
   2384     return nodeIndex;
   2385   }
   2386 
   2387   /**
   2388    * Check whether accumulated text should be stripped; if not,
   2389    * append the appropriate flavor of text/cdata node.
   2390    */
   2391   protected final void charactersFlush()
   2392   {
   2393 
   2394     if (m_textPendingStart >= 0)  // -1 indicates no-text-in-progress
   2395     {
   2396       int length = m_chars.size() - m_textPendingStart;
   2397       boolean doStrip = false;
   2398 
   2399       if (getShouldStripWhitespace())
   2400       {
   2401         doStrip = m_chars.isWhitespace(m_textPendingStart, length);
   2402       }
   2403 
   2404       if (doStrip) {
   2405         m_chars.setLength(m_textPendingStart);  // Discard accumulated text
   2406       } else {
   2407         // Guard against characters/ignorableWhitespace events that
   2408         // contained no characters.  They should not result in a node.
   2409         if (length > 0) {
   2410           // If the offset and length do not exceed the given limits
   2411           // (offset < 2^21 and length < 2^10), then save both the offset
   2412           // and length in a bitwise encoded value.
   2413           if (length <= TEXT_LENGTH_MAX
   2414                   && m_textPendingStart <= TEXT_OFFSET_MAX) {
   2415             m_previous = addNode(m_coalescedTextType, DTM.TEXT_NODE,
   2416                              m_parents.peek(), m_previous,
   2417                              length + (m_textPendingStart << TEXT_LENGTH_BITS),
   2418                              false);
   2419 
   2420           } else {
   2421             // Store offset and length in the m_data array if one exceeds
   2422             // the given limits. Use a negative dataIndex as an indication.
   2423             int dataIndex = m_data.size();
   2424             m_previous = addNode(m_coalescedTextType, DTM.TEXT_NODE,
   2425                                m_parents.peek(), m_previous, -dataIndex, false);
   2426 
   2427             m_data.addElement(m_textPendingStart);
   2428             m_data.addElement(length);
   2429           }
   2430         }
   2431       }
   2432 
   2433       // Reset for next text block
   2434       m_textPendingStart = -1;
   2435       m_textType = m_coalescedTextType = DTM.TEXT_NODE;
   2436     }
   2437   }
   2438 
   2439   /**
   2440    * Override the processingInstruction() interface in SAX2DTM2.
   2441    * <p>
   2442    * %OPT% This one is different from SAX2DTM.processingInstruction()
   2443    * in that we do not use extended types for PI nodes. The name of
   2444    * the PI is saved in the DTMStringPool.
   2445    *
   2446    * Receive notification of a processing instruction.
   2447    *
   2448    * @param target The processing instruction target.
   2449    * @param data The processing instruction data, or null if
   2450    *             none is supplied.
   2451    * @throws SAXException Any SAX exception, possibly
   2452    *            wrapping another exception.
   2453    * @see org.xml.sax.ContentHandler#processingInstruction
   2454    */
   2455   public void processingInstruction(String target, String data)
   2456 	  throws SAXException
   2457   {
   2458 
   2459     charactersFlush();
   2460 
   2461     int dataIndex = m_data.size();
   2462     m_previous = addNode(DTM.PROCESSING_INSTRUCTION_NODE,
   2463 			 DTM.PROCESSING_INSTRUCTION_NODE,
   2464 			 m_parents.peek(), m_previous,
   2465 			 -dataIndex, false);
   2466 
   2467     m_data.addElement(m_valuesOrPrefixes.stringToIndex(target));
   2468     m_values.addElement(data);
   2469     m_data.addElement(m_valueIndex++);
   2470 
   2471   }
   2472 
   2473   /**
   2474    * The optimized version of DTMDefaultBase.getFirstAttribute().
   2475    * <p>
   2476    * Given a node handle, get the index of the node's first attribute.
   2477    *
   2478    * @param nodeHandle int Handle of the node.
   2479    * @return Handle of first attribute, or DTM.NULL to indicate none exists.
   2480    */
   2481   public final int getFirstAttribute(int nodeHandle)
   2482   {
   2483     int nodeID = makeNodeIdentity(nodeHandle);
   2484 
   2485     if (nodeID == DTM.NULL)
   2486       return DTM.NULL;
   2487 
   2488     int type = _type2(nodeID);
   2489 
   2490     if (DTM.ELEMENT_NODE == type)
   2491     {
   2492       // Assume that attributes and namespaces immediately follow the element.
   2493       while (true)
   2494       {
   2495         nodeID++;
   2496 	// Assume this can not be null.
   2497 	type = _type2(nodeID);
   2498 
   2499 	if (type == DTM.ATTRIBUTE_NODE)
   2500 	{
   2501 	  return makeNodeHandle(nodeID);
   2502 	}
   2503 	else if (DTM.NAMESPACE_NODE != type)
   2504 	{
   2505 	  break;
   2506 	}
   2507       }
   2508     }
   2509 
   2510     return DTM.NULL;
   2511   }
   2512 
   2513   /**
   2514    * The optimized version of DTMDefaultBase.getFirstAttributeIdentity(int).
   2515    * <p>
   2516    * Given a node identity, get the index of the node's first attribute.
   2517    *
   2518    * @param identity int identity of the node.
   2519    * @return Identity of first attribute, or DTM.NULL to indicate none exists.
   2520    */
   2521   protected int getFirstAttributeIdentity(int identity) {
   2522     if (identity == NULL) {
   2523         return NULL;
   2524     }
   2525     int type = _type2(identity);
   2526 
   2527     if (DTM.ELEMENT_NODE == type)
   2528     {
   2529       // Assume that attributes and namespaces immediately follow the element.
   2530       while (true)
   2531       {
   2532         identity++;
   2533 
   2534         // Assume this can not be null.
   2535         type = _type2(identity);
   2536 
   2537         if (type == DTM.ATTRIBUTE_NODE)
   2538         {
   2539           return identity;
   2540         }
   2541         else if (DTM.NAMESPACE_NODE != type)
   2542         {
   2543           break;
   2544         }
   2545       }
   2546     }
   2547 
   2548     return DTM.NULL;
   2549   }
   2550 
   2551   /**
   2552    * The optimized version of DTMDefaultBase.getNextAttributeIdentity(int).
   2553    * <p>
   2554    * Given a node identity for an attribute, advance to the next attribute.
   2555    *
   2556    * @param identity int identity of the attribute node.  This
   2557    * <strong>must</strong> be an attribute node.
   2558    *
   2559    * @return int DTM node-identity of the resolved attr,
   2560    * or DTM.NULL to indicate none exists.
   2561    *
   2562    */
   2563   protected int getNextAttributeIdentity(int identity) {
   2564     // Assume that attributes and namespace nodes immediately follow the element
   2565     while (true) {
   2566       identity++;
   2567       int type = _type2(identity);
   2568 
   2569       if (type == DTM.ATTRIBUTE_NODE) {
   2570         return identity;
   2571       } else if (type != DTM.NAMESPACE_NODE) {
   2572         break;
   2573       }
   2574     }
   2575 
   2576     return DTM.NULL;
   2577   }
   2578 
   2579   /**
   2580    * The optimized version of DTMDefaultBase.getTypedAttribute(int, int).
   2581    * <p>
   2582    * Given a node handle and an expanded type ID, get the index of the node's
   2583    * attribute of that type, if any.
   2584    *
   2585    * @param nodeHandle int Handle of the node.
   2586    * @param attType int expanded type ID of the required attribute.
   2587    * @return Handle of attribute of the required type, or DTM.NULL to indicate
   2588    * none exists.
   2589    */
   2590   protected final int getTypedAttribute(int nodeHandle, int attType)
   2591   {
   2592 
   2593     int nodeID = makeNodeIdentity(nodeHandle);
   2594 
   2595     if (nodeID == DTM.NULL)
   2596       return DTM.NULL;
   2597 
   2598     int type = _type2(nodeID);
   2599 
   2600     if (DTM.ELEMENT_NODE == type)
   2601     {
   2602       int expType;
   2603       while (true)
   2604       {
   2605 	nodeID++;
   2606 	expType = _exptype2(nodeID);
   2607 
   2608 	if (expType != DTM.NULL)
   2609 	  type = m_extendedTypes[expType].getNodeType();
   2610 	else
   2611 	  return DTM.NULL;
   2612 
   2613 	if (type == DTM.ATTRIBUTE_NODE)
   2614 	{
   2615 	  if (expType == attType) return makeNodeHandle(nodeID);
   2616 	}
   2617 	else if (DTM.NAMESPACE_NODE != type)
   2618 	{
   2619 	  break;
   2620 	}
   2621       }
   2622     }
   2623 
   2624     return DTM.NULL;
   2625   }
   2626 
   2627   /**
   2628    * Override SAX2DTM.getLocalName() in SAX2DTM2.
   2629    * <p>Processing for PIs is different.
   2630    *
   2631    * Given a node handle, return its XPath- style localname. (As defined in
   2632    * Namespaces, this is the portion of the name after any colon character).
   2633    *
   2634    * @param nodeHandle the id of the node.
   2635    * @return String Local name of this node.
   2636    */
   2637   public String getLocalName(int nodeHandle)
   2638   {
   2639     int expType = _exptype(makeNodeIdentity(nodeHandle));
   2640 
   2641     if (expType == DTM.PROCESSING_INSTRUCTION_NODE)
   2642     {
   2643       int dataIndex = _dataOrQName(makeNodeIdentity(nodeHandle));
   2644       dataIndex = m_data.elementAt(-dataIndex);
   2645       return m_valuesOrPrefixes.indexToString(dataIndex);
   2646     }
   2647     else
   2648       return m_expandedNameTable.getLocalName(expType);
   2649   }
   2650 
   2651   /**
   2652    * The optimized version of SAX2DTM.getNodeNameX().
   2653    * <p>
   2654    * Given a node handle, return the XPath node name. This should be the name
   2655    * as described by the XPath data model, NOT the DOM- style name.
   2656    *
   2657    * @param nodeHandle the id of the node.
   2658    * @return String Name of this node, which may be an empty string.
   2659    */
   2660   public final String getNodeNameX(int nodeHandle)
   2661   {
   2662 
   2663     int nodeID = makeNodeIdentity(nodeHandle);
   2664     int eType = _exptype2(nodeID);
   2665 
   2666     if (eType == DTM.PROCESSING_INSTRUCTION_NODE)
   2667     {
   2668       int dataIndex = _dataOrQName(nodeID);
   2669       dataIndex = m_data.elementAt(-dataIndex);
   2670       return m_valuesOrPrefixes.indexToString(dataIndex);
   2671     }
   2672 
   2673     final ExtendedType extType = m_extendedTypes[eType];
   2674 
   2675     if (extType.getNamespace().length() == 0)
   2676     {
   2677       return extType.getLocalName();
   2678     }
   2679     else
   2680     {
   2681       int qnameIndex = m_dataOrQName.elementAt(nodeID);
   2682 
   2683       if (qnameIndex == 0)
   2684         return extType.getLocalName();
   2685 
   2686       if (qnameIndex < 0)
   2687       {
   2688 	qnameIndex = -qnameIndex;
   2689 	qnameIndex = m_data.elementAt(qnameIndex);
   2690       }
   2691 
   2692       return m_valuesOrPrefixes.indexToString(qnameIndex);
   2693     }
   2694   }
   2695 
   2696   /**
   2697    * The optimized version of SAX2DTM.getNodeName().
   2698    * <p>
   2699    * Given a node handle, return its DOM-style node name. This will include
   2700    * names such as #text or #document.
   2701    *
   2702    * @param nodeHandle the id of the node.
   2703    * @return String Name of this node, which may be an empty string.
   2704    * %REVIEW% Document when empty string is possible...
   2705    * %REVIEW-COMMENT% It should never be empty, should it?
   2706    */
   2707   public String getNodeName(int nodeHandle)
   2708   {
   2709 
   2710     int nodeID = makeNodeIdentity(nodeHandle);
   2711     int eType = _exptype2(nodeID);
   2712 
   2713     final ExtendedType extType = m_extendedTypes[eType];
   2714     if (extType.getNamespace().length() == 0)
   2715     {
   2716       int type = extType.getNodeType();
   2717 
   2718       String localName = extType.getLocalName();
   2719       if (type == DTM.NAMESPACE_NODE)
   2720       {
   2721 	if (localName.length() == 0)
   2722 	  return "xmlns";
   2723 	else
   2724 	  return "xmlns:" + localName;
   2725       }
   2726       else if (type == DTM.PROCESSING_INSTRUCTION_NODE)
   2727       {
   2728 	int dataIndex = _dataOrQName(nodeID);
   2729 	dataIndex = m_data.elementAt(-dataIndex);
   2730 	return m_valuesOrPrefixes.indexToString(dataIndex);
   2731       }
   2732       else if (localName.length() == 0)
   2733       {
   2734         return getFixedNames(type);
   2735       }
   2736       else
   2737 	return localName;
   2738     }
   2739     else
   2740     {
   2741       int qnameIndex = m_dataOrQName.elementAt(nodeID);
   2742 
   2743       if (qnameIndex == 0)
   2744         return extType.getLocalName();
   2745 
   2746       if (qnameIndex < 0)
   2747       {
   2748 	qnameIndex = -qnameIndex;
   2749 	qnameIndex = m_data.elementAt(qnameIndex);
   2750       }
   2751 
   2752       return m_valuesOrPrefixes.indexToString(qnameIndex);
   2753     }
   2754   }
   2755 
   2756   /**
   2757    * Override SAX2DTM.getStringValue(int)
   2758    * <p>
   2759    * This method is only used by Xalan-J Interpretive. It is not used by XSLTC.
   2760    * <p>
   2761    * If the caller supplies an XMLStringFactory, the getStringValue() interface
   2762    * in SAX2DTM will be called. Otherwise just calls getStringValueX() and
   2763    * wraps the returned String in an XMLString.
   2764    *
   2765    * Get the string-value of a node as a String object
   2766    * (see http://www.w3.org/TR/xpath#data-model
   2767    * for the definition of a node's string-value).
   2768    *
   2769    * @param nodeHandle The node ID.
   2770    *
   2771    * @return A string object that represents the string-value of the given node.
   2772    */
   2773   public XMLString getStringValue(int nodeHandle)
   2774   {
   2775     int identity = makeNodeIdentity(nodeHandle);
   2776     if (identity == DTM.NULL)
   2777       return EMPTY_XML_STR;
   2778 
   2779     int type= _type2(identity);
   2780 
   2781     if (type == DTM.ELEMENT_NODE || type == DTM.DOCUMENT_NODE)
   2782     {
   2783       int startNode = identity;
   2784       identity = _firstch2(identity);
   2785       if (DTM.NULL != identity)
   2786       {
   2787 	int offset = -1;
   2788 	int length = 0;
   2789 
   2790 	do
   2791 	{
   2792 	  type = _exptype2(identity);
   2793 
   2794 	  if (type == DTM.TEXT_NODE || type == DTM.CDATA_SECTION_NODE)
   2795 	  {
   2796 	    int dataIndex = m_dataOrQName.elementAt(identity);
   2797 	    if (dataIndex >= 0)
   2798 	    {
   2799 	      if (-1 == offset)
   2800 	      {
   2801                 offset = dataIndex >>> TEXT_LENGTH_BITS;
   2802 	      }
   2803 
   2804 	      length += dataIndex & TEXT_LENGTH_MAX;
   2805 	    }
   2806 	    else
   2807 	    {
   2808 	      if (-1 == offset)
   2809 	      {
   2810                 offset = m_data.elementAt(-dataIndex);
   2811 	      }
   2812 
   2813 	      length += m_data.elementAt(-dataIndex + 1);
   2814 	    }
   2815 	  }
   2816 
   2817 	  identity++;
   2818 	} while (_parent2(identity) >= startNode);
   2819 
   2820 	if (length > 0)
   2821 	{
   2822 	  if (m_xstrf != null)
   2823 	    return m_xstrf.newstr(m_chars, offset, length);
   2824 	  else
   2825 	    return new XMLStringDefault(m_chars.getString(offset, length));
   2826 	}
   2827 	else
   2828 	  return EMPTY_XML_STR;
   2829       }
   2830       else
   2831         return EMPTY_XML_STR;
   2832     }
   2833     else if (DTM.TEXT_NODE == type || DTM.CDATA_SECTION_NODE == type)
   2834     {
   2835       int dataIndex = m_dataOrQName.elementAt(identity);
   2836       if (dataIndex >= 0)
   2837       {
   2838       	if (m_xstrf != null)
   2839       	  return m_xstrf.newstr(m_chars, dataIndex >>> TEXT_LENGTH_BITS,
   2840       	                 dataIndex & TEXT_LENGTH_MAX);
   2841       	else
   2842       	  return new XMLStringDefault(m_chars.getString(dataIndex >>> TEXT_LENGTH_BITS,
   2843       	                              dataIndex & TEXT_LENGTH_MAX));
   2844       }
   2845       else
   2846       {
   2847         if (m_xstrf != null)
   2848           return m_xstrf.newstr(m_chars, m_data.elementAt(-dataIndex),
   2849                                 m_data.elementAt(-dataIndex+1));
   2850         else
   2851           return new XMLStringDefault(m_chars.getString(m_data.elementAt(-dataIndex),
   2852                                    m_data.elementAt(-dataIndex+1)));
   2853       }
   2854     }
   2855     else
   2856     {
   2857       int dataIndex = m_dataOrQName.elementAt(identity);
   2858 
   2859       if (dataIndex < 0)
   2860       {
   2861         dataIndex = -dataIndex;
   2862         dataIndex = m_data.elementAt(dataIndex + 1);
   2863       }
   2864 
   2865       if (m_xstrf != null)
   2866         return m_xstrf.newstr((String)m_values.elementAt(dataIndex));
   2867       else
   2868         return new XMLStringDefault((String)m_values.elementAt(dataIndex));
   2869     }
   2870   }
   2871 
   2872   /**
   2873    * The optimized version of SAX2DTM.getStringValue(int).
   2874    * <p>
   2875    * %OPT% This is one of the most often used interfaces. Performance is
   2876    * critical here. This one is different from SAX2DTM.getStringValue(int) in
   2877    * that it returns a String instead of a XMLString.
   2878    *
   2879    * Get the string- value of a node as a String object (see http: //www. w3.
   2880    * org/TR/xpath#data- model for the definition of a node's string- value).
   2881    *
   2882    * @param nodeHandle The node ID.
   2883    *
   2884    * @return A string object that represents the string-value of the given node.
   2885    */
   2886   public final String getStringValueX(final int nodeHandle)
   2887   {
   2888     int identity = makeNodeIdentity(nodeHandle);
   2889     if (identity == DTM.NULL)
   2890       return EMPTY_STR;
   2891 
   2892     int type= _type2(identity);
   2893 
   2894     if (type == DTM.ELEMENT_NODE || type == DTM.DOCUMENT_NODE)
   2895     {
   2896       int startNode = identity;
   2897       identity = _firstch2(identity);
   2898       if (DTM.NULL != identity)
   2899       {
   2900 	int offset = -1;
   2901 	int length = 0;
   2902 
   2903 	do
   2904 	{
   2905 	  type = _exptype2(identity);
   2906 
   2907 	  if (type == DTM.TEXT_NODE || type == DTM.CDATA_SECTION_NODE)
   2908 	  {
   2909 	    int dataIndex = m_dataOrQName.elementAt(identity);
   2910 	    if (dataIndex >= 0)
   2911 	    {
   2912 	      if (-1 == offset)
   2913 	      {
   2914                 offset = dataIndex >>> TEXT_LENGTH_BITS;
   2915 	      }
   2916 
   2917 	      length += dataIndex & TEXT_LENGTH_MAX;
   2918 	    }
   2919 	    else
   2920 	    {
   2921 	      if (-1 == offset)
   2922 	      {
   2923                 offset = m_data.elementAt(-dataIndex);
   2924 	      }
   2925 
   2926 	      length += m_data.elementAt(-dataIndex + 1);
   2927 	    }
   2928 	  }
   2929 
   2930 	  identity++;
   2931 	} while (_parent2(identity) >= startNode);
   2932 
   2933 	if (length > 0)
   2934 	{
   2935 	  return m_chars.getString(offset, length);
   2936 	}
   2937 	else
   2938 	  return EMPTY_STR;
   2939       }
   2940       else
   2941         return EMPTY_STR;
   2942     }
   2943     else if (DTM.TEXT_NODE == type || DTM.CDATA_SECTION_NODE == type)
   2944     {
   2945       int dataIndex = m_dataOrQName.elementAt(identity);
   2946       if (dataIndex >= 0)
   2947       {
   2948       	return m_chars.getString(dataIndex >>> TEXT_LENGTH_BITS,
   2949       	                          dataIndex & TEXT_LENGTH_MAX);
   2950       }
   2951       else
   2952       {
   2953         return m_chars.getString(m_data.elementAt(-dataIndex),
   2954                                   m_data.elementAt(-dataIndex+1));
   2955       }
   2956     }
   2957     else
   2958     {
   2959       int dataIndex = m_dataOrQName.elementAt(identity);
   2960 
   2961       if (dataIndex < 0)
   2962       {
   2963         dataIndex = -dataIndex;
   2964         dataIndex = m_data.elementAt(dataIndex + 1);
   2965       }
   2966 
   2967       return (String)m_values.elementAt(dataIndex);
   2968     }
   2969   }
   2970 
   2971   /**
   2972    * Returns the string value of the entire tree
   2973    */
   2974   public String getStringValue()
   2975   {
   2976     int child = _firstch2(ROOTNODE);
   2977     if (child == DTM.NULL) return EMPTY_STR;
   2978 
   2979     // optimization: only create StringBuffer if > 1 child
   2980     if ((_exptype2(child) == DTM.TEXT_NODE) && (_nextsib2(child) == DTM.NULL))
   2981     {
   2982       int dataIndex = m_dataOrQName.elementAt(child);
   2983       if (dataIndex >= 0)
   2984         return m_chars.getString(dataIndex >>> TEXT_LENGTH_BITS, dataIndex & TEXT_LENGTH_MAX);
   2985       else
   2986         return m_chars.getString(m_data.elementAt(-dataIndex),
   2987                                   m_data.elementAt(-dataIndex + 1));
   2988     }
   2989     else
   2990       return getStringValueX(getDocument());
   2991 
   2992   }
   2993 
   2994   /**
   2995    * The optimized version of SAX2DTM.dispatchCharactersEvents(int, ContentHandler, boolean).
   2996    * <p>
   2997    * Directly call the
   2998    * characters method on the passed ContentHandler for the
   2999    * string-value of the given node (see http://www.w3.org/TR/xpath#data-model
   3000    * for the definition of a node's string-value). Multiple calls to the
   3001    * ContentHandler's characters methods may well occur for a single call to
   3002    * this method.
   3003    *
   3004    * @param nodeHandle The node ID.
   3005    * @param ch A non-null reference to a ContentHandler.
   3006    * @param normalize true if the content should be normalized according to
   3007    * the rules for the XPath
   3008    * <a href="http://www.w3.org/TR/xpath#function-normalize-space">normalize-space</a>
   3009    * function.
   3010    *
   3011    * @throws SAXException
   3012    */
   3013   public final void dispatchCharactersEvents(int nodeHandle, ContentHandler ch,
   3014                                              boolean normalize)
   3015           throws SAXException
   3016   {
   3017 
   3018     int identity = makeNodeIdentity(nodeHandle);
   3019 
   3020     if (identity == DTM.NULL)
   3021       return;
   3022 
   3023     int type = _type2(identity);
   3024 
   3025     if (type == DTM.ELEMENT_NODE || type == DTM.DOCUMENT_NODE)
   3026     {
   3027       int startNode = identity;
   3028       identity = _firstch2(identity);
   3029       if (DTM.NULL != identity)
   3030       {
   3031 	int offset = -1;
   3032 	int length = 0;
   3033 
   3034 	do
   3035 	{
   3036 	  type = _exptype2(identity);
   3037 
   3038 	  if (type == DTM.TEXT_NODE || type == DTM.CDATA_SECTION_NODE)
   3039 	  {
   3040 	    int dataIndex = m_dataOrQName.elementAt(identity);
   3041 
   3042 	    if (dataIndex >= 0)
   3043 	    {
   3044 	      if (-1 == offset)
   3045 	      {
   3046                 offset = dataIndex >>> TEXT_LENGTH_BITS;
   3047 	      }
   3048 
   3049 	      length += dataIndex & TEXT_LENGTH_MAX;
   3050 	    }
   3051 	    else
   3052 	    {
   3053 	      if (-1 == offset)
   3054 	      {
   3055                 offset = m_data.elementAt(-dataIndex);
   3056 	      }
   3057 
   3058 	      length += m_data.elementAt(-dataIndex + 1);
   3059 	    }
   3060 	  }
   3061 
   3062 	  identity++;
   3063 	} while (_parent2(identity) >= startNode);
   3064 
   3065 	if (length > 0)
   3066 	{
   3067           if(normalize)
   3068             m_chars.sendNormalizedSAXcharacters(ch, offset, length);
   3069           else
   3070 	    m_chars.sendSAXcharacters(ch, offset, length);
   3071 	}
   3072       }
   3073     }
   3074     else if (DTM.TEXT_NODE == type || DTM.CDATA_SECTION_NODE == type)
   3075     {
   3076       int dataIndex = m_dataOrQName.elementAt(identity);
   3077 
   3078       if (dataIndex >= 0)
   3079       {
   3080       	if (normalize)
   3081       	  m_chars.sendNormalizedSAXcharacters(ch, dataIndex >>> TEXT_LENGTH_BITS,
   3082       	                                      dataIndex & TEXT_LENGTH_MAX);
   3083       	else
   3084       	  m_chars.sendSAXcharacters(ch, dataIndex >>> TEXT_LENGTH_BITS,
   3085       	                            dataIndex & TEXT_LENGTH_MAX);
   3086       }
   3087       else
   3088       {
   3089         if (normalize)
   3090           m_chars.sendNormalizedSAXcharacters(ch, m_data.elementAt(-dataIndex),
   3091                                               m_data.elementAt(-dataIndex+1));
   3092         else
   3093           m_chars.sendSAXcharacters(ch, m_data.elementAt(-dataIndex),
   3094                                     m_data.elementAt(-dataIndex+1));
   3095       }
   3096     }
   3097     else
   3098     {
   3099       int dataIndex = m_dataOrQName.elementAt(identity);
   3100 
   3101       if (dataIndex < 0)
   3102       {
   3103         dataIndex = -dataIndex;
   3104         dataIndex = m_data.elementAt(dataIndex + 1);
   3105       }
   3106 
   3107       String str = (String)m_values.elementAt(dataIndex);
   3108 
   3109       if(normalize)
   3110         FastStringBuffer.sendNormalizedSAXcharacters(str.toCharArray(),
   3111                                                      0, str.length(), ch);
   3112       else
   3113         ch.characters(str.toCharArray(), 0, str.length());
   3114     }
   3115   }
   3116 
   3117   /**
   3118    * Given a node handle, return its node value. This is mostly
   3119    * as defined by the DOM, but may ignore some conveniences.
   3120    * <p>
   3121    *
   3122    * @param nodeHandle The node id.
   3123    * @return String Value of this node, or null if not
   3124    * meaningful for this node type.
   3125    */
   3126   public String getNodeValue(int nodeHandle)
   3127   {
   3128 
   3129     int identity = makeNodeIdentity(nodeHandle);
   3130     int type = _type2(identity);
   3131 
   3132     if (type == DTM.TEXT_NODE || type == DTM.CDATA_SECTION_NODE)
   3133     {
   3134       int dataIndex = _dataOrQName(identity);
   3135       if (dataIndex > 0)
   3136       {
   3137       	return m_chars.getString(dataIndex >>> TEXT_LENGTH_BITS,
   3138       	                          dataIndex & TEXT_LENGTH_MAX);
   3139       }
   3140       else
   3141       {
   3142         return m_chars.getString(m_data.elementAt(-dataIndex),
   3143                                   m_data.elementAt(-dataIndex+1));
   3144       }
   3145     }
   3146     else if (DTM.ELEMENT_NODE == type || DTM.DOCUMENT_FRAGMENT_NODE == type
   3147              || DTM.DOCUMENT_NODE == type)
   3148     {
   3149       return null;
   3150     }
   3151     else
   3152     {
   3153       int dataIndex = m_dataOrQName.elementAt(identity);
   3154 
   3155       if (dataIndex < 0)
   3156       {
   3157         dataIndex = -dataIndex;
   3158         dataIndex = m_data.elementAt(dataIndex + 1);
   3159       }
   3160 
   3161       return (String)m_values.elementAt(dataIndex);
   3162     }
   3163   }
   3164 
   3165     /**
   3166      * Copy the String value of a Text node to a SerializationHandler
   3167      */
   3168     protected final void copyTextNode(final int nodeID, SerializationHandler handler)
   3169         throws SAXException
   3170     {
   3171         if (nodeID != DTM.NULL) {
   3172       	    int dataIndex = m_dataOrQName.elementAt(nodeID);
   3173             if (dataIndex >= 0) {
   3174                 m_chars.sendSAXcharacters(handler,
   3175                                           dataIndex >>> TEXT_LENGTH_BITS,
   3176                                           dataIndex & TEXT_LENGTH_MAX);
   3177             } else {
   3178                 m_chars.sendSAXcharacters(handler, m_data.elementAt(-dataIndex),
   3179                                           m_data.elementAt(-dataIndex+1));
   3180             }
   3181         }
   3182     }
   3183 
   3184     /**
   3185      * Copy an Element node to a SerializationHandler.
   3186      *
   3187      * @param nodeID The node identity
   3188      * @param exptype The expanded type of the Element node
   3189      * @param handler The SerializationHandler
   3190      * @return The qualified name of the Element node.
   3191      */
   3192     protected final String copyElement(int nodeID, int exptype,
   3193                                SerializationHandler handler)
   3194         throws SAXException
   3195     {
   3196         final ExtendedType extType = m_extendedTypes[exptype];
   3197         String uri = extType.getNamespace();
   3198         String name = extType.getLocalName();
   3199 
   3200         if (uri.length() == 0) {
   3201             handler.startElement(name);
   3202             return name;
   3203         }
   3204         else {
   3205             int qnameIndex = m_dataOrQName.elementAt(nodeID);
   3206 
   3207             if (qnameIndex == 0) {
   3208                 handler.startElement(name);
   3209                 handler.namespaceAfterStartElement(EMPTY_STR, uri);
   3210                 return name;
   3211             }
   3212 
   3213             if (qnameIndex < 0) {
   3214     	        qnameIndex = -qnameIndex;
   3215     	        qnameIndex = m_data.elementAt(qnameIndex);
   3216             }
   3217 
   3218             String qName = m_valuesOrPrefixes.indexToString(qnameIndex);
   3219             handler.startElement(qName);
   3220             int prefixIndex = qName.indexOf(':');
   3221             String prefix;
   3222             if (prefixIndex > 0) {
   3223                 prefix = qName.substring(0, prefixIndex);
   3224             }
   3225             else {
   3226                 prefix = null;
   3227             }
   3228             handler.namespaceAfterStartElement(prefix, uri);
   3229             return qName;
   3230         }
   3231 
   3232     }
   3233 
   3234     /**
   3235      * Copy  namespace nodes.
   3236      *
   3237      * @param nodeID The Element node identity
   3238      * @param handler The SerializationHandler
   3239      * @param inScope  true if all namespaces in scope should be copied,
   3240      *  false if only the namespace declarations should be copied.
   3241      */
   3242     protected final void copyNS(final int nodeID, SerializationHandler handler, boolean inScope)
   3243         throws SAXException
   3244     {
   3245         // %OPT% Optimization for documents which does not have any explicit
   3246         // namespace nodes. For these documents, there is an implicit
   3247         // namespace node (xmlns:xml="http://www.w3.org/XML/1998/namespace")
   3248         // declared on the root element node. In this case, there is no
   3249         // need to do namespace copying. We can safely return without
   3250         // doing anything.
   3251         if (m_namespaceDeclSetElements != null &&
   3252             m_namespaceDeclSetElements.size() == 1 &&
   3253             m_namespaceDeclSets != null &&
   3254             ((SuballocatedIntVector)m_namespaceDeclSets.elementAt(0))
   3255             .size() == 1)
   3256             return;
   3257 
   3258         SuballocatedIntVector nsContext = null;
   3259         int nextNSNode;
   3260 
   3261         // Find the first namespace node
   3262         if (inScope) {
   3263             nsContext = findNamespaceContext(nodeID);
   3264             if (nsContext == null || nsContext.size() < 1)
   3265                 return;
   3266             else
   3267                 nextNSNode = makeNodeIdentity(nsContext.elementAt(0));
   3268         }
   3269         else
   3270             nextNSNode = getNextNamespaceNode2(nodeID);
   3271 
   3272         int nsIndex = 1;
   3273         while (nextNSNode != DTM.NULL) {
   3274             // Retrieve the name of the namespace node
   3275             int eType = _exptype2(nextNSNode);
   3276             String nodeName = m_extendedTypes[eType].getLocalName();
   3277 
   3278             // Retrieve the node value of the namespace node
   3279             int dataIndex = m_dataOrQName.elementAt(nextNSNode);
   3280 
   3281             if (dataIndex < 0) {
   3282                 dataIndex = -dataIndex;
   3283                 dataIndex = m_data.elementAt(dataIndex + 1);
   3284             }
   3285 
   3286             String nodeValue = (String)m_values.elementAt(dataIndex);
   3287 
   3288             handler.namespaceAfterStartElement(nodeName, nodeValue);
   3289 
   3290             if (inScope) {
   3291                 if (nsIndex < nsContext.size()) {
   3292                     nextNSNode = makeNodeIdentity(nsContext.elementAt(nsIndex));
   3293                     nsIndex++;
   3294                 }
   3295                 else
   3296                     return;
   3297             }
   3298             else
   3299                 nextNSNode = getNextNamespaceNode2(nextNSNode);
   3300         }
   3301     }
   3302 
   3303     /**
   3304      * Return the next namespace node following the given base node.
   3305      *
   3306      * @baseID The node identity of the base node, which can be an
   3307      * element, attribute or namespace node.
   3308      * @return The namespace node immediately following the base node.
   3309      */
   3310     protected final int getNextNamespaceNode2(int baseID) {
   3311         int type;
   3312         while ((type = _type2(++baseID)) == DTM.ATTRIBUTE_NODE);
   3313 
   3314         if (type == DTM.NAMESPACE_NODE)
   3315             return baseID;
   3316         else
   3317             return NULL;
   3318     }
   3319 
   3320     /**
   3321      * Copy  attribute nodes from an element .
   3322      *
   3323      * @param nodeID The Element node identity
   3324      * @param handler The SerializationHandler
   3325      */
   3326     protected final void copyAttributes(final int nodeID, SerializationHandler handler)
   3327         throws SAXException{
   3328 
   3329        for(int current = getFirstAttributeIdentity(nodeID); current != DTM.NULL; current = getNextAttributeIdentity(current)){
   3330             int eType = _exptype2(current);
   3331             copyAttribute(current, eType, handler);
   3332        }
   3333     }
   3334 
   3335 
   3336 
   3337     /**
   3338      * Copy an Attribute node to a SerializationHandler
   3339      *
   3340      * @param nodeID The node identity
   3341      * @param exptype The expanded type of the Element node
   3342      * @param handler The SerializationHandler
   3343      */
   3344     protected final void copyAttribute(int nodeID, int exptype,
   3345         SerializationHandler handler)
   3346         throws SAXException
   3347     {
   3348         /*
   3349             final String uri = getNamespaceName(node);
   3350             if (uri.length() != 0) {
   3351                 final String prefix = getPrefix(node);
   3352                 handler.namespaceAfterStartElement(prefix, uri);
   3353             }
   3354             handler.addAttribute(getNodeName(node), getNodeValue(node));
   3355         */
   3356         final ExtendedType extType = m_extendedTypes[exptype];
   3357         final String uri = extType.getNamespace();
   3358         final String localName = extType.getLocalName();
   3359 
   3360         String prefix = null;
   3361         String qname = null;
   3362         int dataIndex = _dataOrQName(nodeID);
   3363         int valueIndex = dataIndex;
   3364             if (dataIndex <= 0) {
   3365                 int prefixIndex = m_data.elementAt(-dataIndex);
   3366                 valueIndex = m_data.elementAt(-dataIndex+1);
   3367                 qname = m_valuesOrPrefixes.indexToString(prefixIndex);
   3368                 int colonIndex = qname.indexOf(':');
   3369                 if (colonIndex > 0) {
   3370                     prefix = qname.substring(0, colonIndex);
   3371                 }
   3372             }
   3373             if (uri.length() != 0) {
   3374                 handler.namespaceAfterStartElement(prefix, uri);
   3375             }
   3376 
   3377         String nodeName = (prefix != null) ? qname : localName;
   3378         String nodeValue = (String)m_values.elementAt(valueIndex);
   3379 
   3380         handler.addAttribute(nodeName, nodeValue);
   3381     }
   3382 
   3383 }
   3384