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