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