KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > xml > dtm > ref > sax2dtm > SAX2DTM2


1 /*
2  * Copyright 1999-2004 The Apache Software Foundation.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16 /*
17  * $Id: SAX2DTM2.java,v 1.10 2004/02/24 04:22:12 zongaro Exp $
18  */

19 package org.apache.xml.dtm.ref.sax2dtm;
20
21 import org.apache.xml.dtm.*;
22 import org.apache.xml.dtm.ref.*;
23 import org.apache.xml.utils.FastStringBuffer;
24 import org.apache.xml.utils.XMLString;
25 import org.apache.xml.utils.XMLStringDefault;
26 import org.apache.xml.utils.XMLStringFactory;
27 import org.apache.xml.res.XMLMessages;
28 import org.apache.xml.res.XMLErrorResources;
29 import org.apache.xml.serializer.SerializationHandler;
30
31 import javax.xml.transform.Source JavaDoc;
32 import java.util.Vector JavaDoc;
33 import org.apache.xml.utils.IntStack;
34 import org.xml.sax.*;
35
36 /**
37  * SAX2DTM2 is an optimized version of SAX2DTM which is used in non-incremental situation.
38  * It is used as the super class of the XSLTC SAXImpl. Many of the interfaces in SAX2DTM
39  * and DTMDefaultBase are overridden in SAX2DTM2 in order to allow fast, efficient
40  * access to the DTM model. Some nested iterators in DTMDefaultBaseIterators
41  * are also overridden in SAX2DTM2 for performance reasons.
42  * <p>
43  * Performance is the biggest consideration in the design of SAX2DTM2. To make the code most
44  * efficient, the incremental support is dropped in SAX2DTM2, which means that you should not
45  * use it in incremental situation. To reduce the overhead of pulling data from the DTM model,
46  * a few core interfaces in SAX2DTM2 have direct access to the internal arrays of the
47  * SuballocatedIntVectors.
48  * <p>
49  * The design of SAX2DTM2 may limit its extensibilty. If you have a reason to extend the
50  * SAX2DTM model, please extend from SAX2DTM instead of this class.
51  * <p>
52  * TODO: This class is currently only used by XSLTC. We need to investigate the possibility
53  * of also using it in Xalan-J Interpretive. Xalan's performance is likely to get an instant
54  * boost if we use SAX2DTM2 instead of SAX2DTM in non-incremental case.
55  * <p>
56  * %MK% The code in this class is critical to the XSLTC_DTM performance. Be very careful
57  * when making changes here!
58  */

