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