Home | History | Annotate | Download | only in ref
      1 /*
      2  * Licensed to the Apache Software Foundation (ASF) under one
      3  * or more contributor license agreements. See the NOTICE file
      4  * distributed with this work for additional information
      5  * regarding copyright ownership. The ASF licenses this file
      6  * to you under the Apache License, Version 2.0 (the  "License");
      7  * you may not use this file except in compliance with the License.
      8  * You may obtain a copy of the License at
      9  *
     10  *     http://www.apache.org/licenses/LICENSE-2.0
     11  *
     12  * Unless required by applicable law or agreed to in writing, software
     13  * distributed under the License is distributed on an "AS IS" BASIS,
     14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     15  * See the License for the specific language governing permissions and
     16  * limitations under the License.
     17  */
     18 /*
     19  * $Id: DTMDefaultBase.java 468653 2006-10-28 07:07:05Z minchau $
     20  */
     21 package org.apache.xml.dtm.ref;
     22 
     23 import org.apache.xml.dtm.*;
     24 import org.apache.xml.utils.SuballocatedIntVector;
     25 import org.apache.xml.utils.BoolStack;
     26 
     27 import java.util.Vector;
     28 
     29 import javax.xml.transform.Source;
     30 
     31 import org.apache.xml.utils.XMLString;
     32 import org.apache.xml.utils.XMLStringFactory;
     33 
     34 import org.apache.xml.res.XMLMessages;
     35 import org.apache.xml.res.XMLErrorResources;
     36 
     37 import java.io.*; // for dumpDTM
     38 
     39 /**
     40  * The <code>DTMDefaultBase</code> class serves as a helper base for DTMs.
     41  * It sets up structures for navigation and type, while leaving data
     42  * management and construction to the derived classes.
     43  */
     44 public abstract class DTMDefaultBase implements DTM
     45 {
     46     static final boolean JJK_DEBUG=false;
     47 
     48   // This constant is likely to be removed in the future. Use the
     49   // getDocument() method instead of ROOTNODE to get at the root
     50   // node of a DTM.
     51   /** The identity of the root node. */
     52   public static final int ROOTNODE = 0;
     53 
     54   /**
     55    * The number of nodes, which is also used to determine the next
     56    *  node index.
     57    */
     58   protected int m_size = 0;
     59 
     60   /** The expanded names, one array element for each node. */
     61   protected SuballocatedIntVector m_exptype;
     62 
     63   /** First child values, one array element for each node. */
     64   protected SuballocatedIntVector m_firstch;
     65 
     66   /** Next sibling values, one array element for each node. */
     67   protected SuballocatedIntVector m_nextsib;
     68 
     69   /** Previous sibling values, one array element for each node. */
     70   protected SuballocatedIntVector m_prevsib;
     71 
     72   /** Previous sibling values, one array element for each node. */
     73   protected SuballocatedIntVector m_parent;
     74 
     75   /** Vector of SuballocatedIntVectors of NS decl sets */
     76   protected Vector m_namespaceDeclSets = null;
     77 
     78   /** SuballocatedIntVector  of elements at which corresponding
     79    * namespaceDeclSets were defined */
     80   protected SuballocatedIntVector m_namespaceDeclSetElements = null;
     81 
     82   /**
     83    * These hold indexes to elements based on namespace and local name.
     84    * The base lookup is the the namespace.  The second lookup is the local
     85    * name, and the last array contains the the first free element
     86    * at the start, and the list of element handles following.
     87    */
     88   protected int[][][] m_elemIndexes;
     89 
     90   /** The default block size of the node arrays */
     91   public static final int DEFAULT_BLOCKSIZE = 512;  // favor small docs.
     92 
     93   /** The number of blocks for the node arrays */
     94   public static final int DEFAULT_NUMBLOCKS = 32;
     95 
     96   /** The number of blocks used for small documents & RTFs */
     97   public static final int DEFAULT_NUMBLOCKS_SMALL = 4;
     98 
     99   /** The block size of the node arrays */
    100   //protected final int m_blocksize;
    101 
    102   /**
    103    * The value to use when the information has not been built yet.
    104    */
    105   protected static final int NOTPROCESSED = DTM.NULL - 1;
    106 
    107   /**
    108    * The DTM manager who "owns" this DTM.
    109    */
    110 
    111   public DTMManager m_mgr;
    112 
    113   /**
    114    * m_mgr cast to DTMManagerDefault, or null if it isn't an instance
    115    * (Efficiency hook)
    116    */
    117   protected DTMManagerDefault m_mgrDefault=null;
    118 
    119 
    120   /** The document identity number(s). If we have overflowed the addressing
    121    * range of the first that was assigned to us, we may add others. */
    122   protected SuballocatedIntVector m_dtmIdent;
    123 
    124   /** The mask for the identity.
    125       %REVIEW% Should this really be set to the _DEFAULT? What if
    126       a particular DTM wanted to use another value? */
    127   //protected final static int m_mask = DTMManager.IDENT_NODE_DEFAULT;
    128 
    129   /** The base URI for this document. */
    130   protected String m_documentBaseURI;
    131 
    132   /**
    133    * The whitespace filter that enables elements to strip whitespace or not.
    134    */
    135   protected DTMWSFilter m_wsfilter;
    136 
    137   /** Flag indicating whether to strip whitespace nodes */
    138   protected boolean m_shouldStripWS = false;
    139 
    140   /** Stack of flags indicating whether to strip whitespace nodes */
    141   protected BoolStack m_shouldStripWhitespaceStack;
    142 
    143   /** The XMLString factory for creating XMLStrings. */
    144   protected XMLStringFactory m_xstrf;
    145 
    146   /**
    147    * The table for exandedNameID lookups.  This may or may not be the same
    148    * table as is contained in the DTMManagerDefault.
    149    */
    150   protected ExpandedNameTable m_expandedNameTable;
    151 
    152   /** true if indexing is turned on. */
    153   protected boolean m_indexing;
    154 
    155   /**
    156    * Construct a DTMDefaultBase object using the default block size.
    157    *
    158    * @param mgr The DTMManager who owns this DTM.
    159    * @param source The object that is used to specify the construction source.
    160    * @param dtmIdentity The DTM identity ID for this DTM.
    161    * @param whiteSpaceFilter The white space filter for this DTM, which may
    162    *                         be null.
    163    * @param xstringfactory The factory to use for creating XMLStrings.
    164    * @param doIndexing true if the caller considers it worth it to use
    165    *                   indexing schemes.
    166    */
    167   public DTMDefaultBase(DTMManager mgr, Source source, int dtmIdentity,
    168   			DTMWSFilter whiteSpaceFilter,
    169   			XMLStringFactory xstringfactory, boolean doIndexing)
    170   {
    171     this(mgr, source, dtmIdentity, whiteSpaceFilter, xstringfactory,
    172          doIndexing, DEFAULT_BLOCKSIZE, true, false);
    173   }
    174 
    175   /**
    176    * Construct a DTMDefaultBase object from a DOM node.
    177    *
    178    * @param mgr The DTMManager who owns this DTM.
    179    * @param source The object that is used to specify the construction source.
    180    * @param dtmIdentity The DTM identity ID for this DTM.
    181    * @param whiteSpaceFilter The white space filter for this DTM, which may
    182    *                         be null.
    183    * @param xstringfactory The factory to use for creating XMLStrings.
    184    * @param doIndexing true if the caller considers it worth it to use
    185    *                   indexing schemes.
    186    * @param blocksize The block size of the DTM.
    187    * @param usePrevsib true if we want to build the previous sibling node array.
    188    * @param newNameTable true if we want to use a new ExpandedNameTable for this DTM.
    189    */
    190   public DTMDefaultBase(DTMManager mgr, Source source, int dtmIdentity,
    191                         DTMWSFilter whiteSpaceFilter,
    192                         XMLStringFactory xstringfactory, boolean doIndexing,
    193                         int blocksize, boolean usePrevsib,
    194                         boolean newNameTable)
    195   {
    196     // Use smaller sizes for the internal node arrays if the block size
    197     // is small.
    198     int numblocks;
    199     if (blocksize <= 64)
    200     {
    201       numblocks = DEFAULT_NUMBLOCKS_SMALL;
    202       m_dtmIdent= new SuballocatedIntVector(4, 1);
    203     }
    204     else
    205     {
    206       numblocks = DEFAULT_NUMBLOCKS;
    207       m_dtmIdent= new SuballocatedIntVector(32);
    208     }
    209 
    210     m_exptype = new SuballocatedIntVector(blocksize, numblocks);
    211     m_firstch = new SuballocatedIntVector(blocksize, numblocks);
    212     m_nextsib = new SuballocatedIntVector(blocksize, numblocks);
    213     m_parent  = new SuballocatedIntVector(blocksize, numblocks);
    214 
    215     // Only create the m_prevsib array if the usePrevsib flag is true.
    216     // Some DTM implementations (e.g. SAXImpl) do not need this array.
    217     // We can save the time to build it in those cases.
    218     if (usePrevsib)
    219       m_prevsib = new SuballocatedIntVector(blocksize, numblocks);
    220 
    221     m_mgr = mgr;
    222     if(mgr instanceof DTMManagerDefault)
    223       m_mgrDefault=(DTMManagerDefault)mgr;
    224 
    225     m_documentBaseURI = (null != source) ? source.getSystemId() : null;
    226     m_dtmIdent.setElementAt(dtmIdentity,0);
    227     m_wsfilter = whiteSpaceFilter;
    228     m_xstrf = xstringfactory;
    229     m_indexing = doIndexing;
    230 
    231     if (doIndexing)
    232     {
    233       m_expandedNameTable = new ExpandedNameTable();
    234     }
    235     else
    236     {
    237       // Note that this fails if we aren't talking to an instance of
    238       // DTMManagerDefault
    239       m_expandedNameTable = m_mgrDefault.getExpandedNameTable(this);
    240     }
    241 
    242     if (null != whiteSpaceFilter)
    243     {
    244       m_shouldStripWhitespaceStack = new BoolStack();
    245 
    246       pushShouldStripWhitespace(false);
    247     }
    248   }
    249 
    250   /**
    251    * Ensure that the size of the element indexes can hold the information.
    252    *
    253    * @param namespaceID Namespace ID index.
    254    * @param LocalNameID Local name ID.
    255    */
    256   protected void ensureSizeOfIndex(int namespaceID, int LocalNameID)
    257   {
    258 
    259     if (null == m_elemIndexes)
    260     {
    261       m_elemIndexes = new int[namespaceID + 20][][];
    262     }
    263     else if (m_elemIndexes.length <= namespaceID)
    264     {
    265       int[][][] indexes = m_elemIndexes;
    266 
    267       m_elemIndexes = new int[namespaceID + 20][][];
    268 
    269       System.arraycopy(indexes, 0, m_elemIndexes, 0, indexes.length);
    270     }
    271 
    272     int[][] localNameIndex = m_elemIndexes[namespaceID];
    273 
    274     if (null == localNameIndex)
    275     {
    276       localNameIndex = new int[LocalNameID + 100][];
    277       m_elemIndexes[namespaceID] = localNameIndex;
    278     }
    279     else if (localNameIndex.length <= LocalNameID)
    280     {
    281       int[][] indexes = localNameIndex;
    282 
    283       localNameIndex = new int[LocalNameID + 100][];
    284 
    285       System.arraycopy(indexes, 0, localNameIndex, 0, indexes.length);
    286 
    287       m_elemIndexes[namespaceID] = localNameIndex;
    288     }
    289 
    290     int[] elemHandles = localNameIndex[LocalNameID];
    291 
    292     if (null == elemHandles)
    293     {
    294       elemHandles = new int[128];
    295       localNameIndex[LocalNameID] = elemHandles;
    296       elemHandles[0] = 1;
    297     }
    298     else if (elemHandles.length <= elemHandles[0] + 1)
    299     {
    300       int[] indexes = elemHandles;
    301 
    302       elemHandles = new int[elemHandles[0] + 1024];
    303 
    304       System.arraycopy(indexes, 0, elemHandles, 0, indexes.length);
    305 
    306       localNameIndex[LocalNameID] = elemHandles;
    307     }
    308   }
    309 
    310   /**
    311    * Add a node to the element indexes. The node will not be added unless
    312    * it's an element.
    313    *
    314    * @param expandedTypeID The expanded type ID of the node.
    315    * @param identity The node identity index.
    316    */
    317   protected void indexNode(int expandedTypeID, int identity)
    318   {
    319 
    320     ExpandedNameTable ent = m_expandedNameTable;
    321     short type = ent.getType(expandedTypeID);
    322 
    323     if (DTM.ELEMENT_NODE == type)
    324     {
    325       int namespaceID = ent.getNamespaceID(expandedTypeID);
    326       int localNameID = ent.getLocalNameID(expandedTypeID);
    327 
    328       ensureSizeOfIndex(namespaceID, localNameID);
    329 
    330       int[] index = m_elemIndexes[namespaceID][localNameID];
    331 
    332       index[index[0]] = identity;
    333 
    334       index[0]++;
    335     }
    336   }
    337 
    338   /**
    339    * Find the first index that occurs in the list that is greater than or
    340    * equal to the given value.
    341    *
    342    * @param list A list of integers.
    343    * @param start The start index to begin the search.
    344    * @param len The number of items to search.
    345    * @param value Find the slot that has a value that is greater than or
    346    * identical to this argument.
    347    *
    348    * @return The index in the list of the slot that is higher or identical
    349    * to the identity argument, or -1 if no node is higher or equal.
    350    */
    351   protected int findGTE(int[] list, int start, int len, int value)
    352   {
    353 
    354     int low = start;
    355     int high = start + (len - 1);
    356     int end = high;
    357 
    358     while (low <= high)
    359     {
    360       int mid = (low + high) / 2;
    361       int c = list[mid];
    362 
    363       if (c > value)
    364         high = mid - 1;
    365       else if (c < value)
    366         low = mid + 1;
    367       else
    368         return mid;
    369     }
    370 
    371     return (low <= end && list[low] > value) ? low : -1;
    372   }
    373 
    374   /**
    375    * Find the first matching element from the index at or after the
    376    * given node.
    377    *
    378    * @param nsIndex The namespace index lookup.
    379    * @param lnIndex The local name index lookup.
    380    * @param firstPotential The first potential match that is worth looking at.
    381    *
    382    * @return The first node that is greater than or equal to the
    383    *         firstPotential argument, or DTM.NOTPROCESSED if not found.
    384    */
    385   int findElementFromIndex(int nsIndex, int lnIndex, int firstPotential)
    386   {
    387 
    388     int[][][] indexes = m_elemIndexes;
    389 
    390     if (null != indexes && nsIndex < indexes.length)
    391     {
    392       int[][] lnIndexs = indexes[nsIndex];
    393 
    394       if (null != lnIndexs && lnIndex < lnIndexs.length)
    395       {
    396         int[] elems = lnIndexs[lnIndex];
    397 
    398         if (null != elems)
    399         {
    400           int pos = findGTE(elems, 1, elems[0], firstPotential);
    401 
    402           if (pos > -1)
    403           {
    404             return elems[pos];
    405           }
    406         }
    407       }
    408     }
    409 
    410     return NOTPROCESSED;
    411   }
    412 
    413   /**
    414    * Get the next node identity value in the list, and call the iterator
    415    * if it hasn't been added yet.
    416    *
    417    * @param identity The node identity (index).
    418    * @return identity+1, or DTM.NULL.
    419    */
    420   protected abstract int getNextNodeIdentity(int identity);
    421 
    422   /**
    423    * This method should try and build one or more nodes in the table.
    424    *
    425    * @return The true if a next node is found or false if
    426    *         there are no more nodes.
    427    */
    428   protected abstract boolean nextNode();
    429 
    430   /**
    431    * Get the number of nodes that have been added.
    432    *
    433    * @return the number of nodes that have been mapped.
    434    */
    435   protected abstract int getNumberOfNodes();
    436 
    437   /** Stateless axis traversers, lazely built. */
    438   protected DTMAxisTraverser[] m_traversers;
    439 
    440 //    /**
    441 //     * Ensure that the size of the information arrays can hold another entry
    442 //     * at the given index.
    443 //     *
    444 //     * @param index On exit from this function, the information arrays sizes must be
    445 //     * at least index+1.
    446 //     */
    447 //    protected void ensureSize(int index)
    448 //    {
    449 //        // We've cut over to Suballocated*Vector, which are self-sizing.
    450 //    }
    451 
    452   /**
    453    * Get the simple type ID for the given node identity.
    454    *
    455    * @param identity The node identity.
    456    *
    457    * @return The simple type ID, or DTM.NULL.
    458    */
    459   protected short _type(int identity)
    460   {
    461 
    462     int info = _exptype(identity);
    463 
    464     if (NULL != info)
    465       return m_expandedNameTable.getType(info);
    466     else
    467       return NULL;
    468   }
    469 
    470   /**
    471    * Get the expanded type ID for the given node identity.
    472    *
    473    * @param identity The node identity.
    474    *
    475    * @return The expanded type ID, or DTM.NULL.
    476    */
    477   protected int _exptype(int identity)
    478   {
    479   	if (identity == DTM.NULL)
    480   	return NULL;
    481     // Reorganized test and loop into single flow
    482     // Tiny performance improvement, saves a few bytes of code, clearer.
    483     // %OPT% Other internal getters could be treated simliarly
    484     while (identity>=m_size)
    485     {
    486       if (!nextNode() && identity >= m_size)
    487         return NULL;
    488     }
    489     return m_exptype.elementAt(identity);
    490 
    491   }
    492 
    493   /**
    494    * Get the level in the tree for the given node identity.
    495    *
    496    * @param identity The node identity.
    497    *
    498    * @return The tree level, or DTM.NULL.
    499    */
    500   protected int _level(int identity)
    501   {
    502     while (identity>=m_size)
    503     {
    504       boolean isMore = nextNode();
    505       if (!isMore && identity >= m_size)
    506         return NULL;
    507     }
    508 
    509     int i=0;
    510     while(NULL != (identity=_parent(identity)))
    511       ++i;
    512     return i;
    513   }
    514 
    515   /**
    516    * Get the first child for the given node identity.
    517    *
    518    * @param identity The node identity.
    519    *
    520    * @return The first child identity, or DTM.NULL.
    521    */
    522   protected int _firstch(int identity)
    523   {
    524 
    525     // Boiler-plate code for each of the _xxx functions, except for the array.
    526     int info = (identity >= m_size) ? NOTPROCESSED : m_firstch.elementAt(identity);
    527 
    528     // Check to see if the information requested has been processed, and,
    529     // if not, advance the iterator until we the information has been
    530     // processed.
    531     while (info == NOTPROCESSED)
    532     {
    533       boolean isMore = nextNode();
    534 
    535       if (identity >= m_size &&!isMore)
    536         return NULL;
    537       else
    538       {
    539         info = m_firstch.elementAt(identity);
    540         if(info == NOTPROCESSED && !isMore)
    541           return NULL;
    542       }
    543     }
    544 
    545     return info;
    546   }
    547 
    548   /**
    549    * Get the next sibling for the given node identity.
    550    *
    551    * @param identity The node identity.
    552    *
    553    * @return The next sibling identity, or DTM.NULL.
    554    */
    555   protected int _nextsib(int identity)
    556   {
    557     // Boiler-plate code for each of the _xxx functions, except for the array.
    558     int info = (identity >= m_size) ? NOTPROCESSED : m_nextsib.elementAt(identity);
    559 
    560     // Check to see if the information requested has been processed, and,
    561     // if not, advance the iterator until we the information has been
    562     // processed.
    563     while (info == NOTPROCESSED)
    564     {
    565       boolean isMore = nextNode();
    566 
    567       if (identity >= m_size &&!isMore)
    568         return NULL;
    569       else
    570       {
    571         info = m_nextsib.elementAt(identity);
    572         if(info == NOTPROCESSED && !isMore)
    573           return NULL;
    574       }
    575     }
    576 
    577     return info;
    578   }
    579 
    580   /**
    581    * Get the previous sibling for the given node identity.
    582    *
    583    * @param identity The node identity.
    584    *
    585    * @return The previous sibling identity, or DTM.NULL.
    586    */
    587   protected int _prevsib(int identity)
    588   {
    589 
    590     if (identity < m_size)
    591       return m_prevsib.elementAt(identity);
    592 
    593     // Check to see if the information requested has been processed, and,
    594     // if not, advance the iterator until we the information has been
    595     // processed.
    596     while (true)
    597     {
    598       boolean isMore = nextNode();
    599 
    600       if (identity >= m_size && !isMore)
    601         return NULL;
    602       else if (identity < m_size)
    603         return m_prevsib.elementAt(identity);
    604     }
    605   }
    606 
    607   /**
    608    * Get the parent for the given node identity.
    609    *
    610    * @param identity The node identity.
    611    *
    612    * @return The parent identity, or DTM.NULL.
    613    */
    614   protected int _parent(int identity)
    615   {
    616 
    617     if (identity < m_size)
    618       return m_parent.elementAt(identity);
    619 
    620     // Check to see if the information requested has been processed, and,
    621     // if not, advance the iterator until we the information has been
    622     // processed.
    623     while (true)
    624     {
    625       boolean isMore = nextNode();
    626 
    627       if (identity >= m_size && !isMore)
    628         return NULL;
    629       else if (identity < m_size)
    630         return m_parent.elementAt(identity);
    631     }
    632   }
    633 
    634   /**
    635    * Diagnostics function to dump the DTM.
    636    */
    637   public void dumpDTM(OutputStream os)
    638   {
    639     try
    640     {
    641       if(os==null)
    642       {
    643 	      File f = new File("DTMDump"+((Object)this).hashCode()+".txt");
    644  	      System.err.println("Dumping... "+f.getAbsolutePath());
    645  	      os=new FileOutputStream(f);
    646       }
    647       PrintStream ps = new PrintStream(os);
    648 
    649       while (nextNode()){}
    650 
    651       int nRecords = m_size;
    652 
    653       ps.println("Total nodes: " + nRecords);
    654 
    655       for (int index = 0; index < nRecords; ++index)
    656       {
    657       	int i=makeNodeHandle(index);
    658         ps.println("=========== index=" + index + " handle=" + i + " ===========");
    659         ps.println("NodeName: " + getNodeName(i));
    660         ps.println("NodeNameX: " + getNodeNameX(i));
    661         ps.println("LocalName: " + getLocalName(i));
    662         ps.println("NamespaceURI: " + getNamespaceURI(i));
    663         ps.println("Prefix: " + getPrefix(i));
    664 
    665         int exTypeID = _exptype(index);
    666 
    667         ps.println("Expanded Type ID: "
    668                            + Integer.toHexString(exTypeID));
    669 
    670         int type = _type(index);
    671         String typestring;
    672 
    673         switch (type)
    674         {
    675         case DTM.ATTRIBUTE_NODE :
    676           typestring = "ATTRIBUTE_NODE";
    677           break;
    678         case DTM.CDATA_SECTION_NODE :
    679           typestring = "CDATA_SECTION_NODE";
    680           break;
    681         case DTM.COMMENT_NODE :
    682           typestring = "COMMENT_NODE";
    683           break;
    684         case DTM.DOCUMENT_FRAGMENT_NODE :
    685           typestring = "DOCUMENT_FRAGMENT_NODE";
    686           break;
    687         case DTM.DOCUMENT_NODE :
    688           typestring = "DOCUMENT_NODE";
    689           break;
    690         case DTM.DOCUMENT_TYPE_NODE :
    691           typestring = "DOCUMENT_NODE";
    692           break;
    693         case DTM.ELEMENT_NODE :
    694           typestring = "ELEMENT_NODE";
    695           break;
    696         case DTM.ENTITY_NODE :
    697           typestring = "ENTITY_NODE";
    698           break;
    699         case DTM.ENTITY_REFERENCE_NODE :
    700           typestring = "ENTITY_REFERENCE_NODE";
    701           break;
    702         case DTM.NAMESPACE_NODE :
    703           typestring = "NAMESPACE_NODE";
    704           break;
    705         case DTM.NOTATION_NODE :
    706           typestring = "NOTATION_NODE";
    707           break;
    708         case DTM.NULL :
    709           typestring = "NULL";
    710           break;
    711         case DTM.PROCESSING_INSTRUCTION_NODE :
    712           typestring = "PROCESSING_INSTRUCTION_NODE";
    713           break;
    714         case DTM.TEXT_NODE :
    715           typestring = "TEXT_NODE";
    716           break;
    717         default :
    718           typestring = "Unknown!";
    719           break;
    720         }
    721 
    722         ps.println("Type: " + typestring);
    723 
    724         int firstChild = _firstch(index);
    725 
    726         if (DTM.NULL == firstChild)
    727           ps.println("First child: DTM.NULL");
    728         else if (NOTPROCESSED == firstChild)
    729           ps.println("First child: NOTPROCESSED");
    730         else
    731           ps.println("First child: " + firstChild);
    732 
    733         if (m_prevsib != null)
    734         {
    735           int prevSibling = _prevsib(index);
    736 
    737           if (DTM.NULL == prevSibling)
    738             ps.println("Prev sibling: DTM.NULL");
    739           else if (NOTPROCESSED == prevSibling)
    740             ps.println("Prev sibling: NOTPROCESSED");
    741           else
    742             ps.println("Prev sibling: " + prevSibling);
    743         }
    744 
    745         int nextSibling = _nextsib(index);
    746 
    747         if (DTM.NULL == nextSibling)
    748           ps.println("Next sibling: DTM.NULL");
    749         else if (NOTPROCESSED == nextSibling)
    750           ps.println("Next sibling: NOTPROCESSED");
    751         else
    752           ps.println("Next sibling: " + nextSibling);
    753 
    754         int parent = _parent(index);
    755 
    756         if (DTM.NULL == parent)
    757           ps.println("Parent: DTM.NULL");
    758         else if (NOTPROCESSED == parent)
    759           ps.println("Parent: NOTPROCESSED");
    760         else
    761           ps.println("Parent: " + parent);
    762 
    763         int level = _level(index);
    764 
    765         ps.println("Level: " + level);
    766         ps.println("Node Value: " + getNodeValue(i));
    767         ps.println("String Value: " + getStringValue(i));
    768       }
    769     }
    770     catch(IOException ioe)
    771     {
    772       ioe.printStackTrace(System.err);
    773         throw new RuntimeException(ioe.getMessage());
    774     }
    775   }
    776 
    777   /**
    778    * Diagnostics function to dump a single node.
    779    *
    780    * %REVIEW% KNOWN GLITCH: If you pass it a node index rather than a
    781    * node handle, it works just fine... but the displayed identity
    782    * number before the colon is different, which complicates comparing
    783    * it with nodes printed the other way. We could always OR the DTM ID
    784    * into the value, to suppress that distinction...
    785    *
    786    * %REVIEW% This might want to be moved up to DTMDefaultBase, or possibly
    787    * DTM itself, since it's a useful diagnostic and uses only DTM's public
    788    * APIs.
    789    */
    790   public String dumpNode(int nodeHandle)
    791   {
    792 	  if(nodeHandle==DTM.NULL)
    793 		  return "[null]";
    794 
    795         String typestring;
    796         switch (getNodeType(nodeHandle))
    797         {
    798         case DTM.ATTRIBUTE_NODE :
    799           typestring = "ATTR";
    800           break;
    801         case DTM.CDATA_SECTION_NODE :
    802           typestring = "CDATA";
    803           break;
    804         case DTM.COMMENT_NODE :
    805           typestring = "COMMENT";
    806           break;
    807         case DTM.DOCUMENT_FRAGMENT_NODE :
    808           typestring = "DOC_FRAG";
    809           break;
    810         case DTM.DOCUMENT_NODE :
    811           typestring = "DOC";
    812           break;
    813         case DTM.DOCUMENT_TYPE_NODE :
    814           typestring = "DOC_TYPE";
    815           break;
    816         case DTM.ELEMENT_NODE :
    817           typestring = "ELEMENT";
    818           break;
    819         case DTM.ENTITY_NODE :
    820           typestring = "ENTITY";
    821           break;
    822         case DTM.ENTITY_REFERENCE_NODE :
    823           typestring = "ENT_REF";
    824           break;
    825         case DTM.NAMESPACE_NODE :
    826           typestring = "NAMESPACE";
    827           break;
    828         case DTM.NOTATION_NODE :
    829           typestring = "NOTATION";
    830           break;
    831         case DTM.NULL :
    832           typestring = "null";
    833           break;
    834         case DTM.PROCESSING_INSTRUCTION_NODE :
    835           typestring = "PI";
    836           break;
    837         case DTM.TEXT_NODE :
    838           typestring = "TEXT";
    839           break;
    840         default :
    841           typestring = "Unknown!";
    842           break;
    843         }
    844 
    845       StringBuffer sb=new StringBuffer();
    846 	  sb.append("["+nodeHandle+": "+typestring+
    847 				"(0x"+Integer.toHexString(getExpandedTypeID(nodeHandle))+") "+
    848 				getNodeNameX(nodeHandle)+" {"+getNamespaceURI(nodeHandle)+"}"+
    849 				"=\""+ getNodeValue(nodeHandle)+"\"]");
    850 	  return sb.toString();
    851   }
    852 
    853   // ========= DTM Implementation Control Functions. ==============
    854 
    855   /**
    856    * Set an implementation dependent feature.
    857    * <p>
    858    * %REVIEW% Do we really expect to set features on DTMs?
    859    *
    860    * @param featureId A feature URL.
    861    * @param state true if this feature should be on, false otherwise.
    862    */
    863   public void setFeature(String featureId, boolean state){}
    864 
    865   // ========= Document Navigation Functions =========
    866 
    867   /**
    868    * Given a node handle, test if it has child nodes.
    869    * <p> %REVIEW% This is obviously useful at the DOM layer, where it
    870    * would permit testing this without having to create a proxy
    871    * node. It's less useful in the DTM API, where
    872    * (dtm.getFirstChild(nodeHandle)!=DTM.NULL) is just as fast and
    873    * almost as self-evident. But it's a convenience, and eases porting
    874    * of DOM code to DTM.  </p>
    875    *
    876    * @param nodeHandle int Handle of the node.
    877    * @return int true if the given node has child nodes.
    878    */
    879   public boolean hasChildNodes(int nodeHandle)
    880   {
    881 
    882     int identity = makeNodeIdentity(nodeHandle);
    883     int firstChild = _firstch(identity);
    884 
    885     return firstChild != DTM.NULL;
    886   }
    887 
    888   /** Given a node identity, return a node handle. If extended addressing
    889    * has been used (multiple DTM IDs), we need to map the high bits of the
    890    * identity into the proper DTM ID.
    891    *
    892    * This has been made FINAL to facilitate inlining, since we do not expect
    893    * any subclass of DTMDefaultBase to ever change the algorithm. (I don't
    894    * really like doing so, and would love to have an excuse not to...)
    895    *
    896    * %REVIEW% Is it worth trying to specialcase small documents?
    897    * %REVIEW% Should this be exposed at the package/public layers?
    898    *
    899    * @param nodeIdentity Internal offset to this node's records.
    900    * @return NodeHandle (external representation of node)
    901    * */
    902   final public int makeNodeHandle(int nodeIdentity)
    903   {
    904     if(NULL==nodeIdentity) return NULL;
    905 
    906     if(JJK_DEBUG && nodeIdentity>DTMManager.IDENT_NODE_DEFAULT)
    907       System.err.println("GONK! (only useful in limited situations)");
    908 
    909     return m_dtmIdent.elementAt(nodeIdentity >>> DTMManager.IDENT_DTM_NODE_BITS)
    910       + (nodeIdentity & DTMManager.IDENT_NODE_DEFAULT) ;
    911   }
    912 
    913   /** Given a node handle, return a node identity. If extended addressing
    914    * has been used (multiple DTM IDs), we need to map the high bits of the
    915    * identity into the proper DTM ID and thence find the proper offset
    916    * to add to the low bits of the identity
    917    *
    918    * This has been made FINAL to facilitate inlining, since we do not expect
    919    * any subclass of DTMDefaultBase to ever change the algorithm. (I don't
    920    * really like doing so, and would love to have an excuse not to...)
    921    *
    922    * %OPT% Performance is critical for this operation.
    923    *
    924    * %REVIEW% Should this be exposed at the package/public layers?
    925    *
    926    * @param nodeHandle (external representation of node)
    927    * @return nodeIdentity Internal offset to this node's records.
    928    * */
    929   final public int makeNodeIdentity(int nodeHandle)
    930   {
    931     if(NULL==nodeHandle) return NULL;
    932 
    933     if(m_mgrDefault!=null)
    934     {
    935       // Optimization: use the DTMManagerDefault's fast DTMID-to-offsets
    936       // table.  I'm not wild about this solution but this operation
    937       // needs need extreme speed.
    938 
    939       int whichDTMindex=nodeHandle>>>DTMManager.IDENT_DTM_NODE_BITS;
    940 
    941       // %REVIEW% Wish I didn't have to perform the pre-test, but
    942       // someone is apparently asking DTMs whether they contain nodes
    943       // which really don't belong to them. That's probably a bug
    944       // which should be fixed, but until it is:
    945       if(m_mgrDefault.m_dtms[whichDTMindex]!=this)
    946 	return NULL;
    947       else
    948 	return
    949 	  m_mgrDefault.m_dtm_offsets[whichDTMindex]
    950 	  | (nodeHandle & DTMManager.IDENT_NODE_DEFAULT);
    951     }
    952 
    953     int whichDTMid=m_dtmIdent.indexOf(nodeHandle & DTMManager.IDENT_DTM_DEFAULT);
    954     return (whichDTMid==NULL)
    955       ? NULL
    956       : (whichDTMid << DTMManager.IDENT_DTM_NODE_BITS)
    957       + (nodeHandle & DTMManager.IDENT_NODE_DEFAULT);
    958   }
    959 
    960 
    961   /**
    962    * Given a node handle, get the handle of the node's first child.
    963    * If not yet resolved, waits for more nodes to be added to the document and
    964    * tries again.
    965    *
    966    * @param nodeHandle int Handle of the node.
    967    * @return int DTM node-number of first child, or DTM.NULL to indicate none exists.
    968    */
    969   public int getFirstChild(int nodeHandle)
    970   {
    971 
    972     int identity = makeNodeIdentity(nodeHandle);
    973     int firstChild = _firstch(identity);
    974 
    975     return makeNodeHandle(firstChild);
    976   }
    977 
    978   /**
    979    * Given a node handle, get the handle of the node's first child.
    980    * If not yet resolved, waits for more nodes to be added to the document and
    981    * tries again.
    982    *
    983    * @param nodeHandle int Handle of the node.
    984    * @return int DTM node-number of first child, or DTM.NULL to indicate none exists.
    985    */
    986   public int getTypedFirstChild(int nodeHandle, int nodeType)
    987   {
    988 
    989     int firstChild, eType;
    990     if (nodeType < DTM.NTYPES) {
    991       for (firstChild = _firstch(makeNodeIdentity(nodeHandle));
    992            firstChild != DTM.NULL;
    993            firstChild = _nextsib(firstChild)) {
    994         eType = _exptype(firstChild);
    995         if (eType == nodeType
    996                || (eType >= DTM.NTYPES
    997                       && m_expandedNameTable.getType(eType) == nodeType)) {
    998           return makeNodeHandle(firstChild);
    999         }
   1000       }
   1001     } else {
   1002       for (firstChild = _firstch(makeNodeIdentity(nodeHandle));
   1003            firstChild != DTM.NULL;
   1004            firstChild = _nextsib(firstChild)) {
   1005         if (_exptype(firstChild) == nodeType) {
   1006           return makeNodeHandle(firstChild);
   1007         }
   1008       }
   1009     }
   1010     return DTM.NULL;
   1011   }
   1012 
   1013   /**
   1014    * Given a node handle, advance to its last child.
   1015    * If not yet resolved, waits for more nodes to be added to the document and
   1016    * tries again.
   1017    *
   1018    * @param nodeHandle int Handle of the node.
   1019    * @return int Node-number of last child,
   1020    * or DTM.NULL to indicate none exists.
   1021    */
   1022   public int getLastChild(int nodeHandle)
   1023   {
   1024 
   1025     int identity = makeNodeIdentity(nodeHandle);
   1026     int child = _firstch(identity);
   1027     int lastChild = DTM.NULL;
   1028 
   1029     while (child != DTM.NULL)
   1030     {
   1031       lastChild = child;
   1032       child = _nextsib(child);
   1033     }
   1034 
   1035     return makeNodeHandle(lastChild);
   1036   }
   1037 
   1038   /**
   1039    * Retrieves an attribute node by by qualified name and namespace URI.
   1040    *
   1041    * @param nodeHandle int Handle of the node upon which to look up this attribute..
   1042    * @param namespaceURI The namespace URI of the attribute to
   1043    *   retrieve, or null.
   1044    * @param name The local name of the attribute to
   1045    *   retrieve.
   1046    * @return The attribute node handle with the specified name (
   1047    *   <code>nodeName</code>) or <code>DTM.NULL</code> if there is no such
   1048    *   attribute.
   1049    */
   1050   public abstract int getAttributeNode(int nodeHandle, String namespaceURI,
   1051                                        String name);
   1052 
   1053   /**
   1054    * Given a node handle, get the index of the node's first attribute.
   1055    *
   1056    * @param nodeHandle int Handle of the node.
   1057    * @return Handle of first attribute, or DTM.NULL to indicate none exists.
   1058    */
   1059   public int getFirstAttribute(int nodeHandle)
   1060   {
   1061     int nodeID = makeNodeIdentity(nodeHandle);
   1062 
   1063     return makeNodeHandle(getFirstAttributeIdentity(nodeID));
   1064   }
   1065 
   1066   /**
   1067    * Given a node identity, get the index of the node's first attribute.
   1068    *
   1069    * @param identity int identity of the node.
   1070    * @return Identity of first attribute, or DTM.NULL to indicate none exists.
   1071    */
   1072   protected int getFirstAttributeIdentity(int identity) {
   1073     int type = _type(identity);
   1074 
   1075     if (DTM.ELEMENT_NODE == type)
   1076     {
   1077       // Assume that attributes and namespaces immediately follow the element.
   1078       while (DTM.NULL != (identity = getNextNodeIdentity(identity)))
   1079       {
   1080 
   1081         // Assume this can not be null.
   1082         type = _type(identity);
   1083 
   1084         if (type == DTM.ATTRIBUTE_NODE)
   1085         {
   1086           return identity;
   1087         }
   1088         else if (DTM.NAMESPACE_NODE != type)
   1089         {
   1090           break;
   1091         }
   1092       }
   1093     }
   1094 
   1095     return DTM.NULL;
   1096   }
   1097 
   1098   /**
   1099    * Given a node handle and an expanded type ID, get the index of the node's
   1100    * attribute of that type, if any.
   1101    *
   1102    * @param nodeHandle int Handle of the node.
   1103    * @param attType int expanded type ID of the required attribute.
   1104    * @return Handle of attribute of the required type, or DTM.NULL to indicate
   1105    * none exists.
   1106    */
   1107   protected int getTypedAttribute(int nodeHandle, int attType) {
   1108     int type = getNodeType(nodeHandle);
   1109     if (DTM.ELEMENT_NODE == type) {
   1110       int identity = makeNodeIdentity(nodeHandle);
   1111 
   1112       while (DTM.NULL != (identity = getNextNodeIdentity(identity)))
   1113       {
   1114         type = _type(identity);
   1115 
   1116         if (type == DTM.ATTRIBUTE_NODE)
   1117         {
   1118           if (_exptype(identity) == attType) return makeNodeHandle(identity);
   1119         }
   1120         else if (DTM.NAMESPACE_NODE != type)
   1121         {
   1122           break;
   1123         }
   1124       }
   1125     }
   1126 
   1127     return DTM.NULL;
   1128   }
   1129 
   1130   /**
   1131    * Given a node handle, advance to its next sibling.
   1132    * If not yet resolved, waits for more nodes to be added to the document and
   1133    * tries again.
   1134    * @param nodeHandle int Handle of the node.
   1135    * @return int Node-number of next sibling,
   1136    * or DTM.NULL to indicate none exists.
   1137    */
   1138   public int getNextSibling(int nodeHandle)
   1139   {
   1140   	if (nodeHandle == DTM.NULL)
   1141   	return DTM.NULL;
   1142     return makeNodeHandle(_nextsib(makeNodeIdentity(nodeHandle)));
   1143   }
   1144 
   1145   /**
   1146    * Given a node handle, advance to its next sibling.
   1147    * If not yet resolved, waits for more nodes to be added to the document and
   1148    * tries again.
   1149    * @param nodeHandle int Handle of the node.
   1150    * @return int Node-number of next sibling,
   1151    * or DTM.NULL to indicate none exists.
   1152    */
   1153   public int getTypedNextSibling(int nodeHandle, int nodeType)
   1154   {
   1155   	if (nodeHandle == DTM.NULL)
   1156   	return DTM.NULL;
   1157   	int node = makeNodeIdentity(nodeHandle);
   1158   	int eType;
   1159   	while ((node = _nextsib(node)) != DTM.NULL &&
   1160   	((eType = _exptype(node)) != nodeType &&
   1161   	m_expandedNameTable.getType(eType)!= nodeType));
   1162   	//_type(node) != nodeType));
   1163 
   1164     return (node == DTM.NULL ? DTM.NULL : makeNodeHandle(node));
   1165   }
   1166 
   1167   /**
   1168    * Given a node handle, find its preceeding sibling.
   1169    * WARNING: DTM is asymmetric; this operation is resolved by search, and is
   1170    * relatively expensive.
   1171    *
   1172    * @param nodeHandle the id of the node.
   1173    * @return int Node-number of the previous sib,
   1174    * or DTM.NULL to indicate none exists.
   1175    */
   1176   public int getPreviousSibling(int nodeHandle)
   1177   {
   1178     if (nodeHandle == DTM.NULL)
   1179       return DTM.NULL;
   1180 
   1181     if (m_prevsib != null)
   1182       return makeNodeHandle(_prevsib(makeNodeIdentity(nodeHandle)));
   1183     else
   1184     {
   1185       // If the previous sibling array is not built, we get at
   1186       // the previous sibling using the parent, firstch and
   1187       // nextsib arrays.
   1188       int nodeID = makeNodeIdentity(nodeHandle);
   1189       int parent = _parent(nodeID);
   1190       int node = _firstch(parent);
   1191       int result = DTM.NULL;
   1192       while (node != nodeID)
   1193       {
   1194         result = node;
   1195         node = _nextsib(node);
   1196       }
   1197       return makeNodeHandle(result);
   1198     }
   1199   }
   1200 
   1201   /**
   1202    * Given a node handle, advance to the next attribute.
   1203    * If an attr, we advance to
   1204    * the next attr on the same node.  If not an attribute, we return NULL.
   1205    *
   1206    * @param nodeHandle int Handle of the node.
   1207    * @return int DTM node-number of the resolved attr,
   1208    * or DTM.NULL to indicate none exists.
   1209    */
   1210   public int getNextAttribute(int nodeHandle) {
   1211     int nodeID = makeNodeIdentity(nodeHandle);
   1212 
   1213     if (_type(nodeID) == DTM.ATTRIBUTE_NODE) {
   1214       return makeNodeHandle(getNextAttributeIdentity(nodeID));
   1215     }
   1216 
   1217     return DTM.NULL;
   1218   }
   1219 
   1220   /**
   1221    * Given a node identity for an attribute, advance to the next attribute.
   1222    *
   1223    * @param identity int identity of the attribute node.  This
   1224    * <strong>must</strong> be an attribute node.
   1225    *
   1226    * @return int DTM node-identity of the resolved attr,
   1227    * or DTM.NULL to indicate none exists.
   1228    *
   1229    */
   1230   protected int getNextAttributeIdentity(int identity) {
   1231     // Assume that attributes and namespace nodes immediately follow the element
   1232     while (DTM.NULL != (identity = getNextNodeIdentity(identity))) {
   1233       int type = _type(identity);
   1234 
   1235       if (type == DTM.ATTRIBUTE_NODE) {
   1236         return identity;
   1237       } else if (type != DTM.NAMESPACE_NODE) {
   1238         break;
   1239       }
   1240     }
   1241 
   1242     return DTM.NULL;
   1243   }
   1244 
   1245   /** Lazily created namespace lists. */
   1246   private Vector m_namespaceLists = null;  // on demand
   1247 
   1248 
   1249   /** Build table of namespace declaration
   1250    * locations during DTM construction. Table is a Vector of
   1251    * SuballocatedIntVectors containing the namespace node HANDLES declared at
   1252    * that ID, plus an SuballocatedIntVector of the element node INDEXES at which
   1253    * these declarations appeared.
   1254    *
   1255    * NOTE: Since this occurs during model build, nodes will be encountered
   1256    * in doucment order and thus the table will be ordered by element,
   1257    * permitting binary-search as a possible retrieval optimization.
   1258    *
   1259    * %REVIEW% Directly managed arrays rather than vectors?
   1260    * %REVIEW% Handles or IDs? Given usage, I think handles.
   1261    * */
   1262   protected void declareNamespaceInContext(int elementNodeIndex,int namespaceNodeIndex)
   1263   {
   1264     SuballocatedIntVector nsList=null;
   1265     if(m_namespaceDeclSets==null)
   1266       {
   1267 
   1268         // First
   1269         m_namespaceDeclSetElements=new SuballocatedIntVector(32);
   1270         m_namespaceDeclSetElements.addElement(elementNodeIndex);
   1271         m_namespaceDeclSets=new Vector();
   1272         nsList=new SuballocatedIntVector(32);
   1273         m_namespaceDeclSets.addElement(nsList);
   1274       }
   1275     else
   1276       {
   1277         // Most recent. May be -1 (none) if DTM was pruned.
   1278         // %OPT% Is there a lastElement() method? Should there be?
   1279         int last=m_namespaceDeclSetElements.size()-1;
   1280 
   1281         if(last>=0 && elementNodeIndex==m_namespaceDeclSetElements.elementAt(last))
   1282           {
   1283             nsList=(SuballocatedIntVector)m_namespaceDeclSets.elementAt(last);
   1284           }
   1285       }
   1286     if(nsList==null)
   1287       {
   1288         m_namespaceDeclSetElements.addElement(elementNodeIndex);
   1289 
   1290         SuballocatedIntVector inherited =
   1291                                 findNamespaceContext(_parent(elementNodeIndex));
   1292 
   1293         if (inherited!=null) {
   1294             // %OPT% Count-down might be faster, but debuggability may
   1295             // be better this way, and if we ever decide we want to
   1296             // keep this ordered by expanded-type...
   1297             int isize=inherited.size();
   1298 
   1299             // Base the size of a new namespace list on the
   1300             // size of the inherited list - but within reason!
   1301             nsList=new SuballocatedIntVector(Math.max(Math.min(isize+16,2048),
   1302                                                       32));
   1303 
   1304             for(int i=0;i<isize;++i)
   1305               {
   1306                 nsList.addElement(inherited.elementAt(i));
   1307               }
   1308         } else {
   1309             nsList=new SuballocatedIntVector(32);
   1310         }
   1311 
   1312         m_namespaceDeclSets.addElement(nsList);
   1313       }
   1314 
   1315     // Handle overwriting inherited.
   1316     // %OPT% Keep sorted? (By expanded-name rather than by doc order...)
   1317     // Downside: Would require insertElementAt if not found,
   1318     // which has recopying costs. But these are generally short lists...
   1319     int newEType=_exptype(namespaceNodeIndex);
   1320 
   1321     for(int i=nsList.size()-1;i>=0;--i)
   1322       {
   1323         if(newEType==getExpandedTypeID(nsList.elementAt(i)))
   1324           {
   1325             nsList.setElementAt(makeNodeHandle(namespaceNodeIndex),i);
   1326             return;
   1327           }
   1328       }
   1329     nsList.addElement(makeNodeHandle(namespaceNodeIndex));
   1330   }
   1331 
   1332   /** Retrieve list of namespace declaration locations
   1333      * active at this node. List is an SuballocatedIntVector whose
   1334      * entries are the namespace node HANDLES declared at that ID.
   1335      *
   1336      * %REVIEW% Directly managed arrays rather than vectors?
   1337      * %REVIEW% Handles or IDs? Given usage, I think handles.
   1338      * */
   1339   protected SuballocatedIntVector findNamespaceContext(int elementNodeIndex)
   1340   {
   1341     if (null!=m_namespaceDeclSetElements)
   1342       {
   1343         // %OPT% Is binary-search really saving us a lot versus linear?
   1344         // (... It may be, in large docs with many NS decls.)
   1345         int wouldBeAt=findInSortedSuballocatedIntVector(m_namespaceDeclSetElements,
   1346                                             elementNodeIndex);
   1347         if(wouldBeAt>=0) // Found it
   1348           return (SuballocatedIntVector) m_namespaceDeclSets.elementAt(wouldBeAt);
   1349         if(wouldBeAt == -1) // -1-wouldbeat == 0
   1350           return null; // Not after anything; definitely not found
   1351 
   1352         // Not found, but we know where it should have been.
   1353         // Search back until we find an ancestor or run out.
   1354         wouldBeAt=-1-wouldBeAt;
   1355 
   1356         // Decrement wouldBeAt to find last possible ancestor
   1357         int candidate=m_namespaceDeclSetElements.elementAt(-- wouldBeAt);
   1358         int ancestor=_parent(elementNodeIndex);
   1359 
   1360         // Special case: if the candidate is before the given node, and
   1361         // is in the earliest possible position in the document, it
   1362         // must have the namespace declarations we're interested in.
   1363         if (wouldBeAt == 0 && candidate < ancestor) {
   1364           int rootHandle = getDocumentRoot(makeNodeHandle(elementNodeIndex));
   1365           int rootID = makeNodeIdentity(rootHandle);
   1366           int uppermostNSCandidateID;
   1367 
   1368           if (getNodeType(rootHandle) == DTM.DOCUMENT_NODE) {
   1369             int ch = _firstch(rootID);
   1370             uppermostNSCandidateID = (ch != DTM.NULL) ? ch : rootID;
   1371           } else {
   1372             uppermostNSCandidateID = rootID;
   1373           }
   1374 
   1375           if (candidate == uppermostNSCandidateID) {
   1376             return (SuballocatedIntVector)m_namespaceDeclSets.elementAt(wouldBeAt);
   1377           }
   1378         }
   1379 
   1380         while(wouldBeAt>=0 && ancestor>0)
   1381           {
   1382             if (candidate==ancestor) {
   1383                 // Found ancestor in list
   1384                 return (SuballocatedIntVector)m_namespaceDeclSets.elementAt(wouldBeAt);
   1385             } else if (candidate<ancestor) {
   1386                 // Too deep in tree
   1387                 do {
   1388                   ancestor=_parent(ancestor);
   1389                 } while (candidate < ancestor);
   1390             } else if(wouldBeAt > 0){
   1391               // Too late in list
   1392               candidate=m_namespaceDeclSetElements.elementAt(--wouldBeAt);
   1393             }
   1394             else
   1395             	break;
   1396           }
   1397       }
   1398 
   1399     return null; // No namespaces known at this node
   1400   }
   1401 
   1402   /**
   1403      * Subroutine: Locate the specified node within
   1404      * m_namespaceDeclSetElements, or the last element which
   1405      * preceeds it in document order
   1406      *
   1407      * %REVIEW% Inlne this into findNamespaceContext? Create SortedSuballocatedIntVector type?
   1408      *
   1409      * @return If positive or zero, the index of the found item.
   1410      * If negative, index of the point at which it would have appeared,
   1411      * encoded as -1-index and hence reconvertable by subtracting
   1412      * it from -1. (Encoding because I don't want to recompare the strings
   1413      * but don't want to burn bytes on a datatype to hold a flagged value.)
   1414      */
   1415   protected int findInSortedSuballocatedIntVector(SuballocatedIntVector vector, int lookfor)
   1416   {
   1417     // Binary search
   1418     int i = 0;
   1419     if(vector != null) {
   1420       int first = 0;
   1421       int last  = vector.size() - 1;
   1422 
   1423       while (first <= last) {
   1424         i = (first + last) / 2;
   1425         int test = lookfor-vector.elementAt(i);
   1426         if(test == 0) {
   1427           return i; // Name found
   1428         }
   1429         else if (test < 0) {
   1430           last = i - 1; // looked too late
   1431         }
   1432         else {
   1433           first = i + 1; // looked ot early
   1434         }
   1435       }
   1436 
   1437       if (first > i) {
   1438         i = first; // Clean up at loop end
   1439       }
   1440     }
   1441 
   1442     return -1 - i; // not-found has to be encoded.
   1443   }
   1444 
   1445 
   1446   /**
   1447    * Given a node handle, get the index of the node's first child.
   1448    * If not yet resolved, waits for more nodes to be added to the document and
   1449    * tries again
   1450    *
   1451    * @param nodeHandle handle to node, which should probably be an element
   1452    *                   node, but need not be.
   1453    *
   1454    * @param inScope    true if all namespaces in scope should be returned,
   1455    *                   false if only the namespace declarations should be
   1456    *                   returned.
   1457    * @return handle of first namespace, or DTM.NULL to indicate none exists.
   1458    */
   1459   public int getFirstNamespaceNode(int nodeHandle, boolean inScope)
   1460   {
   1461         if(inScope)
   1462         {
   1463             int identity = makeNodeIdentity(nodeHandle);
   1464             if (_type(identity) == DTM.ELEMENT_NODE)
   1465             {
   1466               SuballocatedIntVector nsContext=findNamespaceContext(identity);
   1467               if(nsContext==null || nsContext.size()<1)
   1468                 return NULL;
   1469 
   1470               return nsContext.elementAt(0);
   1471             }
   1472             else
   1473               return NULL;
   1474           }
   1475         else
   1476           {
   1477             // Assume that attributes and namespaces immediately
   1478             // follow the element.
   1479             //
   1480             // %OPT% Would things be faster if all NS nodes were built
   1481             // before all Attr nodes? Some costs at build time for 2nd
   1482             // pass...
   1483             int identity = makeNodeIdentity(nodeHandle);
   1484             if (_type(identity) == DTM.ELEMENT_NODE)
   1485             {
   1486               while (DTM.NULL != (identity = getNextNodeIdentity(identity)))
   1487               {
   1488                 int type = _type(identity);
   1489                 if (type == DTM.NAMESPACE_NODE)
   1490                     return makeNodeHandle(identity);
   1491                 else if (DTM.ATTRIBUTE_NODE != type)
   1492                     break;
   1493               }
   1494               return NULL;
   1495             }
   1496             else
   1497               return NULL;
   1498           }
   1499   }
   1500 
   1501   /**
   1502    * Given a namespace handle, advance to the next namespace.
   1503    *
   1504    * @param baseHandle handle to original node from where the first namespace
   1505    * was relative to (needed to return nodes in document order).
   1506    * @param nodeHandle A namespace handle for which we will find the next node.
   1507    * @param inScope true if all namespaces that are in scope should be processed,
   1508    * otherwise just process the nodes in the given element handle.
   1509    * @return handle of next namespace, or DTM.NULL to indicate none exists.
   1510    */
   1511   public int getNextNamespaceNode(int baseHandle, int nodeHandle,
   1512                                   boolean inScope)
   1513   {
   1514         if(inScope)
   1515           {
   1516             //Since we've been given the base, try direct lookup
   1517             //(could look from nodeHandle but this is at least one
   1518             //comparison/get-parent faster)
   1519             //SuballocatedIntVector nsContext=findNamespaceContext(nodeHandle & m_mask);
   1520 
   1521                 SuballocatedIntVector nsContext=findNamespaceContext(makeNodeIdentity(baseHandle));
   1522 
   1523             if(nsContext==null)
   1524               return NULL;
   1525             int i=1 + nsContext.indexOf(nodeHandle);
   1526             if(i<=0 || i==nsContext.size())
   1527               return NULL;
   1528 
   1529             return nsContext.elementAt(i);
   1530           }
   1531         else
   1532           {
   1533             // Assume that attributes and namespace nodes immediately follow the element.
   1534             int identity = makeNodeIdentity(nodeHandle);
   1535             while (DTM.NULL != (identity = getNextNodeIdentity(identity)))
   1536               {
   1537                 int type = _type(identity);
   1538                 if (type == DTM.NAMESPACE_NODE)
   1539                   {
   1540                     return makeNodeHandle(identity);
   1541                   }
   1542                 else if (type != DTM.ATTRIBUTE_NODE)
   1543                   {
   1544                     break;
   1545                   }
   1546               }
   1547           }
   1548      return DTM.NULL;
   1549   }
   1550 
   1551   /**
   1552    * Given a node handle, find its parent node.
   1553    *
   1554    * @param nodeHandle the id of the node.
   1555    * @return int Node-number of parent,
   1556    * or DTM.NULL to indicate none exists.
   1557    */
   1558   public int getParent(int nodeHandle)
   1559   {
   1560 
   1561     int identity = makeNodeIdentity(nodeHandle);
   1562 
   1563     if (identity > 0)
   1564       return makeNodeHandle(_parent(identity));
   1565     else
   1566       return DTM.NULL;
   1567   }
   1568 
   1569   /**
   1570    * Find the Document node handle for the document currently under construction.
   1571    * PLEASE NOTE that most people should use getOwnerDocument(nodeHandle) instead;
   1572    * this version of the operation is primarily intended for use during negotiation
   1573    * with the DTM Manager.
   1574    *
   1575    *  @return int Node handle of document, which should always be valid.
   1576    */
   1577   public int getDocument()
   1578   {
   1579     return m_dtmIdent.elementAt(0); // makeNodeHandle(0)
   1580   }
   1581 
   1582   /**
   1583    * Given a node handle, find the owning document node.  This has the exact
   1584    * same semantics as the DOM Document method of the same name, in that if
   1585    * the nodeHandle is a document node, it will return NULL.
   1586    *
   1587    * <p>%REVIEW% Since this is DOM-specific, it may belong at the DOM
   1588    * binding layer. Included here as a convenience function and to
   1589    * aid porting of DOM code to DTM.</p>
   1590    *
   1591    * @param nodeHandle the id of the node.
   1592    * @return int Node handle of owning document, or -1 if the node was a Docment
   1593    */
   1594   public int getOwnerDocument(int nodeHandle)
   1595   {
   1596 
   1597     if (DTM.DOCUMENT_NODE == getNodeType(nodeHandle))
   1598   	    return DTM.NULL;
   1599 
   1600     return getDocumentRoot(nodeHandle);
   1601   }
   1602 
   1603   /**
   1604    * Given a node handle, find the owning document node.  Unlike the DOM,
   1605    * this considers the owningDocument of a Document to be itself.
   1606    *
   1607    * @param nodeHandle the id of the node.
   1608    * @return int Node handle of owning document, or the nodeHandle if it is
   1609    *             a Document.
   1610    */
   1611   public int getDocumentRoot(int nodeHandle)
   1612   {
   1613     return getManager().getDTM(nodeHandle).getDocument();
   1614   }
   1615 
   1616   /**
   1617    * Get the string-value of a node as a String object
   1618    * (see http://www.w3.org/TR/xpath#data-model
   1619    * for the definition of a node's string-value).
   1620    *
   1621    * @param nodeHandle The node ID.
   1622    *
   1623    * @return A string object that represents the string-value of the given node.
   1624    */
   1625   public abstract XMLString getStringValue(int nodeHandle);
   1626 
   1627   /**
   1628    * Get number of character array chunks in
   1629    * the string-value of a node.
   1630    * (see http://www.w3.org/TR/xpath#data-model
   1631    * for the definition of a node's string-value).
   1632    * Note that a single text node may have multiple text chunks.
   1633    *
   1634    * @param nodeHandle The node ID.
   1635    *
   1636    * @return number of character array chunks in
   1637    *         the string-value of a node.
   1638    */
   1639   public int getStringValueChunkCount(int nodeHandle)
   1640   {
   1641 
   1642     // %TBD%
   1643     error(XMLMessages.createXMLMessage(XMLErrorResources.ER_METHOD_NOT_SUPPORTED, null));//("getStringValueChunkCount not yet supported!");
   1644 
   1645     return 0;
   1646   }
   1647 
   1648   /**
   1649    * Get a character array chunk in the string-value of a node.
   1650    * (see http://www.w3.org/TR/xpath#data-model
   1651    * for the definition of a node's string-value).
   1652    * Note that a single text node may have multiple text chunks.
   1653    *
   1654    * @param nodeHandle The node ID.
   1655    * @param chunkIndex Which chunk to get.
   1656    * @param startAndLen An array of 2 where the start position and length of
   1657    *                    the chunk will be returned.
   1658    *
   1659    * @return The character array reference where the chunk occurs.
   1660    */
   1661   public char[] getStringValueChunk(int nodeHandle, int chunkIndex,
   1662                                     int[] startAndLen)
   1663   {
   1664 
   1665     // %TBD%
   1666     error(XMLMessages.createXMLMessage(XMLErrorResources.ER_METHOD_NOT_SUPPORTED, null));//"getStringValueChunk not yet supported!");
   1667 
   1668     return null;
   1669   }
   1670 
   1671   /**
   1672    * Given a node handle, return an ID that represents the node's expanded name.
   1673    *
   1674    * @param nodeHandle The handle to the node in question.
   1675    *
   1676    * @return the expanded-name id of the node.
   1677    */
   1678   public int getExpandedTypeID(int nodeHandle)
   1679   {
   1680     // %REVIEW% This _should_ only be null if someone asked the wrong DTM about the node...
   1681     // which one would hope would never happen...
   1682     int id=makeNodeIdentity(nodeHandle);
   1683     if(id==NULL)
   1684       return NULL;
   1685     return _exptype(id);
   1686   }
   1687 
   1688   /**
   1689    * Given an expanded name, return an ID.  If the expanded-name does not
   1690    * exist in the internal tables, the entry will be created, and the ID will
   1691    * be returned.  Any additional nodes that are created that have this
   1692    * expanded name will use this ID.
   1693    *
   1694    * @param type The simple type, i.e. one of ELEMENT, ATTRIBUTE, etc.
   1695    *
   1696    * @param namespace The namespace URI, which may be null, may be an empty
   1697    *                  string (which will be the same as null), or may be a
   1698    *                  namespace URI.
   1699    * @param localName The local name string, which must be a valid
   1700    *                  <a href="http://www.w3.org/TR/REC-xml-names/">NCName</a>.
   1701    *
   1702    * @return the expanded-name id of the node.
   1703    */
   1704   public int getExpandedTypeID(String namespace, String localName, int type)
   1705   {
   1706 
   1707     ExpandedNameTable ent = m_expandedNameTable;
   1708 
   1709     return ent.getExpandedTypeID(namespace, localName, type);
   1710   }
   1711 
   1712   /**
   1713    * Given an expanded-name ID, return the local name part.
   1714    *
   1715    * @param expandedNameID an ID that represents an expanded-name.
   1716    * @return String Local name of this node.
   1717    */
   1718   public String getLocalNameFromExpandedNameID(int expandedNameID)
   1719   {
   1720     return m_expandedNameTable.getLocalName(expandedNameID);
   1721   }
   1722 
   1723   /**
   1724    * Given an expanded-name ID, return the namespace URI part.
   1725    *
   1726    * @param expandedNameID an ID that represents an expanded-name.
   1727    * @return String URI value of this node's namespace, or null if no
   1728    * namespace was resolved.
   1729    */
   1730   public String getNamespaceFromExpandedNameID(int expandedNameID)
   1731   {
   1732     return m_expandedNameTable.getNamespace(expandedNameID);
   1733   }
   1734 
   1735   /**
   1736    * Returns the namespace type of a specific node
   1737    * @param nodeHandle the id of the node.
   1738    * @return the ID of the namespace.
   1739    */
   1740   public int getNamespaceType(final int nodeHandle)
   1741   {
   1742 
   1743     int identity = makeNodeIdentity(nodeHandle);
   1744     int expandedNameID = _exptype(identity);
   1745 
   1746     return m_expandedNameTable.getNamespaceID(expandedNameID);
   1747   }
   1748 
   1749   /**
   1750    * Given a node handle, return its DOM-style node name. This will
   1751    * include names such as #text or #document.
   1752    *
   1753    * @param nodeHandle the id of the node.
   1754    * @return String Name of this node, which may be an empty string.
   1755    * %REVIEW% Document when empty string is possible...
   1756    * %REVIEW-COMMENT% It should never be empty, should it?
   1757    */
   1758   public abstract String getNodeName(int nodeHandle);
   1759 
   1760   /**
   1761    * Given a node handle, return the XPath node name.  This should be
   1762    * the name as described by the XPath data model, NOT the DOM-style
   1763    * name.
   1764    *
   1765    * @param nodeHandle the id of the node.
   1766    * @return String Name of this node, which may be an empty string.
   1767    */
   1768   public String getNodeNameX(int nodeHandle)
   1769   {
   1770 
   1771     /** @todo: implement this org.apache.xml.dtm.DTMDefaultBase abstract method */
   1772     error(XMLMessages.createXMLMessage(XMLErrorResources.ER_METHOD_NOT_SUPPORTED, null));//"Not yet supported!");
   1773 
   1774     return null;
   1775   }
   1776 
   1777   /**
   1778    * Given a node handle, return its XPath-style localname.
   1779    * (As defined in Namespaces, this is the portion of the name after any
   1780    * colon character).
   1781    *
   1782    * @param nodeHandle the id of the node.
   1783    * @return String Local name of this node.
   1784    */
   1785   public abstract String getLocalName(int nodeHandle);
   1786 
   1787   /**
   1788    * Given a namespace handle, return the prefix that the namespace decl is
   1789    * mapping.
   1790    * Given a node handle, return the prefix used to map to the namespace.
   1791    *
   1792    * <p> %REVIEW% Are you sure you want "" for no prefix?  </p>
   1793    * <p> %REVIEW-COMMENT% I think so... not totally sure. -sb  </p>
   1794    *
   1795    * @param nodeHandle the id of the node.
   1796    * @return String prefix of this node's name, or "" if no explicit
   1797    * namespace prefix was given.
   1798    */
   1799   public abstract String getPrefix(int nodeHandle);
   1800 
   1801   /**
   1802    * Given a node handle, return its DOM-style namespace URI
   1803    * (As defined in Namespaces, this is the declared URI which this node's
   1804    * prefix -- or default in lieu thereof -- was mapped to.)
   1805    *
   1806    * <p>%REVIEW% Null or ""? -sb</p>
   1807    *
   1808    * @param nodeHandle the id of the node.
   1809    * @return String URI value of this node's namespace, or null if no
   1810    * namespace was resolved.
   1811    */
   1812   public abstract String getNamespaceURI(int nodeHandle);
   1813 
   1814   /**
   1815    * Given a node handle, return its node value. This is mostly
   1816    * as defined by the DOM, but may ignore some conveniences.
   1817    * <p>
   1818    *
   1819    * @param nodeHandle The node id.
   1820    * @return String Value of this node, or null if not
   1821    * meaningful for this node type.
   1822    */
   1823   public abstract String getNodeValue(int nodeHandle);
   1824 
   1825   /**
   1826    * Given a node handle, return its DOM-style node type.
   1827    * <p>
   1828    * %REVIEW% Generally, returning short is false economy. Return int?
   1829    * %REVIEW% Make assumption that node has already arrived.  Is OK?
   1830    *
   1831    * @param nodeHandle The node id.
   1832    * @return int Node type, as per the DOM's Node._NODE constants.
   1833    */
   1834   public short getNodeType(int nodeHandle)
   1835   {
   1836   	if (nodeHandle == DTM.NULL)
   1837   	return DTM.NULL;
   1838     return m_expandedNameTable.getType(_exptype(makeNodeIdentity(nodeHandle)));
   1839   }
   1840 
   1841   /**
   1842    * Get the depth level of this node in the tree (equals 1 for
   1843    * a parentless node).
   1844    *
   1845    * @param nodeHandle The node id.
   1846    * @return the number of ancestors, plus one
   1847    * @xsl.usage internal
   1848    */
   1849   public short getLevel(int nodeHandle)
   1850   {
   1851     // Apparently, the axis walker stuff requires levels to count from 1.
   1852     int identity = makeNodeIdentity(nodeHandle);
   1853     return (short) (_level(identity) + 1);
   1854   }
   1855 
   1856   /**
   1857    * Get the identity of this node in the tree
   1858    *
   1859    * @param nodeHandle The node handle.
   1860    * @return the node identity
   1861    * @xsl.usage internal
   1862    */
   1863   public int getNodeIdent(int nodeHandle)
   1864   {
   1865     /*if (nodeHandle != DTM.NULL)
   1866       return nodeHandle & m_mask;
   1867     else
   1868       return DTM.NULL;*/
   1869 
   1870       return makeNodeIdentity(nodeHandle);
   1871   }
   1872 
   1873   /**
   1874    * Get the handle of this node in the tree
   1875    *
   1876    * @param nodeId The node identity.
   1877    * @return the node handle
   1878    * @xsl.usage internal
   1879    */
   1880   public int getNodeHandle(int nodeId)
   1881   {
   1882     /*if (nodeId != DTM.NULL)
   1883       return nodeId | m_dtmIdent;
   1884     else
   1885       return DTM.NULL;*/
   1886 
   1887       return makeNodeHandle(nodeId);
   1888   }
   1889 
   1890   // ============== Document query functions ==============
   1891 
   1892   /**
   1893    * Tests whether DTM DOM implementation implements a specific feature and
   1894    * that feature is supported by this node.
   1895    *
   1896    * @param feature The name of the feature to test.
   1897    * @param version This is the version number of the feature to test.
   1898    *   If the version is not
   1899    *   specified, supporting any version of the feature will cause the
   1900    *   method to return <code>true</code>.
   1901    * @return Returns <code>true</code> if the specified feature is
   1902    *   supported on this node, <code>false</code> otherwise.
   1903    */
   1904   public boolean isSupported(String feature, String version)
   1905   {
   1906 
   1907     // %TBD%
   1908     return false;
   1909   }
   1910 
   1911   /**
   1912    * Return the base URI of the document entity. If it is not known
   1913    * (because the document was parsed from a socket connection or from
   1914    * standard input, for example), the value of this property is unknown.
   1915    *
   1916    * @return the document base URI String object or null if unknown.
   1917    */
   1918   public String getDocumentBaseURI()
   1919   {
   1920     return m_documentBaseURI;
   1921   }
   1922 
   1923   /**
   1924    * Set the base URI of the document entity.
   1925    *
   1926    * @param baseURI the document base URI String object or null if unknown.
   1927    */
   1928   public void setDocumentBaseURI(String baseURI)
   1929   {
   1930     m_documentBaseURI = baseURI;
   1931   }
   1932 
   1933   /**
   1934    * Return the system identifier of the document entity. If
   1935    * it is not known, the value of this property is unknown.
   1936    *
   1937    * @param nodeHandle The node id, which can be any valid node handle.
   1938    * @return the system identifier String object or null if unknown.
   1939    */
   1940   public String getDocumentSystemIdentifier(int nodeHandle)
   1941   {
   1942 
   1943     // %REVIEW%  OK? -sb
   1944     return m_documentBaseURI;
   1945   }
   1946 
   1947   /**
   1948    * Return the name of the character encoding scheme
   1949    *        in which the document entity is expressed.
   1950    *
   1951    * @param nodeHandle The node id, which can be any valid node handle.
   1952    * @return the document encoding String object.
   1953    * @xsl.usage internal
   1954    */
   1955   public String getDocumentEncoding(int nodeHandle)
   1956   {
   1957 
   1958     // %REVIEW%  OK??  -sb
   1959     return "UTF-8";
   1960   }
   1961 
   1962   /**
   1963    * Return an indication of the standalone status of the document,
   1964    *        either "yes" or "no". This property is derived from the optional
   1965    *        standalone document declaration in the XML declaration at the
   1966    *        beginning of the document entity, and has no value if there is no
   1967    *        standalone document declaration.
   1968    *
   1969    * @param nodeHandle The node id, which can be any valid node handle.
   1970    * @return the document standalone String object, either "yes", "no", or null.
   1971    */
   1972   public String getDocumentStandalone(int nodeHandle)
   1973   {
   1974     return null;
   1975   }
   1976 
   1977   /**
   1978    * Return a string representing the XML version of the document. This
   1979    * property is derived from the XML declaration optionally present at the
   1980    * beginning of the document entity, and has no value if there is no XML
   1981    * declaration.
   1982    *
   1983    * @param documentHandle The document handle
   1984    *
   1985    * @return the document version String object.
   1986    */
   1987   public String getDocumentVersion(int documentHandle)
   1988   {
   1989     return null;
   1990   }
   1991 
   1992   /**
   1993    * Return an indication of
   1994    * whether the processor has read the complete DTD. Its value is a
   1995    * boolean. If it is false, then certain properties (indicated in their
   1996    * descriptions below) may be unknown. If it is true, those properties
   1997    * are never unknown.
   1998    *
   1999    * @return <code>true</code> if all declarations were processed;
   2000    *         <code>false</code> otherwise.
   2001    */
   2002   public boolean getDocumentAllDeclarationsProcessed()
   2003   {
   2004 
   2005     // %REVIEW% OK?
   2006     return true;
   2007   }
   2008 
   2009   /**
   2010    *   A document type declaration information item has the following properties:
   2011    *
   2012    *     1. [system identifier] The system identifier of the external subset, if
   2013    *        it exists. Otherwise this property has no value.
   2014    *
   2015    * @return the system identifier String object, or null if there is none.
   2016    */
   2017   public abstract String getDocumentTypeDeclarationSystemIdentifier();
   2018 
   2019   /**
   2020    * Return the public identifier of the external subset,
   2021    * normalized as described in 4.2.2 External Entities [XML]. If there is
   2022    * no external subset or if it has no public identifier, this property
   2023    * has no value.
   2024    *
   2025    * @return the public identifier String object, or null if there is none.
   2026    */
   2027   public abstract String getDocumentTypeDeclarationPublicIdentifier();
   2028 
   2029   /**
   2030    * Returns the <code>Element</code> whose <code>ID</code> is given by
   2031    * <code>elementId</code>. If no such element exists, returns
   2032    * <code>DTM.NULL</code>. Behavior is not defined if more than one element
   2033    * has this <code>ID</code>. Attributes (including those
   2034    * with the name "ID") are not of type ID unless so defined by DTD/Schema
   2035    * information available to the DTM implementation.
   2036    * Implementations that do not know whether attributes are of type ID or
   2037    * not are expected to return <code>DTM.NULL</code>.
   2038    *
   2039    * <p>%REVIEW% Presumably IDs are still scoped to a single document,
   2040    * and this operation searches only within a single document, right?
   2041    * Wouldn't want collisions between DTMs in the same process.</p>
   2042    *
   2043    * @param elementId The unique <code>id</code> value for an element.
   2044    * @return The handle of the matching element.
   2045    */
   2046   public abstract int getElementById(String elementId);
   2047 
   2048   /**
   2049    * The getUnparsedEntityURI function returns the URI of the unparsed
   2050    * entity with the specified name in the same document as the context
   2051    * node (see [3.3 Unparsed Entities]). It returns the empty string if
   2052    * there is no such entity.
   2053    * <p>
   2054    * XML processors may choose to use the System Identifier (if one
   2055    * is provided) to resolve the entity, rather than the URI in the
   2056    * Public Identifier. The details are dependent on the processor, and
   2057    * we would have to support some form of plug-in resolver to handle
   2058    * this properly. Currently, we simply return the System Identifier if
   2059    * present, and hope that it a usable URI or that our caller can
   2060    * map it to one.
   2061    * TODO: Resolve Public Identifiers... or consider changing function name.
   2062    * <p>
   2063    * If we find a relative URI
   2064    * reference, XML expects it to be resolved in terms of the base URI
   2065    * of the document. The DOM doesn't do that for us, and it isn't
   2066    * entirely clear whether that should be done here; currently that's
   2067    * pushed up to a higher level of our application. (Note that DOM Level
   2068    * 1 didn't store the document's base URI.)
   2069    * TODO: Consider resolving Relative URIs.
   2070    * <p>
   2071    * (The DOM's statement that "An XML processor may choose to
   2072    * completely expand entities before the structure model is passed
   2073    * to the DOM" refers only to parsed entities, not unparsed, and hence
   2074    * doesn't affect this function.)
   2075    *
   2076    * @param name A string containing the Entity Name of the unparsed
   2077    * entity.
   2078    *
   2079    * @return String containing the URI of the Unparsed Entity, or an
   2080    * empty string if no such entity exists.
   2081    */
   2082   public abstract String getUnparsedEntityURI(String name);
   2083 
   2084   // ============== Boolean methods ================
   2085 
   2086   /**
   2087    * Return true if the xsl:strip-space or xsl:preserve-space was processed
   2088    * during construction of the DTM document.
   2089    *
   2090    * @return true if this DTM supports prestripping.
   2091    */
   2092   public boolean supportsPreStripping()
   2093   {
   2094     return true;
   2095   }
   2096 
   2097   /**
   2098    * Figure out whether nodeHandle2 should be considered as being later
   2099    * in the document than nodeHandle1, in Document Order as defined
   2100    * by the XPath model. This may not agree with the ordering defined
   2101    * by other XML applications.
   2102    * <p>
   2103    * There are some cases where ordering isn't defined, and neither are
   2104    * the results of this function -- though we'll generally return false.
   2105    *
   2106    * @param nodeHandle1 Node handle to perform position comparison on.
   2107    * @param nodeHandle2 Second Node handle to perform position comparison on .
   2108    *
   2109    * @return true if node1 comes before node2, otherwise return false.
   2110    * You can think of this as
   2111    * <code>(node1.documentOrderPosition &lt;= node2.documentOrderPosition)</code>.
   2112    */
   2113   public boolean isNodeAfter(int nodeHandle1, int nodeHandle2)
   2114   {
   2115 		// These return NULL if the node doesn't belong to this document.
   2116     int index1 = makeNodeIdentity(nodeHandle1);
   2117     int index2 = makeNodeIdentity(nodeHandle2);
   2118 
   2119     return index1!=NULL && index2!=NULL && index1 <= index2;
   2120   }
   2121 
   2122   /**
   2123    *     2. [element content whitespace] A boolean indicating whether the
   2124    *        character is white space appearing within element content (see [XML],
   2125    *        2.10 "White Space Handling"). Note that validating XML processors are
   2126    *        required by XML 1.0 to provide this information. If there is no
   2127    *        declaration for the containing element, this property has no value for
   2128    *        white space characters. If no declaration has been read, but the [all
   2129    *        declarations processed] property of the document information item is
   2130    *        false (so there may be an unread declaration), then the value of this
   2131    *        property is unknown for white space characters. It is always false for
   2132    *        characters that are not white space.
   2133    *
   2134    * @param nodeHandle the node ID.
   2135    * @return <code>true</code> if the character data is whitespace;
   2136    *         <code>false</code> otherwise.
   2137    */
   2138   public boolean isCharacterElementContentWhitespace(int nodeHandle)
   2139   {
   2140 
   2141     // %TBD%
   2142     return false;
   2143   }
   2144 
   2145   /**
   2146    *    10. [all declarations processed] This property is not strictly speaking
   2147    *        part of the infoset of the document. Rather it is an indication of
   2148    *        whether the processor has read the complete DTD. Its value is a
   2149    *        boolean. If it is false, then certain properties (indicated in their
   2150    *        descriptions below) may be unknown. If it is true, those properties
   2151    *        are never unknown.
   2152    *
   2153    * @param documentHandle A node handle that must identify a document.
   2154    * @return <code>true</code> if all declarations were processed;
   2155    *         <code>false</code> otherwise.
   2156    */
   2157   public boolean isDocumentAllDeclarationsProcessed(int documentHandle)
   2158   {
   2159     return true;
   2160   }
   2161 
   2162   /**
   2163    *     5. [specified] A flag indicating whether this attribute was actually
   2164    *        specified in the start-tag of its element, or was defaulted from the
   2165    *        DTD.
   2166    *
   2167    * @param attributeHandle The attribute handle in question.
   2168    *
   2169    * @return <code>true</code> if the attribute was specified;
   2170    *         <code>false</code> if it was defaulted.
   2171    */
   2172   public abstract boolean isAttributeSpecified(int attributeHandle);
   2173 
   2174   // ========== Direct SAX Dispatch, for optimization purposes ========
   2175 
   2176   /**
   2177    * Directly call the
   2178    * characters method on the passed ContentHandler for the
   2179    * string-value of the given node (see http://www.w3.org/TR/xpath#data-model
   2180    * for the definition of a node's string-value). Multiple calls to the
   2181    * ContentHandler's characters methods may well occur for a single call to
   2182    * this method.
   2183    *
   2184    * @param nodeHandle The node ID.
   2185    * @param ch A non-null reference to a ContentHandler.
   2186    * @param normalize true if the content should be normalized according to
   2187    * the rules for the XPath
   2188    * <a href="http://www.w3.org/TR/xpath#function-normalize-space">normalize-space</a>
   2189    * function.
   2190    *
   2191    * @throws org.xml.sax.SAXException
   2192    */
   2193   public abstract void dispatchCharactersEvents(
   2194     int nodeHandle, org.xml.sax.ContentHandler ch, boolean normalize)
   2195       throws org.xml.sax.SAXException;
   2196 
   2197   /**
   2198    * Directly create SAX parser events from a subtree.
   2199    *
   2200    * @param nodeHandle The node ID.
   2201    * @param ch A non-null reference to a ContentHandler.
   2202    *
   2203    * @throws org.xml.sax.SAXException
   2204    */
   2205   public abstract void dispatchToEvents(
   2206     int nodeHandle, org.xml.sax.ContentHandler ch)
   2207       throws org.xml.sax.SAXException;
   2208 
   2209   /**
   2210    * Return an DOM node for the given node.
   2211    *
   2212    * @param nodeHandle The node ID.
   2213    *
   2214    * @return A node representation of the DTM node.
   2215    */
   2216   public org.w3c.dom.Node getNode(int nodeHandle)
   2217   {
   2218     return new DTMNodeProxy(this, nodeHandle);
   2219   }
   2220 
   2221   // ==== Construction methods (may not be supported by some implementations!) =====
   2222 
   2223   /**
   2224    * Append a child to the end of the document. Please note that the node
   2225    * is always cloned if it is owned by another document.
   2226    *
   2227    * <p>%REVIEW% "End of the document" needs to be defined more clearly.
   2228    * Does it become the last child of the Document? Of the root element?</p>
   2229    *
   2230    * @param newChild Must be a valid new node handle.
   2231    * @param clone true if the child should be cloned into the document.
   2232    * @param cloneDepth if the clone argument is true, specifies that the
   2233    *                   clone should include all it's children.
   2234    */
   2235   public void appendChild(int newChild, boolean clone, boolean cloneDepth)
   2236   {
   2237     error(XMLMessages.createXMLMessage(XMLErrorResources.ER_METHOD_NOT_SUPPORTED, null));//"appendChild not yet supported!");
   2238   }
   2239 
   2240   /**
   2241    * Append a text node child that will be constructed from a string,
   2242    * to the end of the document.
   2243    *
   2244    * <p>%REVIEW% "End of the document" needs to be defined more clearly.
   2245    * Does it become the last child of the Document? Of the root element?</p>
   2246    *
   2247    * @param str Non-null reverence to a string.
   2248    */
   2249   public void appendTextChild(String str)
   2250   {
   2251     error(XMLMessages.createXMLMessage(XMLErrorResources.ER_METHOD_NOT_SUPPORTED, null));//"appendTextChild not yet supported!");
   2252   }
   2253 
   2254   /**
   2255    * Simple error for asserts and the like.
   2256    *
   2257    * @param msg Error message to report.
   2258    */
   2259   protected void error(String msg)
   2260   {
   2261     throw new DTMException(msg);
   2262   }
   2263 
   2264   /**
   2265    * Find out whether or not to strip whispace nodes.
   2266    *
   2267    *
   2268    * @return whether or not to strip whispace nodes.
   2269    */
   2270   protected boolean getShouldStripWhitespace()
   2271   {
   2272     return m_shouldStripWS;
   2273   }
   2274 
   2275   /**
   2276    * Set whether to strip whitespaces and push in current value of
   2277    * m_shouldStripWS in m_shouldStripWhitespaceStack.
   2278    *
   2279    * @param shouldStrip Flag indicating whether to strip whitespace nodes
   2280    */
   2281   protected void pushShouldStripWhitespace(boolean shouldStrip)
   2282   {
   2283 
   2284     m_shouldStripWS = shouldStrip;
   2285 
   2286     if (null != m_shouldStripWhitespaceStack)
   2287       m_shouldStripWhitespaceStack.push(shouldStrip);
   2288   }
   2289 
   2290   /**
   2291    * Set whether to strip whitespaces at this point by popping out
   2292    * m_shouldStripWhitespaceStack.
   2293    *
   2294    */
   2295   protected void popShouldStripWhitespace()
   2296   {
   2297     if (null != m_shouldStripWhitespaceStack)
   2298       m_shouldStripWS = m_shouldStripWhitespaceStack.popAndTop();
   2299   }
   2300 
   2301   /**
   2302    * Set whether to strip whitespaces and set the top of the stack to
   2303    * the current value of m_shouldStripWS.
   2304    *
   2305    *
   2306    * @param shouldStrip Flag indicating whether to strip whitespace nodes
   2307    */
   2308   protected void setShouldStripWhitespace(boolean shouldStrip)
   2309   {
   2310 
   2311     m_shouldStripWS = shouldStrip;
   2312 
   2313     if (null != m_shouldStripWhitespaceStack)
   2314       m_shouldStripWhitespaceStack.setTop(shouldStrip);
   2315   }
   2316 
   2317   /**
   2318    * A dummy routine to satisify the abstract interface. If the DTM
   2319    * implememtation that extends the default base requires notification
   2320    * of registration, they can override this method.
   2321    */
   2322    public void documentRegistration()
   2323    {
   2324    }
   2325 
   2326   /**
   2327    * A dummy routine to satisify the abstract interface. If the DTM
   2328    * implememtation that extends the default base requires notification
   2329    * when the document is being released, they can override this method
   2330    */
   2331    public void documentRelease()
   2332    {
   2333    }
   2334 
   2335    /**
   2336     * Migrate a DTM built with an old DTMManager to a new DTMManager.
   2337     * After the migration, the new DTMManager will treat the DTM as
   2338     * one that is built by itself.
   2339     * This is used to support DTM sharing between multiple transformations.
   2340     * @param mgr the DTMManager
   2341     */
   2342    public void migrateTo(DTMManager mgr)
   2343    {
   2344      m_mgr = mgr;
   2345      if(mgr instanceof DTMManagerDefault)
   2346        m_mgrDefault=(DTMManagerDefault)mgr;
   2347    }
   2348 
   2349 	 /** Query which DTMManager this DTM is currently being handled by.
   2350 	  *
   2351 	  * %REVEW% Should this become part of the base DTM API?
   2352 	  *
   2353 	  * @return a DTMManager, or null if this is a "stand-alone" DTM.
   2354 	  */
   2355 	 public DTMManager getManager()
   2356 	 {
   2357 		 return m_mgr;
   2358 	 }
   2359 
   2360 	 /** Query which DTMIDs this DTM is currently using within the DTMManager.
   2361 	  *
   2362 	  * %REVEW% Should this become part of the base DTM API?
   2363 	  *
   2364 	  * @return an IntVector, or null if this is a "stand-alone" DTM.
   2365 	  */
   2366 	 public SuballocatedIntVector getDTMIDs()
   2367 	 {
   2368 		 if(m_mgr==null) return null;
   2369 		 return m_dtmIdent;
   2370 	 }
   2371 }
   2372