1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one 3 * or more contributor license agreements. See the NOTICE file 4 * distributed with this work for additional information 5 * regarding copyright ownership. The ASF licenses this file 6 * to you under the Apache License, Version 2.0 (the "License"); 7 * you may not use this file except in compliance with the License. 8 * You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, software 13 * distributed under the License is distributed on an "AS IS" BASIS, 14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 * See the License for the specific language governing permissions and 16 * limitations under the License. 17 */ 18 /* 19 * $Id: SAX2DTM2.java 468653 2006-10-28 07:07:05Z minchau $ 20 */ 21 package org.apache.xml.dtm.ref.sax2dtm; 22 23 import org.apache.xml.dtm.*; 24 import org.apache.xml.dtm.ref.*; 25 import org.apache.xml.utils.FastStringBuffer; 26 import org.apache.xml.utils.XMLString; 27 import org.apache.xml.utils.XMLStringDefault; 28 import org.apache.xml.utils.XMLStringFactory; 29 import org.apache.xml.res.XMLMessages; 30 import org.apache.xml.res.XMLErrorResources; 31 import org.apache.xml.serializer.SerializationHandler; 32 33 import javax.xml.transform.Source; 34 import java.util.Vector; 35 import org.apache.xml.utils.SuballocatedIntVector; 36 import org.xml.sax.*; 37 38 /** 39 * SAX2DTM2 is an optimized version of SAX2DTM which is used in non-incremental situation. 40 * It is used as the super class of the XSLTC SAXImpl. Many of the interfaces in SAX2DTM 41 * and DTMDefaultBase are overridden in SAX2DTM2 in order to allow fast, efficient 42 * access to the DTM model. Some nested iterators in DTMDefaultBaseIterators 43 * are also overridden in SAX2DTM2 for performance reasons. 44 * <p> 45 * Performance is the biggest consideration in the design of SAX2DTM2. To make the code most 46 * efficient, the incremental support is dropped in SAX2DTM2, which means that you should not 47 * use it in incremental situation. To reduce the overhead of pulling data from the DTM model, 48 * a few core interfaces in SAX2DTM2 have direct access to the internal arrays of the 49 * SuballocatedIntVectors. 50 * <p> 51 * The design of SAX2DTM2 may limit its extensibilty. If you have a reason to extend the 52 * SAX2DTM model, please extend from SAX2DTM instead of this class. 53 * <p> 54 * TODO: This class is currently only used by XSLTC. We need to investigate the possibility 55 * of also using it in Xalan-J Interpretive. Xalan's performance is likely to get an instant 56 * boost if we use SAX2DTM2 instead of SAX2DTM in non-incremental case. 57 * <p> 58 * %MK% The code in this class is critical to the XSLTC_DTM performance. Be very careful 59 * when making changes here! 60 */ 61 public class SAX2DTM2 extends SAX2DTM 62 { 63 64 /**************************************************************** 65 * Optimized version of the nested iterators 66 ****************************************************************/ 67 68 /** 69 * Iterator that returns all immediate children of a given node 70 */ 71 public final class ChildrenIterator extends InternalAxisIteratorBase 72 { 73 74 /** 75 * Setting start to END should 'close' the iterator, 76 * i.e. subsequent call to next() should return END. 77 * <p> 78 * If the iterator is not restartable, this has no effect. 79 * %REVIEW% Should it return/throw something in that case, 80 * or set current node to END, to indicate request-not-honored? 81 * 82 * @param node Sets the root of the iteration. 83 * 84 * @return A DTMAxisIterator set to the start of the iteration. 85 */ setStartNode(int node)86 public DTMAxisIterator setStartNode(int node) 87 { 88 //%HZ%: Added reference to DTMDefaultBase.ROOTNODE back in, temporarily 89 if (node == DTMDefaultBase.ROOTNODE) 90 node = getDocument(); 91 if (_isRestartable) 92 { 93 _startNode = node; 94 _currentNode = (node == DTM.NULL) ? DTM.NULL 95 : _firstch2(makeNodeIdentity(node)); 96 97 return resetPosition(); 98 } 99 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 */ next()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 */ setStartNode(int node)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 */ setNodeType(final int type)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 */ next()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 */ TypedChildrenIterator(int nodeType)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 */ setStartNode(int node)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 */ next()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 */ getNodeByPosition(int position)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 */ TypedRootIterator(int nodeType)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 */ next()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 */ setStartNode(int node)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 */ next()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 */ TypedFollowingSiblingIterator(int type)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 */ next()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 */ setStartNode(int node)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 */ next()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 */ TypedAttributeIterator(int nodeType)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 */ setStartNode(int node)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 */ next()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 */ isReverse()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 */ setStartNode(int node)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 */ next()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 */ TypedPrecedingSiblingIterator(int type)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 */ next()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 */ getLast()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 */ isReverse()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 */ cloneIterator()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 */ setStartNode(int node)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 */ next()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 */ reset()934 public DTMAxisIterator reset() 935 { 936 937 _sp = _oldsp; 938 939 return resetPosition(); 940 } 941 setMark()942 public void setMark() { 943 _markedsp = _sp; 944 _markedNode = _currentNode; 945 _markedDescendant = _stack[0]; 946 } 947 gotoMark()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 */ TypedPrecedingIterator(int type)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 */ next()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 FollowingIterator()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 */ setStartNode(int node)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 */ next()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 */ TypedFollowingIterator(int type)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 */ next()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 */ getStartNode()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 */ isReverse()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 */ cloneIterator()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 */ setStartNode(int node)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 */ reset()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 */ next()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 setMark()1375 public void setMark() { 1376 m_markedPos = m_ancestorsPos; 1377 } 1378 gotoMark()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 */ TypedAncestorIterator(int type)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 */ setStartNode(int node)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 */ getNodeByPosition(int position)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 */ getLast()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 */ setStartNode(int node)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 */ isDescendant(int identity)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 */ next()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 */ reset()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 */ TypedDescendantIterator(int nodeType)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 */ next()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 */ TypedSingletonIterator(int nodeType)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 */ next()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 */ SAX2DTM2(DTMManager mgr, Source source, int dtmIdentity, DTMWSFilter whiteSpaceFilter, XMLStringFactory xstringfactory, boolean doIndexing)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 */ SAX2DTM2(DTMManager mgr, Source source, int dtmIdentity, DTMWSFilter whiteSpaceFilter, XMLStringFactory xstringfactory, boolean doIndexing, int blocksize, boolean usePrevsib, boolean buildIdIndex, boolean newNameTable)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 */ _exptype(int identity)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 */ _exptype2(int identity)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 */ _nextsib2(int identity)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 */ _firstch2(int identity)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 */ _parent2(int identity)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 */ _type2(int identity)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 */ getExpandedTypeID2(int nodeHandle)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 */ _exptype2Type(int exptype)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 */ getIdForNamespace(String uri)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 */ startElement(String uri, String localName, String qName, Attributes attributes)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 */ endElement(String uri, String localName, String qName)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 */ comment(char ch[], int start, int length)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 */ startDocument()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 */ endDocument()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 */ addNode(int type, int expandedTypeID, int parentIndex, int previousSibling, int dataOrPrefix, boolean canHaveFirstChild)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 */ charactersFlush()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 */ processingInstruction(String target, String data)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 */ getFirstAttribute(int nodeHandle)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 */ getFirstAttributeIdentity(int identity)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 */ getNextAttributeIdentity(int identity)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 */ getTypedAttribute(int nodeHandle, int attType)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 */ getLocalName(int nodeHandle)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 */ getNodeNameX(int nodeHandle)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 */ getNodeName(int nodeHandle)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 */ getStringValue(int nodeHandle)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 */ getStringValueX(final int nodeHandle)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 */ getStringValue()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 */ dispatchCharactersEvents(int nodeHandle, ContentHandler ch, boolean normalize)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 */ getNodeValue(int nodeHandle)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 */ copyTextNode(final int nodeID, SerializationHandler handler)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 */ copyElement(int nodeID, int exptype, SerializationHandler handler)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 */ copyNS(final int nodeID, SerializationHandler handler, boolean inScope)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 */ getNextNamespaceNode2(int baseID)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 */ copyAttributes(final int nodeID, SerializationHandler handler)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 */ copyAttribute(int nodeID, int exptype, SerializationHandler handler)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 } 3384