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