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