59 public class SAX2DTM2 extends SAX2DTM
60 {
61
62   /****************************************************************
63    * Optimized version of the nested iterators
64    ****************************************************************/

65    
66   /**
67    * Iterator that returns all immediate children of a given node
68    */

69   public final class ChildrenIterator extends InternalAxisIteratorBase
70   {
71
72     /**
73      * Setting start to END should 'close' the iterator,
74      * i.e. subsequent call to next() should return END.
75      * <p>
76      * If the iterator is not restartable, this has no effect.
77      * %REVIEW% Should it return/throw something in that case,
78      * or set current node to END, to indicate request-not-honored?
79      *
80      * @param node Sets the root of the iteration.
81      *
82      * @return A DTMAxisIterator set to the start of the iteration.
83      */

84     public DTMAxisIterator setStartNode(int node)
85     {
86 //%HZ%: Added reference to DTMDefaultBase.ROOTNODE back in, temporarily
87
if (node == DTMDefaultBase.ROOTNODE)
88         node = getDocument();
89       if (_isRestartable)
90       {
91         _startNode = node;
92         _currentNode = (node == DTM.NULL) ? DTM.NULL
93                                           : _firstch2(makeNodeIdentity(node));
94
95         return resetPosition();
96       }
97
98       return this;
99     }
100
101     /**
102      * Get the next node in the iteration.
103      *
104      * @return The next node handle in the iteration, or END if no more
105      * are available.
106      */

107     public int next()
108     {
109       if (_currentNode != NULL) {
110         int node = _currentNode;
111         _currentNode = _nextsib2(node);
112         return returnNode(makeNodeHandle(node));
113       }
114
115       return END;
116     }
117   } // end of ChildrenIterator
118

119   /**
120    * Iterator that returns the parent of a given node. Note that
121    * this delivers only a single node; if you want all the ancestors,
122    * see AncestorIterator.
123    */

124   public final class ParentIterator extends InternalAxisIteratorBase
125   {
126
127     /** The extended type ID that was requested. */
128     private int _nodeType = DTM.NULL;
129
130     /**
131      * Set start to END should 'close' the iterator,
132      * i.e. subsequent call to next() should return END.
133      *
134      * @param node Sets the root of the iteration.
135      *
136      * @return A DTMAxisIterator set to the start of the iteration.
137      */

138     public DTMAxisIterator setStartNode(int node)
139     {
140 //%HZ%: Added reference to DTMDefaultBase.ROOTNODE back in, temporarily
141
if (node == DTMDefaultBase.ROOTNODE)
142         node = getDocument();
143       if (_isRestartable)
144       {
145         _startNode = node;
146         
147         if (node != DTM.NULL)
148           _currentNode = _parent2(makeNodeIdentity(node));
149         else
150           _currentNode = DTM.NULL;
151         
152         return resetPosition();
153       }
154
155       return this;
156     }
157
158     /**
159      * Set the node type of the parent that we're looking for.
160      * Note that this does _not_ mean "find the nearest ancestor of
161      * this type", but "yield the parent if it is of this type".
162      *
163      *
164      * @param type extended type ID.
165      *
166      * @return ParentIterator configured with the type filter set.
167      */

168     public DTMAxisIterator setNodeType(final int type)
169     {
170
171       _nodeType = type;
172
173       return this;
174     }
175
176     /**
177      * Get the next node in the iteration. In this case, we return
178      * only the immediate parent, _if_ it matches the requested nodeType.
179      *
180      * @return The next node handle in the iteration, or END.
181      */

182     public int next()
183     {
184       int result = _currentNode;
185       if (result == END)
186         return DTM.NULL;
187
188       // %OPT% The most common case is handled first.
189
if (_nodeType == NULL) {
190         _currentNode = END;
191         return returnNode(makeNodeHandle(result));
192       }
193       else if (_nodeType >= DTM.NTYPES) {
194         if (_nodeType == _exptype2(result)) {
195           _currentNode = END;
196       return returnNode(makeNodeHandle(result));
197         }
198       }
199       else {
200         if (_nodeType == _type2(result)) {
201       _currentNode = END;
202       return returnNode(makeNodeHandle(result));
203         }
204       }
205       
206       return DTM.NULL;
207     }
208   } // end of ParentIterator
209

210   /**
211    * Iterator that returns children of a given type for a given node.
212    * The functionality chould be achieved by putting a filter on top
213    * of a basic child iterator, but a specialised iterator is used
214    * for efficiency (both speed and size of translet).
215    */

216   public final class TypedChildrenIterator extends InternalAxisIteratorBase
217   {
218
219     /** The extended type ID that was requested. */
220     private final int _nodeType;
221
222     /**
223      * Constructor TypedChildrenIterator
224      *
225      *
226      * @param nodeType The extended type ID being requested.
227      */

228     public TypedChildrenIterator(int nodeType)
229     {
230       _nodeType = nodeType;
231     }
232
233     /**
234      * Set start to END should 'close' the iterator,
235      * i.e. subsequent call to next() should return END.
236      *
237      * @param node Sets the root of the iteration.
238      *
239      * @return A DTMAxisIterator set to the start of the iteration.
240      */

241     public DTMAxisIterator setStartNode(int node)
242     {
243 //%HZ%: Added reference to DTMDefaultBase.ROOTNODE back in, temporarily
244
if (node == DTMDefaultBase.ROOTNODE)
245         node = getDocument();
246       if (_isRestartable)
247       {
248         _startNode = node;
249         _currentNode = (node == DTM.NULL)
250                                    ? DTM.NULL
251                                    : _firstch2(makeNodeIdentity(_startNode));
252
253         return resetPosition();
254       }
255
256       return this;
257     }
258
259     /**
260      * Get the next node in the iteration.
261      *
262      * @return The next node handle in the iteration, or END.
263      */

264     public int next()
265     {
266       int node = _currentNode;
267       if (node == DTM.NULL)
268         return DTM.NULL;
269
270       final int nodeType = _nodeType;
271
272       if (nodeType != DTM.ELEMENT_NODE) {
273         while (node != DTM.NULL && _exptype2(node) != nodeType) {
274           node = _nextsib2(node);
275         }
276       }
277       // %OPT% If the nodeType is element (matching child::*), we only
278
// need to compare the expType with DTM.NTYPES. A child node of
279
// an element can be either an element, text, comment or
280
// processing instruction node. Only element node has an extended
281
// type greater than or equal to DTM.NTYPES.
282
else {
283         int eType;
284         while (node != DTM.NULL) {
285           eType = _exptype2(node);
286           if (eType >= DTM.NTYPES)
287             break;
288           else
289             node = _nextsib2(node);
290         }
291       }
292
293       if (node == DTM.NULL) {
294         _currentNode = DTM.NULL;
295         return DTM.NULL;
296       } else {
297         _currentNode = _nextsib2(node);
298         return returnNode(makeNodeHandle(node));
299       }
300
301     }
302
303     /**
304      * Return the node at the given position.
305      */

306     public int getNodeByPosition(int position)
307     {
308       if (position <= 0)
309         return DTM.NULL;
310       
311       int node = _currentNode;
312       int pos = 0;
313       
314       final int nodeType = _nodeType;
315       if (nodeType != DTM.ELEMENT_NODE) {
316         while (node != DTM.NULL) {
317           if (_exptype2(node) == nodeType) {
318             pos++;
319             if (pos == position)
320               return makeNodeHandle(node);
321           }
322           
323           node = _nextsib2(node);
324         }
325         return NULL;
326       }
327       else {
328         while (node != DTM.NULL) {
329           if (_exptype2(node) >= DTM.NTYPES) {
330             pos++;
331             if (pos == position)
332               return makeNodeHandle(node);
333           }
334           node = _nextsib2(node);
335         }
336         return NULL;
337       }
338     }
339
340   } // end of TypedChildrenIterator
341

342   /**
343    * Iterator that returns the namespace nodes as defined by the XPath data model
344    * for a given node, filtered by extended type ID.
345    */

346   public class TypedRootIterator extends RootIterator
347   {
348
349     /** The extended type ID that was requested. */
350     private final int _nodeType;
351
352     /**
353      * Constructor TypedRootIterator
354      *
355      * @param nodeType The extended type ID being requested.
356      */

357     public TypedRootIterator(int nodeType)
358     {
359       super();
360       _nodeType = nodeType;
361     }
362
363     /**
364      * Get the next node in the iteration.
365      *
366      * @return The next node handle in the iteration, or END.
367      */

368     public int next()
369     {
370       if(_startNode == _currentNode)
371         return NULL;
372
373       final int node = _startNode;
374       int expType = _exptype2(makeNodeIdentity(node));
375
376       _currentNode = node;
377
378       if (_nodeType >= DTM.NTYPES) {
379         if (_nodeType == expType) {
380           return returnNode(node);
381         }
382       }
383       else {
384         if (expType < DTM.NTYPES) {
385           if (expType == _nodeType) {
386             return returnNode(node);
387           }
388         }
389         else {
390           if (m_extendedTypes[expType].getNodeType() == _nodeType) {
391             return returnNode(node);
392           }
393         }
394       }
395
396       return NULL;
397     }
398   } // end of TypedRootIterator
399

400   /**
401    * Iterator that returns all siblings of a given node.
402    */

403   public class FollowingSiblingIterator extends InternalAxisIteratorBase
404   {
405
406     /**
407      * Set start to END should 'close' the iterator,
408      * i.e. subsequent call to next() should return END.
409      *
410      * @param node Sets the root of the iteration.
411      *
412      * @return A DTMAxisIterator set to the start of the iteration.
413      */

414     public DTMAxisIterator setStartNode(int node)
415     {
416 //%HZ%: Added reference to DTMDefaultBase.ROOTNODE back in, temporarily
417
if (node == DTMDefaultBase.ROOTNODE)
418         node = getDocument();
419       if (_isRestartable)
420       {
421         _startNode = node;
422         _currentNode = makeNodeIdentity(node);
423
424         return resetPosition();
425       }
426
427       return this;
428     }
429
430     /**
431      * Get the next node in the iteration.
432      *
433      * @return The next node handle in the iteration, or END.
434      */

435     public int next()
436     {
437       _currentNode = (_currentNode == DTM.NULL) ? DTM.NULL
438                                                 : _nextsib2(_currentNode);
439       return returnNode(makeNodeHandle(_currentNode));
440     }
441   } // end of FollowingSiblingIterator
442

443   /**
444    * Iterator that returns all following siblings of a given node.
445    */

446   public final class TypedFollowingSiblingIterator
447           extends FollowingSiblingIterator
448   {
449
450     /** The extended type ID that was requested. */
451     private final int _nodeType;
452
453     /**
454      * Constructor TypedFollowingSiblingIterator
455      *
456      *
457      * @param type The extended type ID being requested.
458      */

459     public TypedFollowingSiblingIterator(int type)
460     {
461       _nodeType = type;
462     }
463
464     /**
465      * Get the next node in the iteration.
466      *
467      * @return The next node handle in the iteration, or END.
468      */

469     public int next()
470     {
471       if (_currentNode == DTM.NULL) {
472         return DTM.NULL;
473       }
474
475       int node = _currentNode;
476       final int nodeType = _nodeType;
477
478       if (nodeType != DTM.ELEMENT_NODE) {
479         while ((node = _nextsib2(node)) != DTM.NULL && _exptype2(node) != nodeType) {}
480       }
481       else {
482         while ((node = _nextsib2(node)) != DTM.NULL && _exptype2(node) < DTM.NTYPES) {}
483       }
484       
485       _currentNode = node;
486
487       return (node == DTM.NULL)
488                       ? DTM.NULL
489                       : returnNode(makeNodeHandle(node));
490     }
491
492   } // end of TypedFollowingSiblingIterator
493

494   /**
495    * Iterator that returns attribute nodes (of what nodes?)
496    */

497   public final class AttributeIterator extends InternalAxisIteratorBase
498   {
499
500     // assumes caller will pass element nodes
501

502     /**
503      * Set start to END should 'close' the iterator,
504      * i.e. subsequent call to next() should return END.
505      *
506      * @param node Sets the root of the iteration.
507      *
508      * @return A DTMAxisIterator set to the start of the iteration.
509      */

510     public DTMAxisIterator setStartNode(int node)
511     {
512 //%HZ%: Added reference to DTMDefaultBase.ROOTNODE back in, temporarily
513
if (node == DTMDefaultBase.ROOTNODE)
514         node = getDocument();
515       if (_isRestartable)
516       {
517         _startNode = node;
518         _currentNode = getFirstAttributeIdentity(makeNodeIdentity(node));
519
520         return resetPosition();
521       }
522
523       return this;
524     }
525
526     /**
527      * Get the next node in the iteration.
528      *
529      * @return The next node handle in the iteration, or END.
530      */

531     public int next()
532     {
533
534       final int node = _currentNode;
535
536       if (node != NULL) {
537         _currentNode = getNextAttributeIdentity(node);
538         return returnNode(makeNodeHandle(node));
539       }
540
541       return NULL;
542     }
543   } // end of AttributeIterator
544

545   /**
546    * Iterator that returns attribute nodes of a given type
547    */

548   public final class TypedAttributeIterator extends InternalAxisIteratorBase
549   {
550
551     /** The extended type ID that was requested. */
552     private final int _nodeType;
553
554     /**
555      * Constructor TypedAttributeIterator
556      *
557      *
558      * @param nodeType The extended type ID that is requested.
559      */

560     public TypedAttributeIterator(int nodeType)
561     {
562       _nodeType = nodeType;
563     }
564
565     // assumes caller will pass element nodes
566

567     /**
568      * Set start to END should 'close' the iterator,
569      * i.e. subsequent call to next() should return END.
570      *
571      * @param node Sets the root of the iteration.
572      *
573      * @return A DTMAxisIterator set to the start of the iteration.
574      */

575     public DTMAxisIterator setStartNode(int node)
576     {
577       if (_isRestartable)
578       {
579         _startNode = node;
580
581         _currentNode = getTypedAttribute(node, _nodeType);
582
583         return resetPosition();
584       }
585
586       return this;
587     }
588
589     /**
590      * Get the next node in the iteration.
591      *
592      * @return The next node handle in the iteration, or END.
593      */

594     public int next()
595     {
596
597       final int node = _currentNode;
598
599       // singleton iterator, since there can only be one attribute of
600
// a given type.
601
_currentNode = NULL;
602
603       return returnNode(node);
604     }
605   } // end of TypedAttributeIterator
606

607   /**
608    * Iterator that returns preceding siblings of a given node
609    */

610   public class PrecedingSiblingIterator extends InternalAxisIteratorBase
611   {
612
613     /**
614      * The node identity of _startNode for this iterator
615      */

616     protected int _startNodeID;
617
618     /**
619      * True if this iterator has a reversed axis.
620      *
621      * @return true.
622      */

623     public boolean isReverse()
624     {
625       return true;
626     }
627
628     /**
629      * Set start to END should 'close' the iterator,
630      * i.e. subsequent call to next() should return END.
631      *
632      * @param node Sets the root of the iteration.
633      *
634      * @return A DTMAxisIterator set to the start of the iteration.
635      */

636     public DTMAxisIterator setStartNode(int node)
637     {
638 //%HZ%: Added reference to DTMDefaultBase.ROOTNODE back in, temporarily
639
if (node == DTMDefaultBase.ROOTNODE)
640         node = getDocument();
641       if (_isRestartable)
642       {
643         _startNode = node;
644         node = _startNodeID = makeNodeIdentity(node);
645
646         if(node == NULL)
647         {
648           _currentNode = node;
649           return resetPosition();
650         }
651
652         int type = _type2(node);
653         if(ExpandedNameTable.ATTRIBUTE == type
654            || ExpandedNameTable.NAMESPACE == type )
655         {
656           _currentNode = node;
657         }
658         else
659         {
660           // Be careful to handle the Document node properly
661
_currentNode = _parent2(node);
662           if(NULL!=_currentNode)
663             _currentNode = _firstch2(_currentNode);
664           else
665             _currentNode = node;
666         }
667
668         return resetPosition();
669       }
670
671       return this;
672     }
673
674     /**
675      * Get the next node in the iteration.
676      *
677      * @return The next node handle in the iteration, or END.
678      */

679     public int next()
680     {
681
682       if (_currentNode == _startNodeID || _currentNode == DTM.NULL)
683       {
684         return NULL;
685       }
686       else
687       {
688         final int node = _currentNode;
689         _currentNode = _nextsib2(node);
690
691         return returnNode(makeNodeHandle(node));
692       }
693     }
694   } // end of PrecedingSiblingIterator
695

696   /**
697    * Iterator that returns preceding siblings of a given type for
698    * a given node
699    */

700   public final class TypedPrecedingSiblingIterator
701           extends PrecedingSiblingIterator
702   {
703
704     /** The extended type ID that was requested. */
705     private final int _nodeType;
706
707     /**
708      * Constructor TypedPrecedingSiblingIterator
709      *
710      *
711      * @param type The extended type ID being requested.
712      */

713     public TypedPrecedingSiblingIterator(int type)
714     {
715       _nodeType = type;
716     }
717
718     /**
719      * Get the next node in the iteration.
720      *
721      * @return The next node handle in the iteration, or END.
722      */

723     public int next()
724     {
725       int node = _currentNode;
726
727       final int nodeType = _nodeType;
728       final int startNodeID = _startNodeID;
729
730       if (nodeType != DTM.ELEMENT_NODE) {
731         while (node != NULL && node != startNodeID && _exptype2(node) != nodeType) {
732           node = _nextsib2(node);
733         }
734       }
735       else {
736         while (node != NULL && node != startNodeID && _exptype2(node) < DTM.NTYPES) {
737           node = _nextsib2(node);
738         }
739       }
740
741       if (node == DTM.NULL || node == startNodeID) {
742         _currentNode = NULL;
743         return NULL;
744       }
745       else {
746         _currentNode = _nextsib2(node);
747         return returnNode(makeNodeHandle(node));
748       }
749     }
750     
751     /**
752      * Return the index of the last node in this iterator.
753      */

754     public int getLast()
755     {
756       if (_last != -1)
757         return _last;
758       
759       setMark();
760       
761       int node = _currentNode;
762       final int nodeType = _nodeType;
763       final int startNodeID = _startNodeID;
764       
765       int last = 0;
766       if (nodeType != DTM.ELEMENT_NODE) {
767         while (node != NULL && node != startNodeID) {
768           if (_exptype2(node) == nodeType) {
769             last++;
770           }
771           node = _nextsib2(node);
772         }
773       }
774       else {
775         while (node != NULL && node != startNodeID) {
776           if (_exptype2(node) >= DTM.NTYPES) {
777             last++;
778           }
779           node = _nextsib2(node);
780         }
781       }
782       
783       gotoMark();
784       
785       return (_last = last);
786     }
787   } // end of TypedPrecedingSiblingIterator
788

789   /**
790    * Iterator that returns preceding nodes of a given node.
791    * This includes the node set {root+1, start-1}, but excludes
792    * all ancestors, attributes, and namespace nodes.
793    */

794   public class PrecedingIterator extends InternalAxisIteratorBase
795   {
796
797     /** The max ancestors, but it can grow... */
798     private final int _maxAncestors = 8;
799
800     /**
801      * The stack of start node + ancestors up to the root of the tree,
802      * which we must avoid.
803      */

804     protected int[] _stack = new int[_maxAncestors];
805
806     /** (not sure yet... -sb) */
807     protected int _sp, _oldsp;
808
809     protected int _markedsp, _markedNode, _markedDescendant;
810
811     /* _currentNode precedes candidates. This is the identity, not the handle! */
812
813     /**
814      * True if this iterator has a reversed axis.
815      *
816      * @return true since this iterator is a reversed axis.
817      */

818     public boolean isReverse()
819     {
820       return true;
821     }
822
823     /**
824      * Returns a deep copy of this iterator. The cloned iterator is not reset.
825      *
826      * @return a deep copy of this iterator.
827      */

828     public DTMAxisIterator cloneIterator()
829     {
830       _isRestartable = false;
831
832       try
833       {
834         final PrecedingIterator clone = (PrecedingIterator) super.clone();
835         final int[] stackCopy = new int[_stack.length];
836         System.arraycopy(_stack, 0, stackCopy, 0, _stack.length);
837
838         clone._stack = stackCopy;
839
840         // return clone.reset();
841
return clone;
842       }
843       catch (CloneNotSupportedException JavaDoc e)
844       {
845         throw new DTMException(XMLMessages.createXMLMessage(XMLErrorResources.ER_ITERATOR_CLONE_NOT_SUPPORTED, null)); //"Iterator clone not supported.");
846
}
847     }
848
849     /**
850      * Set start to END should 'close' the iterator,
851      * i.e. subsequent call to next() should return END.
852      *
853      * @param node Sets the root of the iteration.
854      *
855      * @return A DTMAxisIterator set to the start of the iteration.
856      */

857     public DTMAxisIterator setStartNode(int node)
858     {
859 //%HZ%: Added reference to DTMDefaultBase.ROOTNODE back in, temporarily
860
if (node == DTMDefaultBase.ROOTNODE)
861         node = getDocument();
862       if (_isRestartable)
863       {
864         node = makeNodeIdentity(node);
865
866         // iterator is not a clone
867
int parent, index;
868
869        if (_type2(node) == DTM.ATTRIBUTE_NODE)
870          node = _parent2(node);
871
872         _startNode = node;
873         _stack[index = 0] = node;
874         
875         parent=node;
876     while ((parent = _parent2(parent)) != NULL)
877     {
878       if (++index == _stack.length)
879       {
880         final int[] stack = new int[index*2];
881         System.arraycopy(_stack, 0, stack, 0, index);
882         _stack = stack;
883       }
884       _stack[index] = parent;
885         }
886         
887         if(index>0)
888       --index; // Pop actual root node (if not start) back off the stack
889

890         _currentNode=_stack[index]; // Last parent before root node
891

892         _oldsp = _sp = index;
893
894         return resetPosition();
895       }
896
897       return this;
898     }
899
900     /**
901      * Get the next node in the iteration.
902      *
903      * @return The next node handle in the iteration, or END.
904      */

905     public int next()
906     {
907         // Bugzilla 8324: We were forgetting to skip Attrs and NS nodes.
908
// Also recoded the loop controls for clarity and to flatten out
909
// the tail-recursion.
910
for(++_currentNode; _sp>=0; ++_currentNode)
911     {
912       if(_currentNode < _stack[_sp])
913       {
914         int type = _type2(_currentNode);
915         if(type != ATTRIBUTE_NODE && type != NAMESPACE_NODE)
916           return returnNode(makeNodeHandle(_currentNode));
917       }
918       else
919         --_sp;
920     }
921     return NULL;
922     }
923
924     // redefine DTMAxisIteratorBase's reset
925

926     /**
927      * Resets the iterator to the last start node.
928      *
929      * @return A DTMAxisIterator, which may or may not be the same as this
930      * iterator.
931      */

932     public DTMAxisIterator reset()
933     {
934
935       _sp = _oldsp;
936
937       return resetPosition();
938     }
939
940     public void setMark() {
941         _markedsp = _sp;
942         _markedNode = _currentNode;
943         _markedDescendant = _stack[0];
944     }
945
946     public void gotoMark() {
947         _sp = _markedsp;
948         _currentNode = _markedNode;
949     }
950   } // end of PrecedingIterator
951

952   /**
953    * Iterator that returns preceding nodes of agiven type for a
954    * given node. This includes the node set {root+1, start-1}, but
955    * excludes all ancestors.
956    */

957   public final class TypedPrecedingIterator extends PrecedingIterator
958   {
959
960     /** The extended type ID that was requested. */
961     private final int _nodeType;
962
963     /**
964      * Constructor TypedPrecedingIterator
965      *
966      *
967      * @param type The extended type ID being requested.
968      */

969     public TypedPrecedingIterator(int type)
970     {
971       _nodeType = type;
972     }
973
974     /**
975      * Get the next node in the iteration.
976      *
977      * @return The next node handle in the iteration, or END.
978      */

979     public int next()
980     {
981       int node = _currentNode;
982       final int nodeType = _nodeType;
983
984       if (nodeType >= DTM.NTYPES) {
985         while (true) {
986           node++;
987
988           if (_sp < 0) {
989             node = NULL;
990             break;
991           }
992           else if (node >= _stack[_sp]) {
993             if (--_sp < 0) {
994               node = NULL;
995               break;
996             }
997           }
998           else if (_exptype2(node) == nodeType) {
999             break;
1000          }
1001        }
1002      }
1003      else {
1004        int expType;
1005
1006        while (true) {
1007          node++;
1008
1009          if (_sp < 0) {
1010            node = NULL;
1011            break;
1012          }
1013          else if (node >= _stack[_sp]) {
1014            if (--_sp < 0) {
1015              node = NULL;
1016              break;
1017            }
1018          }
1019          else {
1020            expType = _exptype2(node);
1021            if (expType < DTM.NTYPES) {
1022              if (expType == nodeType) {
1023                break;
1024              }
1025            }
1026            else {
1027              if (m_extendedTypes[expType].getNodeType() == nodeType) {
1028                break;
1029              }
1030            }
1031          }
1032        }
1033      }
1034
1035      _currentNode = node;
1036             
1037      return (node == NULL) ? NULL : returnNode(makeNodeHandle(node));
1038    }
1039  } // end of TypedPrecedingIterator
1040

1041  /**
1042   * Iterator that returns following nodes of for a given node.
1043   */

1044  public class FollowingIterator extends InternalAxisIteratorBase
1045  {
1046    //DTMAxisTraverser m_traverser; // easier for now
1047

1048    public FollowingIterator()
1049    {
1050      //m_traverser = getAxisTraverser(Axis.FOLLOWING);
1051
}
1052
1053    /**
1054     * Set start to END should 'close' the iterator,
1055     * i.e. subsequent call to next() should return END.
1056     *
1057     * @param node Sets the root of the iteration.
1058     *
1059     * @return A DTMAxisIterator set to the start of the iteration.
1060     */

1061    public DTMAxisIterator setStartNode(int node)
1062    {
1063//%HZ%: Added reference to DTMDefaultBase.ROOTNODE back in, temporarily
1064
if (node == DTMDefaultBase.ROOTNODE)
1065        node = getDocument();
1066      if (_isRestartable)
1067      {
1068        _startNode = node;
1069
1070        //_currentNode = m_traverser.first(node);
1071

1072        node = makeNodeIdentity(node);
1073
1074        int first;
1075        int type = _type2(node);
1076
1077        if ((DTM.ATTRIBUTE_NODE == type) || (DTM.NAMESPACE_NODE == type))
1078        {
1079          node = _parent2(node);
1080          first = _firstch2(node);
1081
1082          if (NULL != first) {
1083            _currentNode = makeNodeHandle(first);
1084            return resetPosition();
1085          }
1086        }
1087
1088        do
1089        {
1090          first = _nextsib2(node);
1091
1092          if (NULL == first)
1093            node = _parent2(node);
1094        }
1095        while (NULL == first && NULL != node);
1096
1097        _currentNode = makeNodeHandle(first);
1098
1099        // _currentNode precedes possible following(node) nodes
1100
return resetPosition();
1101      }
1102
1103      return this;
1104    }
1105
1106    /**
1107     * Get the next node in the iteration.
1108     *
1109     * @return The next node handle in the iteration, or END.
1110     */

1111    public int next()
1112    {
1113
1114      int node = _currentNode;
1115
1116      //_currentNode = m_traverser.next(_startNode, _currentNode);
1117
int current = makeNodeIdentity(node);
1118
1119      while (true)
1120      {
1121        current++;
1122
1123        int type = _type2(current);
1124        if (NULL == type) {
1125          _currentNode = NULL;
1126          return returnNode(node);
1127        }
1128
1129        if (ATTRIBUTE_NODE == type || NAMESPACE_NODE == type)
1130          continue;
1131
1132        _currentNode = makeNodeHandle(current);
1133        return returnNode(node);
1134      }
1135    }
1136    
1137  } // end of FollowingIterator
1138

1139  /**
1140   * Iterator that returns following nodes of a given type for a given node.
1141   */

1142  public final class TypedFollowingIterator extends FollowingIterator
1143  {
1144
1145    /** The extended type ID that was requested. */
1146    private final int _nodeType;
1147
1148    /**
1149     * Constructor TypedFollowingIterator
1150     *
1151     *
1152     * @param type The extended type ID being requested.
1153     */

1154    public TypedFollowingIterator(int type)
1155    {
1156      _nodeType = type;
1157    }
1158
1159    /**
1160     * Get the next node in the iteration.
1161     *
1162     * @return The next node handle in the iteration, or END.
1163     */

1164    public int next()
1165    {
1166      int current;
1167      int node;
1168      int type;
1169
1170      final int nodeType = _nodeType;
1171      int currentNodeID = makeNodeIdentity(_currentNode);
1172      
1173      if (nodeType >= DTM.NTYPES) {
1174        do {
1175          node = currentNodeID;
1176      current = node;
1177
1178          do {
1179            current++;
1180            type = _type2(current);
1181          }
1182          while (type != NULL && (ATTRIBUTE_NODE == type || NAMESPACE_NODE == type));
1183        
1184          currentNodeID = (type != NULL) ? current : NULL;
1185        }
1186        while (node != DTM.NULL && _exptype2(node) != nodeType);
1187      }
1188      else {
1189        do {
1190          node = currentNodeID;
1191      current = node;
1192
1193          do {
1194            current++;
1195            type = _type2(current);
1196          }
1197          while (type != NULL && (ATTRIBUTE_NODE == type || NAMESPACE_NODE == type));
1198        
1199          currentNodeID = (type != NULL) ? current : NULL;
1200        }
1201        while (node != DTM.NULL
1202               && (_exptype2(node) != nodeType && _type2(node) != nodeType));
1203      }
1204
1205      _currentNode = makeNodeHandle(currentNodeID);
1206      return (node == DTM.NULL ? DTM.NULL :returnNode(makeNodeHandle(node)));
1207    }
1208  } // end of TypedFollowingIterator
1209

1210  /**
1211   * Iterator that returns the ancestors of a given node in document
1212   * order. (NOTE! This was changed from the XSLTC code!)
1213   */

1214  public class AncestorIterator extends InternalAxisIteratorBase
1215  {
1216    // The initial size of the ancestor array
1217
private static final int m_blocksize = 32;
1218    
1219    // The array for ancestor nodes. This array will grow dynamically.
1220
int[] m_ancestors = new int[m_blocksize];
1221    
1222    // Number of ancestor nodes in the array
1223
int m_size = 0;
1224    
1225    int m_ancestorsPos;
1226
1227    int m_markedPos;
1228    
1229    /** The real start node for this axes, since _startNode will be adjusted. */
1230    int m_realStartNode;
1231    
1232    /**
1233     * Get start to END should 'close' the iterator,
1234     * i.e. subsequent call to next() should return END.
1235     *
1236     * @return The root node of the iteration.
1237     */

1238    public int getStartNode()
1239    {
1240      return m_realStartNode;
1241    }
1242
1243    /**
1244     * True if this iterator has a reversed axis.
1245     *
1246     * @return true since this iterator is a reversed axis.
1247     */

1248    public final boolean isReverse()
1249    {
1250      return true;
1251    }
1252
1253    /**
1254     * Returns a deep copy of this iterator. The cloned iterator is not reset.
1255     *
1256     * @return a deep copy of this iterator.
1257     */

1258    public DTMAxisIterator cloneIterator()
1259    {
1260      _isRestartable = false; // must set to false for any clone
1261

1262      try
1263      {
1264        final AncestorIterator clone = (AncestorIterator) super.clone();
1265
1266        clone._startNode = _startNode;
1267
1268        // return clone.reset();
1269
return clone;
1270      }
1271      catch (CloneNotSupportedException JavaDoc e)
1272      {
1273        throw new DTMException(XMLMessages.createXMLMessage(XMLErrorResources.ER_ITERATOR_CLONE_NOT_SUPPORTED, null)); //"Iterator clone not supported.");
1274
}
1275    }
1276
1277    /**
1278     * Set start to END should 'close' the iterator,
1279     * i.e. subsequent call to next() should return END.
1280     *
1281     * @param node Sets the root of the iteration.
1282     *
1283     * @return A DTMAxisIterator set to the start of the iteration.
1284     */

1285    public DTMAxisIterator setStartNode(int node)
1286    {
1287//%HZ%: Added reference to DTMDefaultBase.ROOTNODE back in, temporarily
1288
if (node == DTMDefaultBase.ROOTNODE)
1289        node = getDocument();
1290      m_realStartNode = node;
1291
1292      if (_isRestartable)
1293      {
1294        int nodeID = makeNodeIdentity(node);
1295        m_size = 0;
1296        
1297        if (nodeID == DTM.NULL) {
1298          _currentNode = DTM.NULL;
1299          m_ancestorsPos = 0;
1300          return this;
1301        }
1302
1303        // Start from the current node's parent if
1304
// _includeSelf is false.
1305
if (!_includeSelf) {
1306          nodeID = _parent2(nodeID);
1307          node = makeNodeHandle(nodeID);
1308        }
1309
1310        _startNode = node;
1311
1312        while (nodeID != END) {
1313          //m_ancestors.addElement(node);
1314
if (m_size >= m_ancestors.length)
1315          {
1316            int[] newAncestors = new int[m_size * 2];
1317            System.arraycopy(m_ancestors, 0, newAncestors, 0, m_ancestors.length);
1318            m_ancestors = newAncestors;
1319          }
1320          
1321          m_ancestors[m_size++] = node;
1322          nodeID = _parent2(nodeID);
1323          node = makeNodeHandle(nodeID);
1324        }
1325        
1326        m_ancestorsPos = m_size - 1;
1327
1328        _currentNode = (m_ancestorsPos>=0)
1329                               ? m_ancestors[m_ancestorsPos]
1330                               : DTM.NULL;
1331
1332        return resetPosition();
1333      }
1334
1335      return this;
1336    }
1337
1338    /**
1339     * Resets the iterator to the last start node.
1340     *
1341     * @return A DTMAxisIterator, which may or may not be the same as this
1342     * iterator.
1343     */

1344    public DTMAxisIterator reset()
1345    {
1346
1347      m_ancestorsPos = m_size - 1;
1348
1349      _currentNode = (m_ancestorsPos >= 0) ? m_ancestors[m_ancestorsPos]
1350                                         : DTM.NULL;
1351
1352      return resetPosition();
1353    }
1354
1355    /**
1356     * Get the next node in the iteration.
1357     *
1358     * @return The next node handle in the iteration, or END.
1359     */

1360    public int next()
1361    {
1362
1363      int next = _currentNode;
1364      
1365      int pos = --m_ancestorsPos;
1366
1367      _currentNode = (pos >= 0) ? m_ancestors[m_ancestorsPos]
1368                                : DTM.NULL;
1369      
1370      return returnNode(next);
1371    }
1372
1373    public void setMark() {
1374        m_markedPos = m_ancestorsPos;
1375    }
1376
1377    public void gotoMark() {
1378        m_ancestorsPos = m_markedPos;
1379        _currentNode = m_ancestorsPos>=0 ? m_ancestors[m_ancestorsPos]
1380                                         : DTM.NULL;
1381    }
1382  } // end of AncestorIterator
1383

1384  /**
1385   * Typed iterator that returns the ancestors of a given node.
1386   */

1387  public final class TypedAncestorIterator extends AncestorIterator
1388  {
1389
1390    /** The extended type ID that was requested. */
1391    private final int _nodeType;
1392
1393    /**
1394     * Constructor TypedAncestorIterator
1395     *
1396     *
1397     * @param type The extended type ID being requested.
1398     */

1399    public TypedAncestorIterator(int type)
1400    {
1401      _nodeType = type;
1402    }
1403
1404    /**
1405     * Set start to END should 'close' the iterator,
1406     * i.e. subsequent call to next() should return END.
1407     *
1408     * @param node Sets the root of the iteration.
1409     *
1410     * @return A DTMAxisIterator set to the start of the iteration.
1411     */

1412    public DTMAxisIterator setStartNode(int node)
1413    {
1414//%HZ%: Added reference to DTMDefaultBase.ROOTNODE back in, temporarily
1415
if (node == DTMDefaultBase.ROOTNODE)
1416        node = getDocument();
1417      m_realStartNode = node;
1418
1419      if (_isRestartable)
1420      {
1421        int nodeID = makeNodeIdentity(node);
1422        m_size = 0;
1423        
1424        if (nodeID == DTM.NULL) {
1425          _currentNode = DTM.NULL;
1426          m_ancestorsPos = 0;
1427          return this;
1428        }
1429        
1430        final int nodeType = _nodeType;
1431
1432        if (!_includeSelf) {
1433          nodeID = _parent2(nodeID);
1434          node = makeNodeHandle(nodeID);
1435        }
1436
1437        _startNode = node;
1438
1439        if (nodeType >= DTM.NTYPES) {
1440          while (nodeID != END) {
1441            int eType = _exptype2(nodeID);
1442
1443            if (eType == nodeType) {
1444              if (m_size >= m_ancestors.length)
1445              {
1446                int[] newAncestors = new int[m_size * 2];
1447                System.arraycopy(m_ancestors, 0, newAncestors, 0, m_ancestors.length);
1448                m_ancestors = newAncestors;
1449              }
1450              m_ancestors[m_size++] = makeNodeHandle(nodeID);
1451            }
1452            nodeID = _parent2(nodeID);
1453          }
1454        }
1455        else {
1456          while (nodeID != END) {
1457            int eType = _exptype2(nodeID);
1458
1459            if ((eType < DTM.NTYPES && eType == nodeType)
1460                || (eType >= DTM.NTYPES
1461                    && m_extendedTypes[eType].getNodeType() == nodeType)) {
1462              if (m_size >= m_ancestors.length)
1463              {
1464                int[] newAncestors = new int[m_size * 2];
1465                System.arraycopy(m_ancestors, 0, newAncestors, 0, m_ancestors.length);
1466                m_ancestors = newAncestors;
1467              }
1468              m_ancestors[m_size++] = makeNodeHandle(nodeID);
1469            }
1470            nodeID = _parent2(nodeID);
1471          }
1472        }
1473        m_ancestorsPos = m_size - 1;
1474
1475        _currentNode = (m_ancestorsPos>=0)
1476                               ? m_ancestors[m_ancestorsPos]
1477                               : DTM.NULL;
1478
1479        return resetPosition();
1480      }
1481
1482      return this;
1483    }
1484
1485    /**
1486     * Return the node at the given position.
1487     */

1488    public int getNodeByPosition(int position)
1489    {
1490      if (position > 0 && position <= m_size) {
1491        return m_ancestors[position-1];
1492      }
1493      else
1494        return DTM.NULL;
1495    }
1496    
1497    /**
1498     * Returns the position of the last node within the iteration, as
1499     * defined by XPath.
1500     */

1501    public int getLast() {
1502      return m_size;
1503    }
1504  } // end of TypedAncestorIterator
1505

1506  /**
1507   * Iterator that returns the descendants of a given node.
1508   */

1509  public class DescendantIterator extends InternalAxisIteratorBase
1510  {
1511
1512    /**
1513     * Set start to END should 'close' the iterator,
1514     * i.e. subsequent call to next() should return END.
1515     *
1516     * @param node Sets the root of the iteration.
1517     *
1518     * @return A DTMAxisIterator set to the start of the iteration.
1519     */

1520    public DTMAxisIterator setStartNode(int node)
1521    {
1522//%HZ%: Added reference to DTMDefaultBase.ROOTNODE back in, temporarily
1523
if (node == DTMDefaultBase.ROOTNODE)
1524        node = getDocument();
1525      if (_isRestartable)
1526      {
1527        node = makeNodeIdentity(node);
1528        _startNode = node;
1529
1530        if (_includeSelf)
1531          node--;
1532
1533        _currentNode = node;
1534
1535        return resetPosition();
1536      }
1537
1538      return this;
1539    }
1540
1541    /**
1542     * Tell if this node identity is a descendant. Assumes that
1543     * the node info for the element has already been obtained.
1544     *
1545     * This one-sided test works only if the parent has been
1546     * previously tested and is known to be a descendent. It fails if
1547     * the parent is the _startNode's next sibling, or indeed any node
1548     * that follows _startNode in document order. That may suffice
1549     * for this iterator, but it's not really an isDescendent() test.
1550     * %REVIEW% rename?
1551     *
1552     * @param identity The index number of the node in question.
1553     * @return true if the index is a descendant of _startNode.
1554     */

1555    protected final boolean isDescendant(int identity)
1556    {
1557      return (_parent2(identity) >= _startNode) || (_startNode == identity);
1558    }
1559
1560    /**
1561     * Get the next node in the iteration.
1562     *
1563     * @return The next node handle in the iteration, or END.
1564     */

1565    public int next()
1566    {
1567      final int startNode = _startNode;
1568      if (startNode == NULL) {
1569        return NULL;
1570      }
1571
1572      if (_includeSelf && (_currentNode + 1) == startNode)
1573          return returnNode(makeNodeHandle(++_currentNode)); // | m_dtmIdent);
1574

1575      int node = _currentNode;
1576      int type;
1577
1578      // %OPT% If the startNode is the root node, do not need
1579
// to do the isDescendant() check.
1580
if (startNode == ROOTNODE) {
1581        int eType;
1582        do {
1583          node++;
1584          eType = _exptype2(node);
1585
1586          if (NULL == eType) {
1587            _currentNode = NULL;
1588            return END;
1589          }
1590        } while (eType == TEXT_NODE
1591                 || (type = m_extendedTypes[eType].getNodeType()) == ATTRIBUTE_NODE
1592                 || type == NAMESPACE_NODE);
1593      }
1594      else {
1595        do {
1596          node++;
1597          type = _type2(node);
1598
1599          if (NULL == type ||!isDescendant(node)) {
1600            _currentNode = NULL;
1601            return END;
1602          }
1603        } while(ATTRIBUTE_NODE == type || TEXT_NODE == type
1604                 || NAMESPACE_NODE == type);
1605      }
1606
1607      _currentNode = node;
1608      return returnNode(makeNodeHandle(node)); // make handle.
1609
}
1610  
1611    /**
1612     * Reset.
1613     *
1614     */

1615  public DTMAxisIterator reset()
1616  {
1617
1618    final boolean temp = _isRestartable;
1619
1620    _isRestartable = true;
1621
1622    setStartNode(makeNodeHandle(_startNode));
1623
1624    _isRestartable = temp;
1625
1626    return this;
1627  }
1628    
1629  } // end of DescendantIterator
1630

1631  /**
1632   * Typed iterator that returns the descendants of a given node.
1633   */

1634  public final class TypedDescendantIterator extends DescendantIterator
1635  {
1636
1637    /** The extended type ID that was requested. */
1638    private final int _nodeType;
1639
1640    /**
1641     * Constructor TypedDescendantIterator
1642     *
1643     *
1644     * @param nodeType Extended type ID being requested.
1645     */

1646    public TypedDescendantIterator(int nodeType)
1647    {
1648      _nodeType = nodeType;
1649    }
1650
1651    /**
1652     * Get the next node in the iteration.
1653     *
1654     * @return The next node handle in the iteration, or END.
1655     */

1656    public int next()
1657    {
1658      final int startNode = _startNode;
1659      if (_startNode == NULL) {
1660        return NULL;
1661      }
1662
1663      int node = _currentNode;
1664
1665      int expType;
1666      final int nodeType = _nodeType;
1667      
1668      if (nodeType != DTM.ELEMENT_NODE)
1669      {
1670        do
1671        {
1672          node++;
1673      expType = _exptype2(node);
1674
1675          if (NULL == expType || _parent2(node) < startNode && startNode != node) {
1676            _currentNode = NULL;
1677            return END;
1678          }
1679        }
1680        while (expType != nodeType);
1681      }
1682      // %OPT% If the start node is root (e.g. in the case of //node),
1683
// we can save the isDescendant() check, because all nodes are
1684
// descendants of root.
1685
else if (startNode == DTMDefaultBase.ROOTNODE)
1686      {
1687    do
1688    {
1689      node++;
1690      expType = _exptype2(node);
1691
1692      if (NULL == expType) {
1693        _currentNode = NULL;
1694        return END;
1695      }
1696    } while (expType < DTM.NTYPES
1697            || m_extendedTypes[expType].getNodeType() != DTM.ELEMENT_NODE);
1698      }
1699      else
1700      {
1701        do
1702        {
1703          node++;
1704      expType = _exptype2(node);
1705
1706          if (NULL == expType || _parent2(node) < startNode && startNode != node) {
1707            _currentNode = NULL;
1708            return END;
1709          }
1710        }
1711        while (expType < DTM.NTYPES
1712           || m_extendedTypes[expType].getNodeType() != DTM.ELEMENT_NODE);
1713      }
1714      
1715      _currentNode = node;
1716      return returnNode(makeNodeHandle(node));
1717    }
1718  } // end of TypedDescendantIterator
1719

1720  /**
1721   * Iterator that returns a given node only if it is of a given type.
1722   */

1723  public final class TypedSingletonIterator extends SingletonIterator
1724  {
1725
1726    /** The extended type ID that was requested. */
1727    private final int _nodeType;
1728
1729    /**
1730     * Constructor TypedSingletonIterator
1731     *
1732     *
1733     * @param nodeType The extended type ID being requested.
1734     */

1735    public TypedSingletonIterator(int nodeType)
1736    {
1737      _nodeType = nodeType;
1738    }
1739
1740    /**
1741     * Get the next node in the iteration.
1742     *
1743     * @return The next node handle in the iteration, or END.
1744     */

1745    public int next()
1746    {
1747
1748      final int result = _currentNode;
1749      if (result == END)
1750        return DTM.NULL;
1751      
1752      _currentNode = END;
1753
1754      if (_nodeType >= DTM.NTYPES) {
1755        if (_exptype2(makeNodeIdentity(result)) == _nodeType) {
1756          return returnNode(result);
1757        }
1758      }
1759      else {
1760        if (_type2(makeNodeIdentity(result)) == _nodeType) {
1761          return returnNode(result);
1762        }
1763      }
1764
1765      return NULL;
1766    }
1767  } // end of TypedSingletonIterator
1768

1769  /*******************************************************************
1770   * End of nested iterators
1771   *******************************************************************/

1772
1773
1774  // %OPT% Array references which are used to cache the map0 arrays in
1775
// SuballocatedIntVectors. Using the cached arrays reduces the level
1776
// of indirection and results in better performance than just calling
1777
// SuballocatedIntVector.elementAt().
1778
private int[] m_exptype_map0;
1779  private int[] m_nextsib_map0;
1780  private int[] m_firstch_map0;
1781  private int[] m_parent_map0;
1782  
1783  // Double array references to the map arrays in SuballocatedIntVectors.
1784
private int[][] m_exptype_map;
1785  private int[][] m_nextsib_map;
1786  private int[][] m_firstch_map;
1787  private int[][] m_parent_map;
1788
1789  // %OPT% Cache the array of extended types in this class
1790
protected ExtendedType[] m_extendedTypes;
1791  
1792  // A Vector which is used to store the values of attribute, namespace,
1793
// comment and PI nodes.
1794
//
1795
// %OPT% These values are unlikely to be equal. Storing
1796
// them in a plain Vector is more efficient than storing in the
1797
// DTMStringPool because we can save the cost for hash calculation.
1798
//
1799
// %REVISIT% Do we need a custom class (e.g. StringVector) here?
1800
protected Vector JavaDoc m_values;
1801  
1802  // The current index into the m_values Vector.
1803
private int m_valueIndex = 0;
1804  
1805  // The maximum value of the current node index.
1806
private int m_maxNodeIndex;
1807  
1808  // Cache the shift and mask values for the SuballocatedIntVectors.
1809
protected int m_SHIFT;
1810  protected int m_MASK;
1811  protected int m_blocksize;
1812  
1813  /** %OPT% If the offset and length of a Text node are within certain limits,
1814   * we store a bitwise encoded value into an int, using 10 bits (max. 1024)
1815   * for length and 21 bits for offset. We can save two SuballocatedIntVector
1816   * calls for each getStringValueX() and dispatchCharacterEvents() call by
1817   * doing this.
1818   */

1819  // The number of bits for the length of a Text node.
1820
protected final static int TEXT_LENGTH_BITS = 10;
1821  
1822  // The number of bits for the offset of a Text node.
1823
protected final static int TEXT_OFFSET_BITS = 21;
1824  
1825  // The maximum length value
1826
protected final static int TEXT_LENGTH_MAX = (1<<TEXT_LENGTH_BITS) - 1;
1827  
1828  // The maximum offset value
1829
protected final static int TEXT_OFFSET_MAX = (1<<TEXT_OFFSET_BITS) - 1;
1830  
1831  // True if we want to build the ID index table.
1832
protected boolean m_buildIdIndex = true;
1833      
1834  // Constant for empty String
1835
private static final String JavaDoc EMPTY_STR = "";
1836  
1837  // Constant for empty XMLString
1838
private static final XMLString EMPTY_XML_STR = new XMLStringDefault("");
1839
1840  /**
1841   * Construct a SAX2DTM2 object using the default block size.
1842   */

1843  public SAX2DTM2(DTMManager mgr, Source JavaDoc source, int dtmIdentity,
1844                 DTMWSFilter whiteSpaceFilter,
1845                 XMLStringFactory xstringfactory,
1846                 boolean doIndexing)
1847  {
1848
1849    this(mgr, source, dtmIdentity, whiteSpaceFilter,
1850          xstringfactory, doIndexing, DEFAULT_BLOCKSIZE, true, true, false);
1851  }
1852 
1853  /**
1854   * Construct a SAX2DTM2 object using the given block size.
1855   */

1856  public SAX2DTM2(DTMManager mgr, Source JavaDoc source, int dtmIdentity,
1857                 DTMWSFilter whiteSpaceFilter,
1858                 XMLStringFactory xstringfactory,
1859                 boolean doIndexing,
1860                 int blocksize,
1861                 boolean usePrevsib,
1862                 boolean buildIdIndex,
1863                 boolean newNameTable)
1864  {
1865
1866    super(mgr, source, dtmIdentity, whiteSpaceFilter,
1867          xstringfactory, doIndexing, blocksize, usePrevsib, newNameTable);
1868        
1869    // Initialize the values of m_SHIFT and m_MASK.
1870
int shift;
1871    for(shift=0; (blocksize>>>=1) != 0; ++shift);
1872    
1873    m_blocksize = 1<<shift;
1874    m_SHIFT = shift;
1875    m_MASK = m_blocksize - 1;
1876    
1877    m_buildIdIndex = buildIdIndex;
1878    
1879    // Some documents do not have attribute nodes. That is why
1880
// we set the initial size of this Vector to be small and set
1881
// the increment to a bigger number.
1882
m_values = new Vector JavaDoc(32, 512);
1883    
1884    m_maxNodeIndex = 1 << DTMManager.IDENT_DTM_NODE_BITS;
1885    
1886    // Set the map0 values in the constructor.
1887
m_exptype_map0 = m_exptype.getMap0();
1888    m_nextsib_map0 = m_nextsib.getMap0();
1889    m_firstch_map0 = m_firstch.getMap0();
1890    m_parent_map0 = m_parent.getMap0();
1891  }
1892  
1893  /**
1894   * Override DTMDefaultBase._exptype() by dropping the incremental code.
1895   *
1896   * <p>This one is less efficient than _exptype2. It is only used during
1897   * DTM building. _exptype2 is used after the document is fully built.
1898   */

1899  public final int _exptype(int identity)
1900  {
1901    return m_exptype.elementAt(identity);
1902  }
1903
1904  /************************************************************************
1905   * DTM base accessor interfaces
1906   *
1907   * %OPT% The code in the following interfaces (e.g. _exptype2, etc.) are
1908   * very important to the DTM performance. To have the best performace,
1909   * these several interfaces have direct access to the internal arrays of
1910   * the SuballocatedIntVectors. The final modifier also has a noticeable
1911   * impact on performance.
1912   ***********************************************************************/

1913 
1914  /**
1915   * The optimized version of DTMDefaultBase._exptype().
1916   *
1917   * @param identity A node identity, which <em>must not</em> be equal to
1918   * <code>DTM.NULL</code>
1919   */

1920  public final int _exptype2(int identity)
1921  {
1922    //return m_exptype.elementAt(identity);
1923

1924    if (identity < m_blocksize)
1925      return m_exptype_map0[identity];
1926    else
1927      return m_exptype_map[identity>>>m_SHIFT][identity&m_MASK];
1928  }
1929  
1930  /**
1931   * The optimized version of DTMDefaultBase._nextsib().
1932   *
1933   * @param identity A node identity, which <em>must not</em> be equal to
1934   * <code>DTM.NULL</code>
1935   */

1936  public final int _nextsib2(int identity)
1937  {
1938    //return m_nextsib.elementAt(identity);
1939

1940    if (identity < m_blocksize)
1941      return m_nextsib_map0[identity];
1942    else
1943      return m_nextsib_map[identity>>>m_SHIFT][identity&m_MASK];
1944  }
1945  
1946  /**
1947   * The optimized version of DTMDefaultBase._firstch().
1948   *
1949   * @param identity A node identity, which <em>must not</em> be equal to
1950   * <code>DTM.NULL</code>
1951   */

1952  public final int _firstch2(int identity)
1953  {
1954    //return m_firstch.elementAt(identity);
1955

1956    if (identity < m_blocksize)
1957      return m_firstch_map0[identity];
1958    else
1959      return m_firstch_map[identity>>>m_SHIFT][identity&m_MASK];
1960  }
1961  
1962  /**
1963   * The optimized version of DTMDefaultBase._parent().
1964   *
1965   * @param identity A node identity, which <em>must not</em> be equal to
1966   * <code>DTM.NULL</code>
1967   */

1968  public final int _parent2(int identity)
1969  {
1970    //return m_parent.elementAt(identity);
1971

1972    if (identity < m_blocksize)
1973      return m_parent_map0[identity];
1974    else
1975      return m_parent_map[identity>>>m_SHIFT][identity&m_MASK];
1976  }
1977  
1978  /**
1979   * The optimized version of DTMDefaultBase._type().
1980   *
1981   * @param identity A node identity, which <em>must not</em> be equal to
1982   * <code>DTM.NULL</code>
1983   */

1984  public final int _type2(int identity)
1985  {
1986    //int eType = _exptype2(identity);
1987
int eType;
1988    if (identity < m_blocksize)
1989      eType = m_exptype_map0[identity];
1990    else
1991      eType = m_exptype_map[identity>>>m_SHIFT][identity&m_MASK];
1992    
1993    if (NULL != eType)
1994      return m_extendedTypes[eType].getNodeType();
1995    else
1996      return NULL;
1997  }
1998    
1999  /**
2000   * The optimized version of DTMDefaultBase.getExpandedTypeID(int).
2001   *
2002   * <p>This one is only used by DOMAdapter.getExpandedTypeID(int), which
2003   * is mostly called from the compiled translets.
2004   */

2005  public final int getExpandedTypeID2(int nodeHandle)
2006  {
2007    int nodeID = makeNodeIdentity(nodeHandle);
2008    
2009    //return (nodeID != NULL) ? _exptype2(nodeID) : NULL;
2010

2011    if (nodeID != NULL) {
2012      if (nodeID < m_blocksize)
2013        return m_exptype_map0[nodeID];
2014      else
2015        return m_exptype_map[nodeID>>>m_SHIFT][nodeID&m_MASK];
2016    }
2017    else
2018      return NULL;
2019  }
2020  
2021  /*************************************************************************
2022   * END of DTM base accessor interfaces
2023   *************************************************************************/

2024   
2025
2026  /**
2027   * Return the node type from the expanded type
2028   */

2029  public final int _exptype2Type(int exptype)
2030  {
2031    if (NULL != exptype)
2032      return m_extendedTypes[exptype].getNodeType();
2033    else
2034      return NULL;
2035  }
2036
2037  /**
2038   * Get a prefix either from the uri mapping, or just make
2039   * one up!
2040   *
2041   * @param uri The namespace URI, which may be null.
2042   *
2043   * @return The prefix if there is one, or null.
2044   */

2045  public int getIdForNamespace(String JavaDoc uri)
2046  {
2047     int index = m_values.indexOf(uri);
2048     if (index < 0)
2049     {
2050       m_values.addElement(uri);
2051       return m_valueIndex++;
2052     }
2053     else
2054       return index;
2055  }
2056
2057  /**
2058   * Override SAX2DTM.startElement()
2059   *
2060   * <p>Receive notification of the start of an element.
2061   *
2062   * <p>By default, do nothing. Application writers may override this
2063   * method in a subclass to take specific actions at the start of
2064   * each element (such as allocating a new tree node or writing
2065   * output to a file).</p>
2066   *
2067   * @param name The element type name.
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 JavaDoc uri, String JavaDoc localName, String JavaDoc 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 JavaDoc prefix;
2104
2105    if(!m_pastFirstElement)
2106    {
2107      // SPECIAL CASE: Implied declaration at root element
2108
prefix="xml";
2109      String JavaDoc 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 JavaDoc) m_prefixMappings.elementAt(i);
2121
2122      if (prefix == null)
2123        continue;
2124
2125      String JavaDoc declURL = (String JavaDoc) 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 JavaDoc attrUri = attributes.getURI(i);
2140      String JavaDoc attrQName = attributes.getQName(i);
2141      String JavaDoc valString = attributes.getValue(i);
2142
2143      int nodeType;
2144      
2145      String JavaDoc 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 name The element type name.
2215   * @param attributes The specified or defaulted attributes.
2216   *
2217   * @param uri The Namespace URI, or the empty string if the
2218   * element has no Namespace URI or if Namespace
2219   * processing is not being performed.
2220   * @param localName The local name (without prefix), or the
2221   * empty string if Namespace processing is not being
2222   * performed.
2223   * @param qName The qualified XML 1.0 name (with prefix), or the
2224   * empty string if qualified names are not available.
2225   * @throws SAXException Any SAX exception, possibly
2226   * wrapping another exception.
2227   * @see org.xml.sax.ContentHandler#endElement
2228   */

2229  public void endElement(String JavaDoc uri, String JavaDoc localName, String JavaDoc qName)
2230          throws SAXException
2231  {
2232    charactersFlush();
2233
2234    // If no one noticed, startPrefixMapping is a drag.
2235
// Pop the context for the last child (the one pushed by startElement)
2236
m_contextIndexes.quickPop(1);
2237
2238    // Do it again for this one (the one pushed by the last endElement).
2239
int topContextIndex = m_contextIndexes.peek();
2240    if (topContextIndex != m_prefixMappings.size()) {
2241      m_prefixMappings.setSize(topContextIndex);
2242    }
2243
2244    m_previous = m_parents.pop();
2245
2246    popShouldStripWhitespace();
2247  }
2248
2249  /**
2250   * Report an XML comment anywhere in the document.
2251   *
2252   * <p>This callback will be used for comments inside or outside the
2253   * document element, including comments in the external DTD
2254   * subset (if read).</p>
2255   *
2256   * @param ch An array holding the characters in the comment.
2257   * @param start The starting position in the array.
2258   * @param length The number of characters to use from the array.
2259   * @throws SAXException The application may raise an exception.
2260   */

2261  public void comment(char ch[], int start, int length) throws SAXException
2262  {
2263
2264    if (m_insideDTD) // ignore comments if we're inside the DTD
2265
return;
2266
2267    charactersFlush();
2268
2269    // %OPT% Saving the comment string in a Vector has a lower cost than
2270
// saving it in DTMStringPool.
2271
m_values.addElement(new String JavaDoc(ch, start, length));
2272    int dataIndex = m_valueIndex++;
2273
2274    m_previous = addNode(DTM.COMMENT_NODE, DTM.COMMENT_NODE,
2275                         m_parents.peek(), m_previous, dataIndex, false);
2276  }
2277
2278  /**
2279   * Receive notification of the beginning of the document.
2280   *
2281   * @throws SAXException Any SAX exception, possibly
2282   * wrapping another exception.
2283   * @see org.xml.sax.ContentHandler#startDocument
2284   */

2285  public void startDocument() throws SAXException
2286  {
2287        
2288    int doc = addNode(DTM.DOCUMENT_NODE,
2289                      DTM.DOCUMENT_NODE,
2290                      DTM.NULL, DTM.NULL, 0, true);
2291
2292    m_parents.push(doc);
2293    m_previous = DTM.NULL;
2294
2295    m_contextIndexes.push(m_prefixMappings.size()); // for the next element.
2296
}
2297  
2298  /**
2299   * Receive notification of the end of the document.
2300   *
2301   * @throws SAXException Any SAX exception, possibly
2302   * wrapping another exception.
2303   * @see org.xml.sax.ContentHandler#endDocument
2304   */

2305  public void endDocument() throws SAXException
2306  {
2307    super.endDocument();
2308        
2309    // Add a NULL entry to the end of the node arrays as
2310
// the end indication.
2311
m_exptype.addElement(NULL);
2312    m_parent.addElement(NULL);
2313    m_nextsib.addElement(NULL);
2314    m_firstch.addElement(NULL);
2315    
2316    // Set the cached references after the document is built.
2317
m_extendedTypes = m_expandedNameTable.getExtendedTypes();
2318    m_exptype_map = m_exptype.getMap();
2319    m_nextsib_map = m_nextsib.getMap();
2320    m_firstch_map = m_firstch.getMap();
2321    m_parent_map = m_parent.getMap();
2322  }
2323
2324  /**
2325   * Construct the node map from the node.
2326   *
2327   * @param type raw type ID, one of DTM.XXX_NODE.
2328   * @param expandedTypeID The expended type ID.
2329   * @param parentIndex The current parent index.
2330   * @param previousSibling The previous sibling index.
2331   * @param dataOrPrefix index into m_data table, or string handle.
2332   * @param canHaveFirstChild true if the node can have a first child, false
2333   * if it is atomic.
2334   *
2335   * @return The index identity of the node that was added.
2336   */

2337  protected final int addNode(int type, int expandedTypeID,
2338                        int parentIndex, int previousSibling,
2339                        int dataOrPrefix, boolean canHaveFirstChild)
2340  {
2341    // Common to all nodes:
2342
int nodeIndex = m_size++;
2343
2344    // Have we overflowed a DTM Identity's addressing range?
2345
//if(m_dtmIdent.size() == (nodeIndex>>>DTMManager.IDENT_DTM_NODE_BITS))
2346
if (nodeIndex == m_maxNodeIndex)
2347    {
2348      addNewDTMID(nodeIndex);
2349      m_maxNodeIndex += (1 << DTMManager.IDENT_DTM_NODE_BITS);
2350    }
2351
2352    m_firstch.addElement(DTM.NULL);
2353    m_nextsib.addElement(DTM.NULL);
2354    m_parent.addElement(parentIndex);
2355    m_exptype.addElement(expandedTypeID);
2356    m_dataOrQName.addElement(dataOrPrefix);
2357
2358    if (m_prevsib != null) {
2359      m_prevsib.addElement(previousSibling);
2360    }
2361
2362    if (m_locator != null && m_useSourceLocationProperty) {
2363      setSourceLocation();
2364    }
2365
2366    // Note that nextSibling is not processed until charactersFlush()
2367
// is called, to handle successive characters() events.
2368

2369    // Special handling by type: Declare namespaces, attach first child
2370
switch(type)
2371    {
2372    case DTM.NAMESPACE_NODE:
2373      declareNamespaceInContext(parentIndex,nodeIndex);
2374      break;
2375    case DTM.ATTRIBUTE_NODE:
2376      break;
2377    default:
2378      if (DTM.NULL != previousSibling) {
2379        m_nextsib.setElementAt(nodeIndex,previousSibling);
2380      }
2381      else if (DTM.NULL != parentIndex) {
2382        m_firstch.setElementAt(nodeIndex,parentIndex);
2383      }
2384      break;
2385    }
2386
2387    return nodeIndex;
2388  }
2389
2390  /**
2391   * Check whether accumulated text should be stripped; if not,
2392   * append the appropriate flavor of text/cdata node.
2393   */

2394  protected final void charactersFlush()
2395  {
2396
2397    if (m_textPendingStart >= 0) // -1 indicates no-text-in-progress
2398
{
2399      int length = m_chars.size() - m_textPendingStart;
2400      boolean doStrip = false;
2401
2402      if (getShouldStripWhitespace())
2403      {
2404        doStrip = m_chars.isWhitespace(m_textPendingStart, length);
2405      }
2406
2407      if (doStrip)
2408        m_chars.setLength(m_textPendingStart); // Discard accumulated text
2409
else
2410      {
2411        // If the offset and length do not exceed the given limits
2412
// (offset < 2^21 and length < 2^10), then save both the offset
2413
// and length in a bitwise encoded value.
2414
if (length <= TEXT_LENGTH_MAX && m_textPendingStart <= TEXT_OFFSET_MAX)
2415        {
2416          m_previous = addNode(m_coalescedTextType, DTM.TEXT_NODE,
2417                             m_parents.peek(), m_previous,
2418                             length + (m_textPendingStart << TEXT_LENGTH_BITS),
2419                             false);
2420          
2421        }
2422        else
2423        {
2424          // Store the offset and length in the m_data array if one of them
2425
// exceeds the given limits. Use a negative dataIndex as an indication.
2426
int dataIndex = m_data.size();
2427          m_previous = addNode(m_coalescedTextType, DTM.TEXT_NODE,
2428                             m_parents.peek(), m_previous, -dataIndex, false);
2429
2430          m_data.addElement(m_textPendingStart);
2431          m_data.addElement(length);
2432        }
2433      }
2434
2435      // Reset for next text block
2436
m_textPendingStart = -1;
2437      m_textType = m_coalescedTextType = DTM.TEXT_NODE;
2438    }
2439  }
2440
2441  /**
2442   * Override the processingInstruction() interface in SAX2DTM2.
2443   * <p>
2444   * %OPT% This one is different from SAX2DTM.processingInstruction()
2445   * in that we do not use extended types for PI nodes. The name of
2446   * the PI is saved in the DTMStringPool.
2447   *
2448   * Receive notification of a processing instruction.
2449   *
2450   * @param target The processing instruction target.
2451   * @param data The processing instruction data, or null if
2452   * none is supplied.
2453   * @throws SAXException Any SAX exception, possibly
2454   * wrapping another exception.
2455   * @see org.xml.sax.ContentHandler#processingInstruction
2456   */

2457  public void processingInstruction(String JavaDoc target, String JavaDoc data)
2458      throws SAXException
2459  {
2460
2461    charactersFlush();
2462
2463    int dataIndex = m_data.size();
2464    m_previous = addNode(DTM.PROCESSING_INSTRUCTION_NODE,
2465             DTM.PROCESSING_INSTRUCTION_NODE,
2466             m_parents.peek(), m_previous,
2467             -dataIndex, false);
2468
2469    m_data.addElement(m_valuesOrPrefixes.stringToIndex(target));
2470    m_values.addElement(data);
2471    m_data.addElement(m_valueIndex++);
2472
2473  }
2474
2475  /**
2476   * The optimized version of DTMDefaultBase.getFirstAttribute().
2477   * <p>
2478   * Given a node handle, get the index of the node's first attribute.
2479   *
2480   * @param nodeHandle int Handle of the node.
2481   * @return Handle of first attribute, or DTM.NULL to indicate none exists.
2482   */

2483  public final int getFirstAttribute(int nodeHandle)
2484  {
2485    int nodeID = makeNodeIdentity(nodeHandle);
2486
2487    if (nodeID == DTM.NULL)
2488      return DTM.NULL;
2489    
2490    int type = _type2(nodeID);
2491
2492    if (DTM.ELEMENT_NODE == type)
2493    {
2494      // Assume that attributes and namespaces immediately follow the element.
2495
while (true)
2496      {
2497        nodeID++;
2498    // Assume this can not be null.
2499
type = _type2(nodeID);
2500
2501    if (type == DTM.ATTRIBUTE_NODE)
2502    {
2503      return makeNodeHandle(nodeID);
2504    }
2505    else if (DTM.NAMESPACE_NODE != type)
2506    {
2507      break;
2508    }
2509      }
2510    }
2511
2512    return DTM.NULL;
2513  }
2514
2515  /**
2516   * The optimized version of DTMDefaultBase.getFirstAttributeIdentity(int).
2517   * <p>
2518   * Given a node identity, get the index of the node's first attribute.
2519   *
2520   * @param identity int identity of the node.
2521   * @return Identity of first attribute, or DTM.NULL to indicate none exists.
2522   */

2523  protected int getFirstAttributeIdentity(int identity) {
2524    if (identity == NULL) {
2525        return NULL;
2526    }
2527    int type = _type2(identity);
2528
2529    if (DTM.ELEMENT_NODE == type)
2530    {
2531      // Assume that attributes and namespaces immediately follow the element.
2532
while (true)
2533      {
2534        identity++;
2535
2536        // Assume this can not be null.
2537
type = _type2(identity);
2538
2539        if (type == DTM.ATTRIBUTE_NODE)
2540        {
2541          return identity;
2542        }
2543        else if (DTM.NAMESPACE_NODE != type)
2544        {
2545          break;
2546        }
2547      }
2548    }
2549
2550    return DTM.NULL;
2551  }
2552
2553  /**
2554   * The optimized version of DTMDefaultBase.getNextAttributeIdentity(int).
2555   * <p>
2556   * Given a node identity for an attribute, advance to the next attribute.
2557   *
2558   * @param identity int identity of the attribute node. This
2559   * <strong>must</strong> be an attribute node.
2560   *
2561   * @return int DTM node-identity of the resolved attr,
2562   * or DTM.NULL to indicate none exists.
2563   *
2564   */

2565  protected int getNextAttributeIdentity(int identity) {
2566    // Assume that attributes and namespace nodes immediately follow the element
2567
while (true) {
2568      identity++;
2569      int type = _type2(identity);
2570
2571      if (type == DTM.ATTRIBUTE_NODE) {
2572        return identity;
2573      } else if (type != DTM.NAMESPACE_NODE) {
2574        break;
2575      }
2576    }
2577
2578    return DTM.NULL;
2579  }
2580
2581  /**
2582   * The optimized version of DTMDefaultBase.getTypedAttribute(int, int).
2583   * <p>
2584   * Given a node handle and an expanded type ID, get the index of the node's
2585   * attribute of that type, if any.
2586   *
2587   * @param nodeHandle int Handle of the node.
2588   * @param attType int expanded type ID of the required attribute.
2589   * @return Handle of attribute of the required type, or DTM.NULL to indicate
2590   * none exists.
2591   */

2592  protected final int getTypedAttribute(int nodeHandle, int attType)
2593  {
2594          
2595    int nodeID = makeNodeIdentity(nodeHandle);
2596    
2597    if (nodeID == DTM.NULL)
2598      return DTM.NULL;
2599    
2600    int type = _type2(nodeID);
2601    
2602    if (DTM.ELEMENT_NODE == type)
2603    {
2604      int expType;
2605      while (true)
2606      {
2607    nodeID++;
2608    expType = _exptype2(nodeID);
2609    
2610    if (expType != DTM.NULL)
2611      type = m_extendedTypes[expType].getNodeType();
2612    else
2613      return DTM.NULL;
2614
2615    if (type == DTM.ATTRIBUTE_NODE)
2616    {
2617      if (expType == attType) return makeNodeHandle(nodeID);
2618    }
2619    else if (DTM.NAMESPACE_NODE != type)
2620    {
2621      break;
2622    }
2623      }
2624    }
2625
2626    return DTM.NULL;
2627  }
2628
2629  /**
2630   * Override SAX2DTM.getLocalName() in SAX2DTM2.
2631   * <p>Processing for PIs is different.
2632   *
2633   * Given a node handle, return its XPath- style localname. (As defined in
2634   * Namespaces, this is the portion of the name after any colon character).
2635   *
2636   * @param nodeHandle the id of the node.
2637   * @return String Local name of this node.
2638   */

2639  public String JavaDoc getLocalName(int nodeHandle)
2640  {
2641    int expType = _exptype(makeNodeIdentity(nodeHandle));
2642    
2643    if (expType == DTM.PROCESSING_INSTRUCTION_NODE)
2644    {
2645      int dataIndex = _dataOrQName(makeNodeIdentity(nodeHandle));
2646      dataIndex = m_data.elementAt(-dataIndex);
2647      return m_valuesOrPrefixes.indexToString(dataIndex);
2648    }
2649    else
2650      return m_expandedNameTable.getLocalName(expType);
2651  }
2652
2653  /**
2654   * The optimized version of SAX2DTM.getNodeNameX().
2655   * <p>
2656   * Given a node handle, return the XPath node name. This should be the name
2657   * as described by the XPath data model, NOT the DOM- style name.
2658   *
2659   * @param nodeHandle the id of the node.
2660   * @return String Name of this node, which may be an empty string.
2661   */

2662  public final String JavaDoc getNodeNameX(int nodeHandle)
2663  {
2664
2665    int nodeID = makeNodeIdentity(nodeHandle);
2666    int eType = _exptype2(nodeID);
2667    
2668    if (eType == DTM.PROCESSING_INSTRUCTION_NODE)
2669    {
2670      int dataIndex = _dataOrQName(nodeID);
2671      dataIndex = m_data.elementAt(-dataIndex);
2672      return m_valuesOrPrefixes.indexToString(dataIndex);
2673    }
2674    
2675    final ExtendedType extType = m_extendedTypes[eType];
2676                         
2677    if (extType.getNamespace().length() == 0)
2678    {
2679      return extType.getLocalName();
2680    }
2681    else
2682    {
2683      int qnameIndex = m_dataOrQName.elementAt(nodeID);
2684
2685      if (qnameIndex == 0)
2686        return extType.getLocalName();
2687      
2688      if (qnameIndex < 0)
2689      {
2690    qnameIndex = -qnameIndex;
2691    qnameIndex = m_data.elementAt(qnameIndex);
2692      }
2693
2694      return m_valuesOrPrefixes.indexToString(qnameIndex);
2695    }
2696  }
2697
2698  /**
2699   * The optimized version of SAX2DTM.getNodeName().
2700   * <p>
2701   * Given a node handle, return its DOM-style node name. This will include
2702   * names such as #text or #document.
2703   *
2704   * @param nodeHandle the id of the node.
2705   * @return String Name of this node, which may be an empty string.
2706   * %REVIEW% Document when empty string is possible...
2707   * %REVIEW-COMMENT% It should never be empty, should it?
2708   */

2709  public String JavaDoc getNodeName(int nodeHandle)
2710  {
2711
2712    int nodeID = makeNodeIdentity(nodeHandle);
2713    int eType = _exptype2(nodeID);
2714
2715    final ExtendedType extType = m_extendedTypes[eType];
2716    if (extType.getNamespace().length() == 0)
2717    {
2718      int type = extType.getNodeType();
2719      
2720      String JavaDoc localName = extType.getLocalName();
2721      if (type == DTM.NAMESPACE_NODE)
2722      {
2723    if (localName.length() == 0)
2724      return "xmlns";
2725    else
2726      return "xmlns:" + localName;
2727      }
2728      else if (type == DTM.PROCESSING_INSTRUCTION_NODE)
2729      {
2730    int dataIndex = _dataOrQName(nodeID);
2731    dataIndex = m_data.elementAt(-dataIndex);
2732    return m_valuesOrPrefixes.indexToString(dataIndex);
2733      }
2734      else if (localName.length() == 0)
2735      {
2736    return m_fixednames[type];
2737      }
2738      else
2739    return localName;
2740    }
2741    else
2742    {
2743      int qnameIndex = m_dataOrQName.elementAt(nodeID);
2744
2745      if (qnameIndex == 0)
2746        return extType.getLocalName();
2747      
2748      if (qnameIndex < 0)
2749      {
2750    qnameIndex = -qnameIndex;
2751    qnameIndex = m_data.elementAt(qnameIndex);
2752      }
2753
2754      return m_valuesOrPrefixes.indexToString(qnameIndex);
2755    }
2756  }
2757
2758  /**
2759   * Override SAX2DTM.getStringValue(int)
2760   * <p>
2761   * This method is only used by Xalan-J Interpretive. It is not used by XSLTC.
2762   * <p>
2763   * If the caller supplies an XMLStringFactory, the getStringValue() interface
2764   * in SAX2DTM will be called. Otherwise just calls getStringValueX() and
2765   * wraps the returned String in an XMLString.
2766   *
2767   * Get the string-value of a node as a String object
2768   * (see http://www.w3.org/TR/xpath#data-model
2769   * for the definition of a node's string-value).
2770   *
2771   * @param nodeHandle The node ID.
2772   *
2773   * @return A string object that represents the string-value of the given node.
2774   */

2775  public XMLString getStringValue(int nodeHandle)
2776  {
2777    int identity = makeNodeIdentity(nodeHandle);
2778    if (identity == DTM.NULL)
2779      return EMPTY_XML_STR;
2780    
2781    int type= _type2(identity);
2782
2783    if (type == DTM.ELEMENT_NODE || type == DTM.DOCUMENT_NODE)
2784    {
2785      int startNode = identity;
2786      identity = _firstch2(identity);
2787      if (DTM.NULL != identity)
2788      {
2789    int offset = -1;
2790    int length = 0;
2791
2792    do
2793    {
2794      type = _exptype2(identity);
2795
2796      if (type == DTM.TEXT_NODE || type == DTM.CDATA_SECTION_NODE)
2797      {
2798        int dataIndex = m_dataOrQName.elementAt(identity);
2799        if (dataIndex > 0)
2800        {
2801          if (-1 == offset)
2802          {
2803                offset = dataIndex >>> TEXT_LENGTH_BITS;
2804          }
2805
2806          length += dataIndex & TEXT_LENGTH_MAX;
2807        }
2808        else
2809        {
2810          if (-1 == offset)
2811          {
2812                offset = m_data.elementAt(-dataIndex);
2813          }
2814
2815          length += m_data.elementAt(-dataIndex + 1);
2816        }
2817      }
2818
2819      identity++;
2820    } while (_parent2(identity) >= startNode);
2821
2822    if (length > 0)
2823    {
2824      if (m_xstrf != null)
2825        return m_xstrf.newstr(m_chars, offset, length);
2826      else
2827        return new XMLStringDefault(m_chars.getString(offset, length));
2828    }
2829    else
2830      return EMPTY_XML_STR;
2831      }
2832      else
2833        return EMPTY_XML_STR;
2834    }
2835    else if (DTM.TEXT_NODE == type || DTM.CDATA_SECTION_NODE == type)
2836    {
2837      int dataIndex = m_dataOrQName.elementAt(identity);
2838      if (dataIndex > 0)
2839      {
2840        if (m_xstrf != null)
2841          return m_xstrf.newstr(m_chars, dataIndex >>> TEXT_LENGTH_BITS,
2842                         dataIndex & TEXT_LENGTH_MAX);
2843        else
2844          return new XMLStringDefault(m_chars.getString(dataIndex >>> TEXT_LENGTH_BITS,
2845                                      dataIndex & TEXT_LENGTH_MAX));
2846      }
2847      else
2848      {
2849        if (m_xstrf != null)
2850          return m_xstrf.newstr(m_chars, m_data.elementAt(-dataIndex),
2851                                m_data.elementAt(-dataIndex+1));
2852        else
2853          return new XMLStringDefault(m_chars.getString(m_data.elementAt(-dataIndex),
2854                                   m_data.elementAt(-dataIndex+1)));
2855      }
2856    }
2857    else
2858    {
2859      int dataIndex = m_dataOrQName.elementAt(identity);
2860
2861      if (dataIndex < 0)
2862      {
2863        dataIndex = -dataIndex;
2864        dataIndex = m_data.elementAt(dataIndex + 1);
2865      }
2866
2867      if (m_xstrf != null)
2868        return m_xstrf.newstr((String JavaDoc)m_values.elementAt(dataIndex));
2869      else
2870        return new XMLStringDefault((String JavaDoc)m_values.elementAt(dataIndex));
2871    }
2872  }
2873  
2874  /**
2875   * The optimized version of SAX2DTM.getStringValue(int).
2876   * <p>
2877   * %OPT% This is one of the most often used interfaces. Performance is
2878   * critical here. This one is different from SAX2DTM.getStringValue(int) in
2879   * that it returns a String instead of a XMLString.
2880   *
2881   * Get the string- value of a node as a String object (see http: //www. w3.
2882   * org/TR/xpath#data- model for the definition of a node's string- value).
2883   *
2884   * @param nodeHandle The node ID.
2885   *
2886   * @return A string object that represents the string-value of the given node.
2887   */

2888  public final String JavaDoc getStringValueX(final int nodeHandle)
2889  {
2890    int identity = makeNodeIdentity(nodeHandle);
2891    if (identity == DTM.NULL)
2892      return EMPTY_STR;
2893    
2894    int type= _type2(identity);
2895
2896    if (type == DTM.ELEMENT_NODE || type == DTM.DOCUMENT_NODE)
2897    {
2898      int startNode = identity;
2899      identity = _firstch2(identity);
2900      if (DTM.NULL != identity)
2901      {
2902    int offset = -1;
2903    int length = 0;
2904
2905    do
2906    {
2907      type = _exptype2(identity);
2908
2909      if (type == DTM.TEXT_NODE || type == DTM.CDATA_SECTION_NODE)
2910      {
2911        int dataIndex = m_dataOrQName.elementAt(identity);
2912        if (dataIndex > 0)
2913        {
2914          if (-1 == offset)
2915          {
2916                offset = dataIndex >>> TEXT_LENGTH_BITS;
2917          }
2918
2919          length += dataIndex & TEXT_LENGTH_MAX;
2920        }
2921        else
2922        {
2923          if (-1 == offset)
2924          {
2925                offset = m_data.elementAt(-dataIndex);
2926          }
2927
2928          length += m_data.elementAt(-dataIndex + 1);
2929        }
2930      }
2931
2932      identity++;
2933    } while (_parent2(identity) >= startNode);
2934
2935    if (length > 0)
2936    {
2937      return m_chars.getString(offset, length);
2938    }
2939    else
2940      return EMPTY_STR;
2941      }
2942      else
2943        return EMPTY_STR;
2944    }
2945    else if (DTM.TEXT_NODE == type || DTM.CDATA_SECTION_NODE == type)
2946    {
2947      int dataIndex = m_dataOrQName.elementAt(identity);
2948      if (dataIndex > 0)
2949      {
2950        return m_chars.getString(dataIndex >>> TEXT_LENGTH_BITS,
2951                                  dataIndex & TEXT_LENGTH_MAX);
2952      }
2953      else
2954      {
2955        return m_chars.getString(m_data.elementAt(-dataIndex),
2956                                  m_data.elementAt(-dataIndex+1));
2957      }
2958    }
2959    else
2960    {
2961      int dataIndex = m_dataOrQName.elementAt(identity);
2962
2963      if (dataIndex < 0)
2964      {
2965        dataIndex = -dataIndex;
2966        dataIndex = m_data.elementAt(dataIndex + 1);
2967      }
2968
2969      return (String JavaDoc)m_values.elementAt(dataIndex);
2970    }
2971  }
2972
2973  /**
2974   * Returns the string value of the entire tree
2975   */

2976  public String JavaDoc getStringValue()
2977  {
2978    int child = _firstch2(ROOTNODE);
2979    if (child == DTM.NULL) return EMPTY_STR;
2980      
2981    // optimization: only create StringBuffer if > 1 child
2982
if ((_exptype2(child) == DTM.TEXT_NODE) && (_nextsib2(child) == DTM.NULL))
2983    {
2984      int dataIndex = m_dataOrQName.elementAt(child);
2985      if (dataIndex > 0)
2986        return m_chars.getString(dataIndex >>> TEXT_LENGTH_BITS, dataIndex & TEXT_LENGTH_MAX);
2987      else
2988        return m_chars.getString(m_data.elementAt(-dataIndex),
2989                                  m_data.elementAt(-dataIndex + 1));
2990    }
2991    else
2992      return getStringValueX(getDocument());
2993    
2994  }
2995
2996  /**
2997   * The optimized version of SAX2DTM.dispatchCharactersEvents(int, ContentHandler, boolean).
2998   * <p>
2999   * Directly call the
3000   * characters method on the passed ContentHandler for the
3001   * string-value of the given node (see http://www.w3.org/TR/xpath#data-model
3002   * for the definition of a node's string-value). Multiple calls to the
3003   * ContentHandler's characters methods may well occur for a single call to
3004   * this method.
3005   *
3006   * @param nodeHandle The node ID.
3007   * @param ch A non-null reference to a ContentHandler.
3008   * @param normalize true if the content should be normalized according to
3009   * the rules for the XPath
3010   * <a HREF="http://www.w3.org/TR/xpath#function-normalize-space">normalize-space</a>
3011   * function.
3012   *
3013   * @throws SAXException
3014   */

3015  public final void dispatchCharactersEvents(int nodeHandle, ContentHandler ch,
3016                                             boolean normalize)
3017          throws SAXException
3018  {
3019
3020    int identity = makeNodeIdentity(nodeHandle);
3021    
3022    if (identity == DTM.NULL)
3023      return;
3024    
3025    int type = _type2(identity);
3026
3027    if (type == DTM.ELEMENT_NODE || type == DTM.DOCUMENT_NODE)
3028    {
3029      int startNode = identity;
3030      identity = _firstch2(identity);
3031      if (DTM.NULL != identity)
3032      {
3033    int offset = -1;
3034    int length = 0;
3035
3036    do
3037    {
3038      type = _exptype2(identity);
3039
3040      if (type == DTM.TEXT_NODE || type == DTM.CDATA_SECTION_NODE)
3041      {
3042        int dataIndex = m_dataOrQName.elementAt(identity);
3043
3044        if (dataIndex > 0)
3045        {
3046          if (-1 == offset)
3047          {
3048                offset = dataIndex >>> TEXT_LENGTH_BITS;
3049          }
3050
3051          length += dataIndex & TEXT_LENGTH_MAX;
3052        }
3053        else
3054        {
3055          if (-1 == offset)
3056          {
3057                offset = m_data.elementAt(-dataIndex);
3058          }
3059
3060          length += m_data.elementAt(-dataIndex + 1);
3061        }
3062      }
3063
3064      identity++;
3065    } while (_parent2(identity) >= startNode);
3066
3067    if (length > 0)
3068    {
3069          if(normalize)
3070            m_chars.sendNormalizedSAXcharacters(ch, offset, length);
3071          else
3072        m_chars.sendSAXcharacters(ch, offset, length);
3073    }
3074      }
3075    }
3076    else if (DTM.TEXT_NODE == type || DTM.CDATA_SECTION_NODE == type)
3077    {
3078      int dataIndex = m_dataOrQName.elementAt(identity);
3079
3080      if (dataIndex > 0)
3081      {
3082        if (normalize)
3083          m_chars.sendNormalizedSAXcharacters(ch, dataIndex >>> TEXT_LENGTH_BITS,
3084                                              dataIndex & TEXT_LENGTH_MAX);
3085        else
3086          m_chars.sendSAXcharacters(ch, dataIndex >>> TEXT_LENGTH_BITS,
3087                                    dataIndex & TEXT_LENGTH_MAX);
3088      }
3089      else
3090      {
3091        if (normalize)
3092          m_chars.sendNormalizedSAXcharacters(ch, m_data.elementAt(-dataIndex),
3093                                              m_data.elementAt(-dataIndex+1));
3094        else
3095          m_chars.sendSAXcharacters(ch, m_data.elementAt(-dataIndex),
3096                                    m_data.elementAt(-dataIndex+1));
3097      }
3098    }
3099    else
3100    {
3101      int dataIndex = m_dataOrQName.elementAt(identity);
3102
3103      if (dataIndex < 0)
3104      {
3105        dataIndex = -dataIndex;
3106        dataIndex = m_data.elementAt(dataIndex + 1);
3107      }
3108      
3109      String JavaDoc str = (String JavaDoc)m_values.elementAt(dataIndex);
3110      
3111      if(normalize)
3112        FastStringBuffer.sendNormalizedSAXcharacters(str.toCharArray(),
3113                                                     0, str.length(), ch);
3114      else
3115        ch.characters(str.toCharArray(), 0, str.length());
3116    }
3117  }
3118
3119  /**
3120   * Given a node handle, return its node value. This is mostly
3121   * as defined by the DOM, but may ignore some conveniences.
3122   * <p>
3123   *
3124   * @param nodeHandle The node id.
3125   * @return String Value of this node, or null if not
3126   * meaningful for this node type.
3127   */

3128  public String JavaDoc getNodeValue(int nodeHandle)
3129  {
3130
3131    int identity = makeNodeIdentity(nodeHandle);
3132    int type = _type2(identity);
3133
3134    if (type == DTM.TEXT_NODE || type == DTM.CDATA_SECTION_NODE)
3135    {
3136      int dataIndex = _dataOrQName(identity);
3137      if (dataIndex > 0)
3138      {
3139        return m_chars.getString(dataIndex >>> TEXT_LENGTH_BITS,
3140                                  dataIndex & TEXT_LENGTH_MAX);
3141      }
3142      else
3143      {
3144        return m_chars.getString(m_data.elementAt(-dataIndex),
3145                                  m_data.elementAt(-dataIndex+1));
3146      }
3147    }
3148    else if (DTM.ELEMENT_NODE == type || DTM.DOCUMENT_FRAGMENT_NODE == type
3149             || DTM.DOCUMENT_NODE == type)
3150    {
3151      return null;
3152    }
3153    else
3154    {
3155      int dataIndex = m_dataOrQName.elementAt(identity);
3156
3157      if (dataIndex < 0)
3158      {
3159        dataIndex = -dataIndex;
3160        dataIndex = m_data.elementAt(dataIndex + 1);
3161      }
3162
3163      return (String JavaDoc)m_values.elementAt(dataIndex);
3164    }
3165  }
3166
3167    /**
3168     * Copy the String value of a Text node to a SerializationHandler
3169     */

3170    protected final void copyTextNode(final int nodeID, SerializationHandler handler)
3171        throws SAXException
3172    {
3173        if (nodeID != DTM.NULL) {
3174            int dataIndex = m_dataOrQName.elementAt(nodeID);
3175            if (dataIndex > 0) {
3176                m_chars.sendSAXcharacters(handler,
3177                                          dataIndex >>> TEXT_LENGTH_BITS,
3178                                          dataIndex & TEXT_LENGTH_MAX);
3179            } else {
3180                m_chars.sendSAXcharacters(handler, m_data.elementAt(-dataIndex),
3181                                          m_data.elementAt(-dataIndex+1));
3182            }
3183        }
3184    }
3185
3186    /**
3187     * Copy an Element node to a SerializationHandler.
3188     *
3189     * @param nodeID The node identity
3190     * @param exptype The expanded type of the Element node
3191     * @param handler The SerializationHandler
3192     * @return The qualified name of the Element node.
3193     */

3194    protected final String JavaDoc copyElement(int nodeID, int exptype,
3195                               SerializationHandler handler)
3196        throws SAXException
3197    {
3198        final ExtendedType extType = m_extendedTypes[exptype];
3199        String JavaDoc uri = extType.getNamespace();
3200        String JavaDoc name = extType.getLocalName();
3201      
3202        if (uri.length() == 0) {
3203            handler.startElement(name);
3204            return name;
3205        }
3206        else {
3207            int qnameIndex = m_dataOrQName.elementAt(nodeID);
3208    
3209            if (qnameIndex == 0) {
3210                handler.startElement(name);
3211                handler.namespaceAfterStartElement(EMPTY_STR, uri);
3212                return name;
3213            }
3214          
3215            if (qnameIndex < 0) {
3216                qnameIndex = -qnameIndex;
3217                qnameIndex = m_data.elementAt(qnameIndex);
3218            }
3219    
3220            String JavaDoc qName = m_valuesOrPrefixes.indexToString(qnameIndex);
3221            handler.startElement(qName);
3222            int prefixIndex = qName.indexOf(':');
3223            String JavaDoc prefix;
3224            if (prefixIndex > 0) {
3225                prefix = qName.substring(0, prefixIndex);
3226            }
3227            else {
3228                prefix = null;
3229            }
3230            handler.namespaceAfterStartElement(prefix, uri);
3231            return qName;
3232        }
3233             
3234    }
3235    
3236     /**
3237     * Copy namespace nodes.
3238     *
3239     * @param nodeID The Element node identity
3240     * @param handler The SerializationHandler
3241     * @param inScope true if all namespaces in scope should be copied,
3242     * false if only the namespace declarations should be copied.
3243     */

3244
3245  protected final void copyNS(final int nodeID, SerializationHandler handler, boolean inScope)
3246        throws SAXException{
3247       final int node = makeNodeHandle(nodeID);
3248       for(int current = getFirstNamespaceNode(node, inScope); current != DTM.NULL;
3249           current = getNextNamespaceNode(node, current, inScope)){
3250                handler.namespaceAfterStartElement(getNodeNameX(current), getNodeValue(current));
3251       }
3252      
3253    }
3254   
3255    /**
3256     * Copy attribute nodes from an element .
3257     *
3258     * @param nodeID The Element node identity
3259     * @param handler The SerializationHandler
3260     */

3261protected final void copyAttributes(final int nodeID, SerializationHandler handler)
3262        throws SAXException{
3263       
3264       for(int current = getFirstAttributeIdentity(nodeID); current != DTM.NULL; current = getNextAttributeIdentity(current)){
3265            int eType = _exptype2(current);
3266            copyAttribute(current, eType, handler);
3267       }
3268    }
3269
3270 
3271  
3272    /**
3273     * Copy an Attribute node to a SerializationHandler
3274     *
3275     * @param nodeID The node identity
3276     * @param exptype The expanded type of the Element node
3277     * @param handler The SerializationHandler
3278     */

3279    protected final void copyAttribute(int nodeID, int exptype,
3280        SerializationHandler handler)
3281        throws SAXException
3282    {
3283        /*
3284            final String uri = getNamespaceName(node);
3285            if (uri.length() != 0) {
3286                final String prefix = getPrefix(node);
3287                handler.namespaceAfterStartElement(prefix, uri);
3288            }
3289            handler.addAttribute(getNodeName(node), getNodeValue(node));
3290        */

3291        final ExtendedType extType = m_extendedTypes[exptype];
3292        final String JavaDoc uri = extType.getNamespace();
3293        final String JavaDoc localName = extType.getLocalName();
3294        
3295        String JavaDoc prefix = null;
3296        String JavaDoc qname = null;
3297        int dataIndex = _dataOrQName(nodeID);
3298        int valueIndex = dataIndex;
3299        if (uri.length() != 0) {
3300            if (dataIndex <= 0) {
3301                int prefixIndex = m_data.elementAt(-dataIndex);
3302                valueIndex = m_data.elementAt(-dataIndex+1);
3303                qname = m_valuesOrPrefixes.indexToString(prefixIndex);
3304                int colonIndex = qname.indexOf(':');
3305                if (colonIndex > 0) {
3306                    prefix = qname.substring(0, colonIndex);
3307                }
3308            }
3309            handler.namespaceAfterStartElement(prefix, uri);
3310        }
3311        
3312        String JavaDoc nodeName = (prefix != null) ? qname : localName;
3313        String JavaDoc nodeValue = (String JavaDoc)m_values.elementAt(valueIndex);
3314        
3315        handler.addAttribute(nodeName, nodeValue);
3316    }
3317    
3318}
3319
Popular Tags