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 }