001    /*
002     * Licensed to the Apache Software Foundation (ASF) under one
003     * or more contributor license agreements. See the NOTICE file
004     * distributed with this work for additional information
005     * regarding copyright ownership. The ASF licenses this file
006     * to you under the Apache License, Version 2.0 (the  "License");
007     * you may not use this file except in compliance with the License.
008     * You may obtain a copy of the License at
009     *
010     *     http://www.apache.org/licenses/LICENSE-2.0
011     *
012     * Unless required by applicable law or agreed to in writing, software
013     * distributed under the License is distributed on an "AS IS" BASIS,
014     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015     * See the License for the specific language governing permissions and
016     * limitations under the License.
017     */
018    /*
019     * $Id: DTMDefaultBase.java 1225429 2011-12-29 04:44:11Z mrglavas $
020     */
021    package org.apache.xml.dtm.ref;
022    
023    import org.apache.xml.dtm.*;
024    import org.apache.xml.utils.SuballocatedIntVector;
025    import org.apache.xml.utils.BoolStack;
026    
027    import java.util.Vector;
028    
029    import javax.xml.transform.Source;
030    
031    import org.apache.xml.utils.XMLString;
032    import org.apache.xml.utils.XMLStringFactory;
033    
034    import org.apache.xml.res.XMLMessages;
035    import org.apache.xml.res.XMLErrorResources;
036    
037    import java.io.*; // for dumpDTM
038    
039    /**
040     * The <code>DTMDefaultBase</code> class serves as a helper base for DTMs.
041     * It sets up structures for navigation and type, while leaving data
042     * management and construction to the derived classes.
043     */
044    public abstract class DTMDefaultBase implements DTM
045    {
046        static final boolean JJK_DEBUG=false;
047    
048      // This constant is likely to be removed in the future. Use the 
049      // getDocument() method instead of ROOTNODE to get at the root 
050      // node of a DTM.
051      /** The identity of the root node. */
052      public static final int ROOTNODE = 0;
053            
054      /**
055       * The number of nodes, which is also used to determine the next
056       *  node index.
057       */
058      protected int m_size = 0;
059    
060      /** The expanded names, one array element for each node. */
061      protected SuballocatedIntVector m_exptype;
062    
063      /** First child values, one array element for each node. */
064      protected SuballocatedIntVector m_firstch;
065    
066      /** Next sibling values, one array element for each node. */
067      protected SuballocatedIntVector m_nextsib;
068    
069      /** Previous sibling values, one array element for each node. */
070      protected SuballocatedIntVector m_prevsib;
071    
072      /** Previous sibling values, one array element for each node. */
073      protected SuballocatedIntVector m_parent;
074    
075      /** Vector of SuballocatedIntVectors of NS decl sets */
076      protected Vector m_namespaceDeclSets = null;
077    
078      /** SuballocatedIntVector  of elements at which corresponding
079       * namespaceDeclSets were defined */
080      protected SuballocatedIntVector m_namespaceDeclSetElements = null;
081    
082      /**
083       * These hold indexes to elements based on namespace and local name.
084       * The base lookup is the the namespace.  The second lookup is the local
085       * name, and the last array contains the the first free element
086       * at the start, and the list of element handles following.
087       */
088      protected int[][][] m_elemIndexes;
089    
090      /** The default block size of the node arrays */
091      public static final int DEFAULT_BLOCKSIZE = 512;  // favor small docs.
092      
093      /** The number of blocks for the node arrays */
094      public static final int DEFAULT_NUMBLOCKS = 32;
095      
096      /** The number of blocks used for small documents & RTFs */
097      public static final int DEFAULT_NUMBLOCKS_SMALL = 4;
098      
099      /** 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) >>> 1;
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    }