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