View Javadoc
1   /*
2    * reserved comment block
3    * DO NOT REMOVE OR ALTER!
4    */
5   /*
6    * Copyright 1999-2004 The Apache Software Foundation.
7    *
8    * Licensed under the Apache License, Version 2.0 (the "License");
9    * you may not use this file except in compliance with the License.
10   * You may obtain a copy of the License at
11   *
12   *     http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing, software
15   * distributed under the License is distributed on an "AS IS" BASIS,
16   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17   * See the License for the specific language governing permissions and
18   * limitations under the License.
19   */
20  /*
21   * $Id: DTMDefaultBase.java,v 1.3 2005/09/28 13:48:52 pvedula Exp $
22   */
23  package com.sun.org.apache.xml.internal.dtm.ref;
24  
25  import com.sun.org.apache.xml.internal.dtm.*;
26  import com.sun.org.apache.xml.internal.utils.SuballocatedIntVector;
27  import com.sun.org.apache.xml.internal.utils.BoolStack;
28  
29  import java.util.Vector;
30  
31  import javax.xml.transform.Source;
32  
33  import com.sun.org.apache.xml.internal.utils.XMLString;
34  import com.sun.org.apache.xml.internal.utils.XMLStringFactory;
35  
36  import com.sun.org.apache.xml.internal.res.XMLMessages;
37  import com.sun.org.apache.xml.internal.res.XMLErrorResources;
38  
39  import java.io.*; // for dumpDTM
40  
41  /**
42   * The <code>DTMDefaultBase</code> class serves as a helper base for DTMs.
43   * It sets up structures for navigation and type, while leaving data
44   * management and construction to the derived classes.
45   */
46  public abstract class DTMDefaultBase implements DTM
47  {
48      static final boolean JJK_DEBUG=false;
49  
50    // This constant is likely to be removed in the future. Use the
51    // getDocument() method instead of ROOTNODE to get at the root
52    // node of a DTM.
53    /** The identity of the root node. */
54    public static final int ROOTNODE = 0;
55  
56    /**
57     * The number of nodes, which is also used to determine the next
58     *  node index.
59     */
60    protected int m_size = 0;
61  
62    /** The expanded names, one array element for each node. */
63    protected SuballocatedIntVector m_exptype;
64  
65    /** First child values, one array element for each node. */
66    protected SuballocatedIntVector m_firstch;
67  
68    /** Next sibling values, one array element for each node. */
69    protected SuballocatedIntVector m_nextsib;
70  
71    /** Previous sibling values, one array element for each node. */
72    protected SuballocatedIntVector m_prevsib;
73  
74    /** Previous sibling values, one array element for each node. */
75    protected SuballocatedIntVector m_parent;
76  
77    /** Vector of SuballocatedIntVectors of NS decl sets */
78    protected Vector m_namespaceDeclSets = null;
79  
80    /** SuballocatedIntVector  of elements at which corresponding
81     * namespaceDeclSets were defined */
82    protected SuballocatedIntVector m_namespaceDeclSetElements = null;
83  
84    /**
85     * These hold indexes to elements based on namespace and local name.
86     * The base lookup is the the namespace.  The second lookup is the local
87     * name, and the last array contains the the first free element
88     * at the start, and the list of element handles following.
89     */
90    protected int[][][] m_elemIndexes;
91  
92    /** The default block size of the node arrays */
93    public static final int DEFAULT_BLOCKSIZE = 512;  // favor small docs.
94  
95    /** The number of blocks for the node arrays */
96    public static final int DEFAULT_NUMBLOCKS = 32;
97  
98    /** The number of blocks used for small documents & RTFs */
99    public static final int DEFAULT_NUMBLOCKS_SMALL = 4;
100 
101   /** The block size of the node arrays */
102   //protected final int m_blocksize;
103 
104   /**
105    * The value to use when the information has not been built yet.
106    */
107   protected static final int NOTPROCESSED = DTM.NULL - 1;
108 
109   /**
110    * The DTM manager who "owns" this DTM.
111    */
112 
113   public DTMManager m_mgr;
114 
115   /**
116    * m_mgr cast to DTMManagerDefault, or null if it isn't an instance
117    * (Efficiency hook)
118    */
119   protected DTMManagerDefault m_mgrDefault=null;
120 
121 
122   /** The document identity number(s). If we have overflowed the addressing
123    * range of the first that was assigned to us, we may add others. */
124   protected SuballocatedIntVector m_dtmIdent;
125 
126   /** The mask for the identity.
127       %REVIEW% Should this really be set to the _DEFAULT? What if
128       a particular DTM wanted to use another value? */
129   //protected final static int m_mask = DTMManager.IDENT_NODE_DEFAULT;
130 
131   /** The base URI for this document. */
132   protected String m_documentBaseURI;
133 
134   /**
135    * The whitespace filter that enables elements to strip whitespace or not.
136    */
137   protected DTMWSFilter m_wsfilter;
138 
139   /** Flag indicating whether to strip whitespace nodes */
140   protected boolean m_shouldStripWS = false;
141 
142   /** Stack of flags indicating whether to strip whitespace nodes */
143   protected BoolStack m_shouldStripWhitespaceStack;
144 
145   /** The XMLString factory for creating XMLStrings. */
146   protected XMLStringFactory m_xstrf;
147 
148   /**
149    * The table for exandedNameID lookups.  This may or may not be the same
150    * table as is contained in the DTMManagerDefault.
151    */
152   protected ExpandedNameTable m_expandedNameTable;
153 
154   /** true if indexing is turned on. */
155   protected boolean m_indexing;
156 
157   /**
158    * Construct a DTMDefaultBase object using the default block size.
159    *
160    * @param mgr The DTMManager who owns this DTM.
161    * @param source The object that is used to specify the construction source.
162    * @param dtmIdentity The DTM identity ID for this DTM.
163    * @param whiteSpaceFilter The white space filter for this DTM, which may
164    *                         be null.
165    * @param xstringfactory The factory to use for creating XMLStrings.
166    * @param doIndexing true if the caller considers it worth it to use
167    *                   indexing schemes.
168    */
169   public DTMDefaultBase(DTMManager mgr, Source source, int dtmIdentity,
170                         DTMWSFilter whiteSpaceFilter,
171                         XMLStringFactory xstringfactory, boolean doIndexing)
172   {
173     this(mgr, source, dtmIdentity, whiteSpaceFilter, xstringfactory,
174          doIndexing, DEFAULT_BLOCKSIZE, true, false);
175   }
176 
177   /**
178    * Construct a DTMDefaultBase object from a DOM node.
179    *
180    * @param mgr The DTMManager who owns this DTM.
181    * @param source The object that is used to specify the construction source.
182    * @param dtmIdentity The DTM identity ID for this DTM.
183    * @param whiteSpaceFilter The white space filter for this DTM, which may
184    *                         be null.
185    * @param xstringfactory The factory to use for creating XMLStrings.
186    * @param doIndexing true if the caller considers it worth it to use
187    *                   indexing schemes.
188    * @param blocksize The block size of the DTM.
189    * @param usePrevsib true if we want to build the previous sibling node array.
190    * @param newNameTable true if we want to use a new ExpandedNameTable for this DTM.
191    */
192   public DTMDefaultBase(DTMManager mgr, Source source, int dtmIdentity,
193                         DTMWSFilter whiteSpaceFilter,
194                         XMLStringFactory xstringfactory, boolean doIndexing,
195                         int blocksize, boolean usePrevsib,
196                         boolean newNameTable)
197   {
198     // Use smaller sizes for the internal node arrays if the block size
199     // is small.
200     int numblocks;
201     if (blocksize <= 64)
202     {
203       numblocks = DEFAULT_NUMBLOCKS_SMALL;
204       m_dtmIdent= new SuballocatedIntVector(4, 1);
205     }
206     else
207     {
208       numblocks = DEFAULT_NUMBLOCKS;
209       m_dtmIdent= new SuballocatedIntVector(32);
210     }
211 
212     m_exptype = new SuballocatedIntVector(blocksize, numblocks);
213     m_firstch = new SuballocatedIntVector(blocksize, numblocks);
214     m_nextsib = new SuballocatedIntVector(blocksize, numblocks);
215     m_parent  = new SuballocatedIntVector(blocksize, numblocks);
216 
217     // Only create the m_prevsib array if the usePrevsib flag is true.
218     // Some DTM implementations (e.g. SAXImpl) do not need this array.
219     // We can save the time to build it in those cases.
220     if (usePrevsib)
221       m_prevsib = new SuballocatedIntVector(blocksize, numblocks);
222 
223     m_mgr = mgr;
224     if(mgr instanceof DTMManagerDefault)
225       m_mgrDefault=(DTMManagerDefault)mgr;
226 
227     m_documentBaseURI = (null != source) ? source.getSystemId() : null;
228     m_dtmIdent.setElementAt(dtmIdentity,0);
229     m_wsfilter = whiteSpaceFilter;
230     m_xstrf = xstringfactory;
231     m_indexing = doIndexing;
232 
233     if (doIndexing)
234     {
235       m_expandedNameTable = new ExpandedNameTable();
236     }
237     else
238     {
239       // Note that this fails if we aren't talking to an instance of
240       // DTMManagerDefault
241       m_expandedNameTable = m_mgrDefault.getExpandedNameTable(this);
242     }
243 
244     if (null != whiteSpaceFilter)
245     {
246       m_shouldStripWhitespaceStack = new BoolStack();
247 
248       pushShouldStripWhitespace(false);
249     }
250   }
251 
252   /**
253    * Ensure that the size of the element indexes can hold the information.
254    *
255    * @param namespaceID Namespace ID index.
256    * @param LocalNameID Local name ID.
257    */
258   protected void ensureSizeOfIndex(int namespaceID, int LocalNameID)
259   {
260 
261     if (null == m_elemIndexes)
262     {
263       m_elemIndexes = new int[namespaceID + 20][][];
264     }
265     else if (m_elemIndexes.length <= namespaceID)
266     {
267       int[][][] indexes = m_elemIndexes;
268 
269       m_elemIndexes = new int[namespaceID + 20][][];
270 
271       System.arraycopy(indexes, 0, m_elemIndexes, 0, indexes.length);
272     }
273 
274     int[][] localNameIndex = m_elemIndexes[namespaceID];
275 
276     if (null == localNameIndex)
277     {
278       localNameIndex = new int[LocalNameID + 100][];
279       m_elemIndexes[namespaceID] = localNameIndex;
280     }
281     else if (localNameIndex.length <= LocalNameID)
282     {
283       int[][] indexes = localNameIndex;
284 
285       localNameIndex = new int[LocalNameID + 100][];
286 
287       System.arraycopy(indexes, 0, localNameIndex, 0, indexes.length);
288 
289       m_elemIndexes[namespaceID] = localNameIndex;
290     }
291 
292     int[] elemHandles = localNameIndex[LocalNameID];
293 
294     if (null == elemHandles)
295     {
296       elemHandles = new int[128];
297       localNameIndex[LocalNameID] = elemHandles;
298       elemHandles[0] = 1;
299     }
300     else if (elemHandles.length <= elemHandles[0] + 1)
301     {
302       int[] indexes = elemHandles;
303 
304       elemHandles = new int[elemHandles[0] + 1024];
305 
306       System.arraycopy(indexes, 0, elemHandles, 0, indexes.length);
307 
308       localNameIndex[LocalNameID] = elemHandles;
309     }
310   }
311 
312   /**
313    * Add a node to the element indexes. The node will not be added unless
314    * it's an element.
315    *
316    * @param expandedTypeID The expanded type ID of the node.
317    * @param identity The node identity index.
318    */
319   protected void indexNode(int expandedTypeID, int identity)
320   {
321 
322     ExpandedNameTable ent = m_expandedNameTable;
323     short type = ent.getType(expandedTypeID);
324 
325     if (DTM.ELEMENT_NODE == type)
326     {
327       int namespaceID = ent.getNamespaceID(expandedTypeID);
328       int localNameID = ent.getLocalNameID(expandedTypeID);
329 
330       ensureSizeOfIndex(namespaceID, localNameID);
331 
332       int[] index = m_elemIndexes[namespaceID][localNameID];
333 
334       index[index[0]] = identity;
335 
336       index[0]++;
337     }
338   }
339 
340   /**
341    * Find the first index that occurs in the list that is greater than or
342    * equal to the given value.
343    *
344    * @param list A list of integers.
345    * @param start The start index to begin the search.
346    * @param len The number of items to search.
347    * @param value Find the slot that has a value that is greater than or
348    * identical to this argument.
349    *
350    * @return The index in the list of the slot that is higher or identical
351    * to the identity argument, or -1 if no node is higher or equal.
352    */
353   protected int findGTE(int[] list, int start, int len, int value)
354   {
355 
356     int low = start;
357     int high = start + (len - 1);
358     int end = high;
359 
360     while (low <= high)
361     {
362       int mid = (low + high) / 2;
363       int c = list[mid];
364 
365       if (c > value)
366         high = mid - 1;
367       else if (c < value)
368         low = mid + 1;
369       else
370         return mid;
371     }
372 
373     return (low <= end && list[low] > value) ? low : -1;
374   }
375 
376   /**
377    * Find the first matching element from the index at or after the
378    * given node.
379    *
380    * @param nsIndex The namespace index lookup.
381    * @param lnIndex The local name index lookup.
382    * @param firstPotential The first potential match that is worth looking at.
383    *
384    * @return The first node that is greater than or equal to the
385    *         firstPotential argument, or DTM.NOTPROCESSED if not found.
386    */
387   int findElementFromIndex(int nsIndex, int lnIndex, int firstPotential)
388   {
389 
390     int[][][] indexes = m_elemIndexes;
391 
392     if (null != indexes && nsIndex < indexes.length)
393     {
394       int[][] lnIndexs = indexes[nsIndex];
395 
396       if (null != lnIndexs && lnIndex < lnIndexs.length)
397       {
398         int[] elems = lnIndexs[lnIndex];
399 
400         if (null != elems)
401         {
402           int pos = findGTE(elems, 1, elems[0], firstPotential);
403 
404           if (pos > -1)
405           {
406             return elems[pos];
407           }
408         }
409       }
410     }
411 
412     return NOTPROCESSED;
413   }
414 
415   /**
416    * Get the next node identity value in the list, and call the iterator
417    * if it hasn't been added yet.
418    *
419    * @param identity The node identity (index).
420    * @return identity+1, or DTM.NULL.
421    */
422   protected abstract int getNextNodeIdentity(int identity);
423 
424   /**
425    * This method should try and build one or more nodes in the table.
426    *
427    * @return The true if a next node is found or false if
428    *         there are no more nodes.
429    */
430   protected abstract boolean nextNode();
431 
432   /**
433    * Get the number of nodes that have been added.
434    *
435    * @return the number of nodes that have been mapped.
436    */
437   protected abstract int getNumberOfNodes();
438 
439   /** Stateless axis traversers, lazely built. */
440   protected DTMAxisTraverser[] m_traversers;
441 
442 //    /**
443 //     * Ensure that the size of the information arrays can hold another entry
444 //     * at the given index.
445 //     *
446 //     * @param index On exit from this function, the information arrays sizes must be
447 //     * at least index+1.
448 //     */
449 //    protected void ensureSize(int index)
450 //    {
451 //        // We've cut over to Suballocated*Vector, which are self-sizing.
452 //    }
453 
454   /**
455    * Get the simple type ID for the given node identity.
456    *
457    * @param identity The node identity.
458    *
459    * @return The simple type ID, or DTM.NULL.
460    */
461   protected short _type(int identity)
462   {
463 
464     int info = _exptype(identity);
465 
466     if (NULL != info)
467       return m_expandedNameTable.getType(info);
468     else
469       return NULL;
470   }
471 
472   /**
473    * Get the expanded type ID for the given node identity.
474    *
475    * @param identity The node identity.
476    *
477    * @return The expanded type ID, or DTM.NULL.
478    */
479   protected int _exptype(int identity)
480   {
481         if (identity == DTM.NULL)
482         return NULL;
483     // Reorganized test and loop into single flow
484     // Tiny performance improvement, saves a few bytes of code, clearer.
485     // %OPT% Other internal getters could be treated simliarly
486     while (identity>=m_size)
487     {
488       if (!nextNode() && identity >= m_size)
489         return NULL;
490     }
491     return m_exptype.elementAt(identity);
492 
493   }
494 
495   /**
496    * Get the level in the tree for the given node identity.
497    *
498    * @param identity The node identity.
499    *
500    * @return The tree level, or DTM.NULL.
501    */
502   protected int _level(int identity)
503   {
504     while (identity>=m_size)
505     {
506       boolean isMore = nextNode();
507       if (!isMore && identity >= m_size)
508         return NULL;
509     }
510 
511     int i=0;
512     while(NULL != (identity=_parent(identity)))
513       ++i;
514     return i;
515   }
516 
517   /**
518    * Get the first child for the given node identity.
519    *
520    * @param identity The node identity.
521    *
522    * @return The first child identity, or DTM.NULL.
523    */
524   protected int _firstch(int identity)
525   {
526 
527     // Boiler-plate code for each of the _xxx functions, except for the array.
528     int info = (identity >= m_size) ? NOTPROCESSED : m_firstch.elementAt(identity);
529 
530     // Check to see if the information requested has been processed, and,
531     // if not, advance the iterator until we the information has been
532     // processed.
533     while (info == NOTPROCESSED)
534     {
535       boolean isMore = nextNode();
536 
537       if (identity >= m_size &&!isMore)
538         return NULL;
539       else
540       {
541         info = m_firstch.elementAt(identity);
542         if(info == NOTPROCESSED && !isMore)
543           return NULL;
544       }
545     }
546 
547     return info;
548   }
549 
550   /**
551    * Get the next sibling for the given node identity.
552    *
553    * @param identity The node identity.
554    *
555    * @return The next sibling identity, or DTM.NULL.
556    */
557   protected int _nextsib(int identity)
558   {
559     // Boiler-plate code for each of the _xxx functions, except for the array.
560     int info = (identity >= m_size) ? NOTPROCESSED : m_nextsib.elementAt(identity);
561 
562     // Check to see if the information requested has been processed, and,
563     // if not, advance the iterator until we the information has been
564     // processed.
565     while (info == NOTPROCESSED)
566     {
567       boolean isMore = nextNode();
568 
569       if (identity >= m_size &&!isMore)
570         return NULL;
571       else
572       {
573         info = m_nextsib.elementAt(identity);
574         if(info == NOTPROCESSED && !isMore)
575           return NULL;
576       }
577     }
578 
579     return info;
580   }
581 
582   /**
583    * Get the previous sibling for the given node identity.
584    *
585    * @param identity The node identity.
586    *
587    * @return The previous sibling identity, or DTM.NULL.
588    */
589   protected int _prevsib(int identity)
590   {
591 
592     if (identity < m_size)
593       return m_prevsib.elementAt(identity);
594 
595     // Check to see if the information requested has been processed, and,
596     // if not, advance the iterator until we the information has been
597     // processed.
598     while (true)
599     {
600       boolean isMore = nextNode();
601 
602       if (identity >= m_size && !isMore)
603         return NULL;
604       else if (identity < m_size)
605         return m_prevsib.elementAt(identity);
606     }
607   }
608 
609   /**
610    * Get the parent for the given node identity.
611    *
612    * @param identity The node identity.
613    *
614    * @return The parent identity, or DTM.NULL.
615    */
616   protected int _parent(int identity)
617   {
618 
619     if (identity < m_size)
620       return m_parent.elementAt(identity);
621 
622     // Check to see if the information requested has been processed, and,
623     // if not, advance the iterator until we the information has been
624     // processed.
625     while (true)
626     {
627       boolean isMore = nextNode();
628 
629       if (identity >= m_size && !isMore)
630         return NULL;
631       else if (identity < m_size)
632         return m_parent.elementAt(identity);
633     }
634   }
635 
636   /**
637    * Diagnostics function to dump the DTM.
638    */
639   public void dumpDTM(OutputStream os)
640   {
641     try
642     {
643       if(os==null)
644       {
645               File f = new File("DTMDump"+((Object)this).hashCode()+".txt");
646               System.err.println("Dumping... "+f.getAbsolutePath());
647               os=new FileOutputStream(f);
648       }
649       PrintStream ps = new PrintStream(os);
650 
651       while (nextNode()){}
652 
653       int nRecords = m_size;
654 
655       ps.println("Total nodes: " + nRecords);
656 
657       for (int index = 0; index < nRecords; ++index)
658       {
659         int i=makeNodeHandle(index);
660         ps.println("=========== index=" + index + " handle=" + i + " ===========");
661         ps.println("NodeName: " + getNodeName(i));
662         ps.println("NodeNameX: " + getNodeNameX(i));
663         ps.println("LocalName: " + getLocalName(i));
664         ps.println("NamespaceURI: " + getNamespaceURI(i));
665         ps.println("Prefix: " + getPrefix(i));
666 
667         int exTypeID = _exptype(index);
668 
669         ps.println("Expanded Type ID: "
670                            + Integer.toHexString(exTypeID));
671 
672         int type = _type(index);
673         String typestring;
674 
675         switch (type)
676         {
677         case DTM.ATTRIBUTE_NODE :
678           typestring = "ATTRIBUTE_NODE";
679           break;
680         case DTM.CDATA_SECTION_NODE :
681           typestring = "CDATA_SECTION_NODE";
682           break;
683         case DTM.COMMENT_NODE :
684           typestring = "COMMENT_NODE";
685           break;
686         case DTM.DOCUMENT_FRAGMENT_NODE :
687           typestring = "DOCUMENT_FRAGMENT_NODE";
688           break;
689         case DTM.DOCUMENT_NODE :
690           typestring = "DOCUMENT_NODE";
691           break;
692         case DTM.DOCUMENT_TYPE_NODE :
693           typestring = "DOCUMENT_NODE";
694           break;
695         case DTM.ELEMENT_NODE :
696           typestring = "ELEMENT_NODE";
697           break;
698         case DTM.ENTITY_NODE :
699           typestring = "ENTITY_NODE";
700           break;
701         case DTM.ENTITY_REFERENCE_NODE :
702           typestring = "ENTITY_REFERENCE_NODE";
703           break;
704         case DTM.NAMESPACE_NODE :
705           typestring = "NAMESPACE_NODE";
706           break;
707         case DTM.NOTATION_NODE :
708           typestring = "NOTATION_NODE";
709           break;
710         case DTM.NULL :
711           typestring = "NULL";
712           break;
713         case DTM.PROCESSING_INSTRUCTION_NODE :
714           typestring = "PROCESSING_INSTRUCTION_NODE";
715           break;
716         case DTM.TEXT_NODE :
717           typestring = "TEXT_NODE";
718           break;
719         default :
720           typestring = "Unknown!";
721           break;
722         }
723 
724         ps.println("Type: " + typestring);
725 
726         int firstChild = _firstch(index);
727 
728         if (DTM.NULL == firstChild)
729           ps.println("First child: DTM.NULL");
730         else if (NOTPROCESSED == firstChild)
731           ps.println("First child: NOTPROCESSED");
732         else
733           ps.println("First child: " + firstChild);
734 
735         if (m_prevsib != null)
736         {
737           int prevSibling = _prevsib(index);
738 
739           if (DTM.NULL == prevSibling)
740             ps.println("Prev sibling: DTM.NULL");
741           else if (NOTPROCESSED == prevSibling)
742             ps.println("Prev sibling: NOTPROCESSED");
743           else
744             ps.println("Prev sibling: " + prevSibling);
745         }
746 
747         int nextSibling = _nextsib(index);
748 
749         if (DTM.NULL == nextSibling)
750           ps.println("Next sibling: DTM.NULL");
751         else if (NOTPROCESSED == nextSibling)
752           ps.println("Next sibling: NOTPROCESSED");
753         else
754           ps.println("Next sibling: " + nextSibling);
755 
756         int parent = _parent(index);
757 
758         if (DTM.NULL == parent)
759           ps.println("Parent: DTM.NULL");
760         else if (NOTPROCESSED == parent)
761           ps.println("Parent: NOTPROCESSED");
762         else
763           ps.println("Parent: " + parent);
764 
765         int level = _level(index);
766 
767         ps.println("Level: " + level);
768         ps.println("Node Value: " + getNodeValue(i));
769         ps.println("String Value: " + getStringValue(i));
770       }
771     }
772     catch(IOException ioe)
773     {
774       ioe.printStackTrace(System.err);
775         throw new RuntimeException(ioe.getMessage());
776     }
777   }
778 
779   /**
780    * Diagnostics function to dump a single node.
781    *
782    * %REVIEW% KNOWN GLITCH: If you pass it a node index rather than a
783    * node handle, it works just fine... but the displayed identity
784    * number before the colon is different, which complicates comparing
785    * it with nodes printed the other way. We could always OR the DTM ID
786    * into the value, to suppress that distinction...
787    *
788    * %REVIEW% This might want to be moved up to DTMDefaultBase, or possibly
789    * DTM itself, since it's a useful diagnostic and uses only DTM's public
790    * APIs.
791    */
792   public String dumpNode(int nodeHandle)
793   {
794           if(nodeHandle==DTM.NULL)
795                   return "[null]";
796 
797         String typestring;
798         switch (getNodeType(nodeHandle))
799         {
800         case DTM.ATTRIBUTE_NODE :
801           typestring = "ATTR";
802           break;
803         case DTM.CDATA_SECTION_NODE :
804           typestring = "CDATA";
805           break;
806         case DTM.COMMENT_NODE :
807           typestring = "COMMENT";
808           break;
809         case DTM.DOCUMENT_FRAGMENT_NODE :
810           typestring = "DOC_FRAG";
811           break;
812         case DTM.DOCUMENT_NODE :
813           typestring = "DOC";
814           break;
815         case DTM.DOCUMENT_TYPE_NODE :
816           typestring = "DOC_TYPE";
817           break;
818         case DTM.ELEMENT_NODE :
819           typestring = "ELEMENT";
820           break;
821         case DTM.ENTITY_NODE :
822           typestring = "ENTITY";
823           break;
824         case DTM.ENTITY_REFERENCE_NODE :
825           typestring = "ENT_REF";
826           break;
827         case DTM.NAMESPACE_NODE :
828           typestring = "NAMESPACE";
829           break;
830         case DTM.NOTATION_NODE :
831           typestring = "NOTATION";
832           break;
833         case DTM.NULL :
834           typestring = "null";
835           break;
836         case DTM.PROCESSING_INSTRUCTION_NODE :
837           typestring = "PI";
838           break;
839         case DTM.TEXT_NODE :
840           typestring = "TEXT";
841           break;
842         default :
843           typestring = "Unknown!";
844           break;
845         }
846 
847       return "[" + nodeHandle + ": " + typestring +
848               "(0x" + Integer.toHexString(getExpandedTypeID(nodeHandle)) + ") " +
849               getNodeNameX(nodeHandle) + " {" + getNamespaceURI(nodeHandle) + "}" +
850               "=\"" + getNodeValue(nodeHandle) + "\"]";
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 com.sun.org.apache.xml.internal.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 }