OSDN Git Service

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