1 /* 2 * Copyright (c) 2007, 2016, 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 if ((uri == null || uri.isEmpty()) && 2028 (localName == null || localName.isEmpty())) 2029 { 2030 final int colon = qName.lastIndexOf(':'); 2031 localName = (colon > -1) ? qName.substring(colon + 1) : qName; 2032 } 2033 2034 int exName = m_expandedNameTable.getExpandedTypeID(uri, localName, 2035 DTM.ELEMENT_NODE); 2036 2037 int prefixIndex = (qName.length() != localName.length()) 2038 ? m_valuesOrPrefixes.stringToIndex(qName) : 0; 2039 2040 int elemNode = addNode(DTM.ELEMENT_NODE, exName, 2041 m_parents.peek(), m_previous, prefixIndex, true); 2042 2043 if (m_indexing) 2044 indexNode(exName, elemNode); 2045 2046 m_parents.push(elemNode); 2047 2048 int startDecls = m_contextIndexes.peek(); 2049 int nDecls = m_prefixMappings.size(); 2050 String prefix; 2051 2052 if (!m_pastFirstElement) { 2053 // SPECIAL CASE: Implied declaration at root element 2054 prefix = "xml"; 2055 String declURL = "http://www.w3.org/XML/1998/namespace"; 2056 exName = m_expandedNameTable.getExpandedTypeID(null, prefix, 2057 DTM.NAMESPACE_NODE); 2058 m_values.add(declURL); 2059 int val = m_valueIndex++; 2060 addNode(DTM.NAMESPACE_NODE, exName, elemNode, 2061 DTM.NULL, val, false); 2062 m_pastFirstElement=true; 2063 } 2064 2065 for (int i = startDecls; i < nDecls; i += 2) { 2066 prefix = m_prefixMappings.elementAt(i); 2067 2068 if (prefix == null) 2069 continue; 2070 2071 String declURL = m_prefixMappings.elementAt(i + 1); 2072 2073 exName = m_expandedNameTable.getExpandedTypeID(null, prefix, 2074 DTM.NAMESPACE_NODE); 2075 2076 m_values.add(declURL); 2077 int val = m_valueIndex++; 2078 2079 addNode(DTM.NAMESPACE_NODE, exName, elemNode, DTM.NULL, val, false); 2080 } 2081 2082 int n = attributes.getLength(); 2083 2084 for (int i = 0; i < n; i++) { 2085 String attrUri = attributes.getURI(i); 2086 String attrLocalName = attributes.getLocalName(i); 2087 String attrQName = attributes.getQName(i); 2088 String valString = attributes.getValue(i); 2089 2090 // in case URI and localName are empty, the input is not using the 2091 // namespaces feature. Then we should take the part after the last 2092 // colon of qName as localName (strip all namespace prefixes) 2093 // When the URI is empty but localName has colons then we can also 2094 // assume non namespace aware and prefixes can be stripped 2095 if (attrUri == null || attrUri.isEmpty()) { 2096 if (attrLocalName == null || attrLocalName.isEmpty()) { 2097 final int colon = attrQName.lastIndexOf(':'); 2098 attrLocalName = (colon > -1) ? attrQName.substring(colon + 1) : attrQName; 2099 } else { 2100 final int colon = attrLocalName.lastIndexOf(':'); 2101 attrLocalName = (colon > -1) ? attrLocalName.substring(colon + 1) : attrLocalName; 2102 } 2103 } 2104 2105 int nodeType; 2106 if ((null != attrQName) && 2107 (attrQName.equals("xmlns") || attrQName.startsWith("xmlns:"))) 2108 { 2109 prefix = getPrefix(attrQName, attrUri); 2110 if (declAlreadyDeclared(prefix)) 2111 continue; // go to the next attribute. 2112 2113 nodeType = DTM.NAMESPACE_NODE; 2114 } else { 2115 nodeType = DTM.ATTRIBUTE_NODE; 2116 2117 if (m_buildIdIndex && attributes.getType(i).equalsIgnoreCase("ID")) 2118 setIDAttribute(valString, elemNode); 2119 } 2120 2121 // Bit of a hack... if somehow valString is null, stringToIndex will 2122 // return -1, which will make things very unhappy. 2123 if (null == valString) 2124 valString = ""; 2125 2126 m_values.add(valString); 2127 int val = m_valueIndex++; 2128 2129 if (attrLocalName.length() != attrQName.length()) { 2130 prefixIndex = m_valuesOrPrefixes.stringToIndex(attrQName); 2131 int dataIndex = m_data.size(); 2132 m_data.addElement(prefixIndex); 2133 m_data.addElement(val); 2134 val = -dataIndex; 2135 } 2136 2137 exName = m_expandedNameTable.getExpandedTypeID(attrUri, attrLocalName, 2138 nodeType); 2139 addNode(nodeType, exName, elemNode, DTM.NULL, val, false); 2140 } 2141 2142 if (null != m_wsfilter) { 2143 short wsv = m_wsfilter.getShouldStripSpace(makeNodeHandle(elemNode), 2144 this); 2145 boolean shouldStrip = (DTMWSFilter.INHERIT == wsv) ? 2146 getShouldStripWhitespace() : 2147 (DTMWSFilter.STRIP == wsv); 2148 2149 pushShouldStripWhitespace(shouldStrip); 2150 } 2151 2152 m_previous = DTM.NULL; 2153 2154 m_contextIndexes.push(m_prefixMappings.size()); // for the children. 2155 } 2156 2157 /** 2158 * Receive notification of the end of an element. 2159 * 2160 * <p>By default, do nothing. Application writers may override this 2161 * method in a subclass to take specific actions at the end of 2162 * each element (such as finalising a tree node or writing 2163 * output to a file).</p> 2164 * 2165 * @param uri The Namespace URI, or the empty string if the 2166 * element has no Namespace URI or if Namespace 2167 * processing is not being performed. 2168 * @param localName The local name (without prefix), or the 2169 * empty string if Namespace processing is not being 2170 * performed. 2171 * @param qName The qualified XML 1.0 name (with prefix), or the 2172 * empty string if qualified names are not available. 2173 * @throws SAXException Any SAX exception, possibly 2174 * wrapping another exception. 2175 * @see ContentHandler#endElement 2176 */ 2177 public void endElement(String uri, String localName, String qName) 2178 throws SAXException 2179 { 2180 charactersFlush(); 2181 2182 // If no one noticed, startPrefixMapping is a drag. 2183 // Pop the context for the last child (the one pushed by startElement) 2184 m_contextIndexes.quickPop(1); 2185 2186 // Do it again for this one (the one pushed by the last endElement). 2187 int topContextIndex = m_contextIndexes.peek(); 2188 if (topContextIndex != m_prefixMappings.size()) { 2189 m_prefixMappings.setSize(topContextIndex); 2190 } 2191 2192 m_previous = m_parents.pop(); 2193 2194 popShouldStripWhitespace(); 2195 } 2196 2197 /** 2198 * Report an XML comment anywhere in the document. 2199 * 2200 * <p>This callback will be used for comments inside or outside the 2201 * document element, including comments in the external DTD 2202 * subset (if read).</p> 2203 * 2204 * @param ch An array holding the characters in the comment. 2205 * @param start The starting position in the array. 2206 * @param length The number of characters to use from the array. 2207 * @throws SAXException The application may raise an exception. 2208 */ 2209 public void comment(char ch[], int start, int length) throws SAXException { 2210 if (m_insideDTD) // ignore comments if we're inside the DTD 2211 return; 2212 2213 charactersFlush(); 2214 2215 // %OPT% Saving the comment string in a Vector has a lower cost than 2216 // saving it in DTMStringPool. 2217 m_values.add(new String(ch, start, length)); 2218 int dataIndex = m_valueIndex++; 2219 2220 m_previous = addNode(DTM.COMMENT_NODE, DTM.COMMENT_NODE, 2221 m_parents.peek(), m_previous, dataIndex, false); 2222 } 2223 2224 /** 2225 * Receive notification of the beginning of the document. 2226 * 2227 * @throws SAXException Any SAX exception, possibly 2228 * wrapping another exception. 2229 * @see ContentHandler#startDocument 2230 */ 2231 public void startDocument() throws SAXException { 2232 int doc = addNode(DTM.DOCUMENT_NODE, DTM.DOCUMENT_NODE, 2233 DTM.NULL, DTM.NULL, 0, true); 2234 2235 m_parents.push(doc); 2236 m_previous = DTM.NULL; 2237 2238 m_contextIndexes.push(m_prefixMappings.size()); // for the next element. 2239 } 2240 2241 /** 2242 * Receive notification of the end of the document. 2243 * 2244 * @throws SAXException Any SAX exception, possibly 2245 * wrapping another exception. 2246 * @see ContentHandler#endDocument 2247 */ 2248 public void endDocument() throws SAXException { 2249 super.endDocument(); 2250 2251 // Add a NULL entry to the end of the node arrays as 2252 // the end indication. 2253 m_exptype.addElement(NULL); 2254 m_parent.addElement(NULL); 2255 m_nextsib.addElement(NULL); 2256 m_firstch.addElement(NULL); 2257 2258 // Set the cached references after the document is built. 2259 m_extendedTypes = m_expandedNameTable.getExtendedTypes(); 2260 m_exptype_map = m_exptype.getMap(); 2261 m_nextsib_map = m_nextsib.getMap(); 2262 m_firstch_map = m_firstch.getMap(); 2263 m_parent_map = m_parent.getMap(); 2264 } 2265 2266 /** 2267 * Construct the node map from the node. 2268 * 2269 * @param type raw type ID, one of DTM.XXX_NODE. 2270 * @param expandedTypeID The expended type ID. 2271 * @param parentIndex The current parent index. 2272 * @param previousSibling The previous sibling index. 2273 * @param dataOrPrefix index into m_data table, or string handle. 2274 * @param canHaveFirstChild true if the node can have a first child, false 2275 * if it is atomic. 2276 * 2277 * @return The index identity of the node that was added. 2278 */ 2279 protected final int addNode(int type, int expandedTypeID, 2280 int parentIndex, int previousSibling, 2281 int dataOrPrefix, boolean canHaveFirstChild) 2282 { 2283 // Common to all nodes: 2284 int nodeIndex = m_size++; 2285 2286 // Have we overflowed a DTM Identity's addressing range? 2287 //if(m_dtmIdent.size() == (nodeIndex>>>DTMManager.IDENT_DTM_NODE_BITS)) 2288 if (nodeIndex == m_maxNodeIndex) { 2289 addNewDTMID(nodeIndex); 2290 m_maxNodeIndex += (1 << DTMManager.IDENT_DTM_NODE_BITS); 2291 } 2292 2293 m_firstch.addElement(DTM.NULL); 2294 m_nextsib.addElement(DTM.NULL); 2295 m_parent.addElement(parentIndex); 2296 m_exptype.addElement(expandedTypeID); 2297 m_dataOrQName.addElement(dataOrPrefix); 2298 2299 if (m_prevsib != null) { 2300 m_prevsib.addElement(previousSibling); 2301 } 2302 2303 if (m_locator != null && m_useSourceLocationProperty) { 2304 setSourceLocation(); 2305 } 2306 2307 // Note that nextSibling is not processed until charactersFlush() 2308 // is called, to handle successive characters() events. 2309 2310 // Special handling by type: Declare namespaces, attach first child 2311 switch(type) { 2312 case DTM.NAMESPACE_NODE: 2313 declareNamespaceInContext(parentIndex,nodeIndex); 2314 break; 2315 case DTM.ATTRIBUTE_NODE: 2316 break; 2317 default: 2318 if (DTM.NULL != previousSibling) { 2319 m_nextsib.setElementAt(nodeIndex,previousSibling); 2320 } else if (DTM.NULL != parentIndex) { 2321 m_firstch.setElementAt(nodeIndex,parentIndex); 2322 } 2323 break; 2324 } 2325 2326 return nodeIndex; 2327 } 2328 2329 /** 2330 * Check whether accumulated text should be stripped; if not, 2331 * append the appropriate flavor of text/cdata node. 2332 */ 2333 protected final void charactersFlush() { 2334 if (m_textPendingStart >= 0) { // -1 indicates no-text-in-progress 2335 int length = m_chars.size() - m_textPendingStart; 2336 boolean doStrip = false; 2337 2338 if (getShouldStripWhitespace()) { 2339 doStrip = m_chars.isWhitespace(m_textPendingStart, length); 2340 } 2341 2342 if (doStrip) { 2343 m_chars.setLength(m_textPendingStart); // Discard accumulated text 2344 } else { 2345 // Guard against characters/ignorableWhitespace events that 2346 // contained no characters. They should not result in a node. 2347 if (length > 0) { 2348 // If the offset and length do not exceed the given limits 2349 // (offset < 2^21 and length < 2^10), then save both the offset 2350 // and length in a bitwise encoded value. 2351 if (length <= TEXT_LENGTH_MAX && 2352 m_textPendingStart <= TEXT_OFFSET_MAX) { 2353 m_previous = addNode(m_coalescedTextType, DTM.TEXT_NODE, 2354 m_parents.peek(), m_previous, 2355 length + (m_textPendingStart << TEXT_LENGTH_BITS), 2356 false); 2357 2358 } else { 2359 // Store offset and length in the m_data array if one exceeds 2360 // the given limits. Use a negative dataIndex as an indication. 2361 int dataIndex = m_data.size(); 2362 m_previous = addNode(m_coalescedTextType, DTM.TEXT_NODE, 2363 m_parents.peek(), m_previous, -dataIndex, false); 2364 2365 m_data.addElement(m_textPendingStart); 2366 m_data.addElement(length); 2367 } 2368 } 2369 } 2370 2371 // Reset for next text block 2372 m_textPendingStart = -1; 2373 m_textType = m_coalescedTextType = DTM.TEXT_NODE; 2374 } 2375 } 2376 2377 /** 2378 * Override the processingInstruction() interface in SAX2DTM2. 2379 * <p> 2380 * %OPT% This one is different from SAX2DTM.processingInstruction() 2381 * in that we do not use extended types for PI nodes. The name of 2382 * the PI is saved in the DTMStringPool. 2383 * 2384 * Receive notification of a processing instruction. 2385 * 2386 * @param target The processing instruction target. 2387 * @param data The processing instruction data, or null if 2388 * none is supplied. 2389 * @throws SAXException Any SAX exception, possibly 2390 * wrapping another exception. 2391 * @see ContentHandler#processingInstruction 2392 */ 2393 public void processingInstruction(String target, String data) 2394 throws SAXException 2395 { 2396 2397 charactersFlush(); 2398 2399 int dataIndex = m_data.size(); 2400 m_previous = addNode(DTM.PROCESSING_INSTRUCTION_NODE, 2401 DTM.PROCESSING_INSTRUCTION_NODE, 2402 m_parents.peek(), m_previous, 2403 -dataIndex, false); 2404 2405 m_data.addElement(m_valuesOrPrefixes.stringToIndex(target)); 2406 m_values.add(data); 2407 m_data.addElement(m_valueIndex++); 2408 2409 } 2410 2411 /** 2412 * The optimized version of DTMDefaultBase.getFirstAttribute(). 2413 * <p> 2414 * Given a node handle, get the index of the node's first attribute. 2415 * 2416 * @param nodeHandle int Handle of the node. 2417 * @return Handle of first attribute, or DTM.NULL to indicate none exists. 2418 */ 2419 public final int getFirstAttribute(int nodeHandle) 2420 { 2421 int nodeID = makeNodeIdentity(nodeHandle); 2422 2423 if (nodeID == DTM.NULL) 2424 return DTM.NULL; 2425 2426 int type = _type2(nodeID); 2427 2428 if (DTM.ELEMENT_NODE == type) 2429 { 2430 // Assume that attributes and namespaces immediately follow the element. 2431 while (true) 2432 { 2433 nodeID++; 2434 // Assume this can not be null. 2435 type = _type2(nodeID); 2436 2437 if (type == DTM.ATTRIBUTE_NODE) 2438 { 2439 return makeNodeHandle(nodeID); 2440 } 2441 else if (DTM.NAMESPACE_NODE != type) 2442 { 2443 break; 2444 } 2445 } 2446 } 2447 2448 return DTM.NULL; 2449 } 2450 2451 /** 2452 * The optimized version of DTMDefaultBase.getFirstAttributeIdentity(int). 2453 * <p> 2454 * Given a node identity, get the index of the node's first attribute. 2455 * 2456 * @param identity int identity of the node. 2457 * @return Identity of first attribute, or DTM.NULL to indicate none exists. 2458 */ 2459 protected int getFirstAttributeIdentity(int identity) { 2460 if (identity == NULL) { 2461 return NULL; 2462 } 2463 int type = _type2(identity); 2464 2465 if (DTM.ELEMENT_NODE == type) 2466 { 2467 // Assume that attributes and namespaces immediately follow the element. 2468 while (true) 2469 { 2470 identity++; 2471 2472 // Assume this can not be null. 2473 type = _type2(identity); 2474 2475 if (type == DTM.ATTRIBUTE_NODE) 2476 { 2477 return identity; 2478 } 2479 else if (DTM.NAMESPACE_NODE != type) 2480 { 2481 break; 2482 } 2483 } 2484 } 2485 2486 return DTM.NULL; 2487 } 2488 2489 /** 2490 * The optimized version of DTMDefaultBase.getNextAttributeIdentity(int). 2491 * <p> 2492 * Given a node identity for an attribute, advance to the next attribute. 2493 * 2494 * @param identity int identity of the attribute node. This 2495 * <strong>must</strong> be an attribute node. 2496 * 2497 * @return int DTM node-identity of the resolved attr, 2498 * or DTM.NULL to indicate none exists. 2499 * 2500 */ 2501 protected int getNextAttributeIdentity(int identity) { 2502 // Assume that attributes and namespace nodes immediately follow the element 2503 while (true) { 2504 identity++; 2505 int type = _type2(identity); 2506 2507 if (type == DTM.ATTRIBUTE_NODE) { 2508 return identity; 2509 } else if (type != DTM.NAMESPACE_NODE) { 2510 break; 2511 } 2512 } 2513 2514 return DTM.NULL; 2515 } 2516 2517 /** 2518 * The optimized version of DTMDefaultBase.getTypedAttribute(int, int). 2519 * <p> 2520 * Given a node handle and an expanded type ID, get the index of the node's 2521 * attribute of that type, if any. 2522 * 2523 * @param nodeHandle int Handle of the node. 2524 * @param attType int expanded type ID of the required attribute. 2525 * @return Handle of attribute of the required type, or DTM.NULL to indicate 2526 * none exists. 2527 */ 2528 protected final int getTypedAttribute(int nodeHandle, int attType) 2529 { 2530 2531 int nodeID = makeNodeIdentity(nodeHandle); 2532 2533 if (nodeID == DTM.NULL) 2534 return DTM.NULL; 2535 2536 int type = _type2(nodeID); 2537 2538 if (DTM.ELEMENT_NODE == type) 2539 { 2540 int expType; 2541 while (true) 2542 { 2543 nodeID++; 2544 expType = _exptype2(nodeID); 2545 2546 if (expType != DTM.NULL) 2547 type = m_extendedTypes[expType].getNodeType(); 2548 else 2549 return DTM.NULL; 2550 2551 if (type == DTM.ATTRIBUTE_NODE) 2552 { 2553 if (expType == attType) return makeNodeHandle(nodeID); 2554 } 2555 else if (DTM.NAMESPACE_NODE != type) 2556 { 2557 break; 2558 } 2559 } 2560 } 2561 2562 return DTM.NULL; 2563 } 2564 2565 /** 2566 * Override SAX2DTM.getLocalName() in SAX2DTM2. 2567 * <p>Processing for PIs is different. 2568 * 2569 * Given a node handle, return its XPath- style localname. (As defined in 2570 * Namespaces, this is the portion of the name after any colon character). 2571 * 2572 * @param nodeHandle the id of the node. 2573 * @return String Local name of this node. 2574 */ 2575 public String getLocalName(int nodeHandle) 2576 { 2577 int expType = _exptype(makeNodeIdentity(nodeHandle)); 2578 2579 if (expType == DTM.PROCESSING_INSTRUCTION_NODE) 2580 { 2581 int dataIndex = _dataOrQName(makeNodeIdentity(nodeHandle)); 2582 dataIndex = m_data.elementAt(-dataIndex); 2583 return m_valuesOrPrefixes.indexToString(dataIndex); 2584 } 2585 else 2586 return m_expandedNameTable.getLocalName(expType); 2587 } 2588 2589 /** 2590 * The optimized version of SAX2DTM.getNodeNameX(). 2591 * <p> 2592 * Given a node handle, return the XPath node name. This should be the name 2593 * as described by the XPath data model, NOT the DOM- style name. 2594 * 2595 * @param nodeHandle the id of the node. 2596 * @return String Name of this node, which may be an empty string. 2597 */ 2598 public final String getNodeNameX(int nodeHandle) 2599 { 2600 2601 int nodeID = makeNodeIdentity(nodeHandle); 2602 int eType = _exptype2(nodeID); 2603 2604 if (eType == DTM.PROCESSING_INSTRUCTION_NODE) 2605 { 2606 int dataIndex = _dataOrQName(nodeID); 2607 dataIndex = m_data.elementAt(-dataIndex); 2608 return m_valuesOrPrefixes.indexToString(dataIndex); 2609 } 2610 2611 final ExtendedType extType = m_extendedTypes[eType]; 2612 2613 if (extType.getNamespace().length() == 0) 2614 { 2615 return extType.getLocalName(); 2616 } 2617 else 2618 { 2619 int qnameIndex = m_dataOrQName.elementAt(nodeID); 2620 2621 if (qnameIndex == 0) 2622 return extType.getLocalName(); 2623 2624 if (qnameIndex < 0) 2625 { 2626 qnameIndex = -qnameIndex; 2627 qnameIndex = m_data.elementAt(qnameIndex); 2628 } 2629 2630 return m_valuesOrPrefixes.indexToString(qnameIndex); 2631 } 2632 } 2633 2634 /** 2635 * The optimized version of SAX2DTM.getNodeName(). 2636 * <p> 2637 * Given a node handle, return its DOM-style node name. This will include 2638 * names such as #text or #document. 2639 * 2640 * @param nodeHandle the id of the node. 2641 * @return String Name of this node, which may be an empty string. 2642 * %REVIEW% Document when empty string is possible... 2643 * %REVIEW-COMMENT% It should never be empty, should it? 2644 */ 2645 public String getNodeName(int nodeHandle) 2646 { 2647 2648 int nodeID = makeNodeIdentity(nodeHandle); 2649 int eType = _exptype2(nodeID); 2650 2651 final ExtendedType extType = m_extendedTypes[eType]; 2652 if (extType.getNamespace().length() == 0) 2653 { 2654 int type = extType.getNodeType(); 2655 2656 String localName = extType.getLocalName(); 2657 if (type == DTM.NAMESPACE_NODE) 2658 { 2659 if (localName.length() == 0) 2660 return "xmlns"; 2661 else 2662 return "xmlns:" + localName; 2663 } 2664 else if (type == DTM.PROCESSING_INSTRUCTION_NODE) 2665 { 2666 int dataIndex = _dataOrQName(nodeID); 2667 dataIndex = m_data.elementAt(-dataIndex); 2668 return m_valuesOrPrefixes.indexToString(dataIndex); 2669 } 2670 else if (localName.length() == 0) 2671 { 2672 return getFixedNames(type); 2673 } 2674 else 2675 return localName; 2676 } 2677 else 2678 { 2679 int qnameIndex = m_dataOrQName.elementAt(nodeID); 2680 2681 if (qnameIndex == 0) 2682 return extType.getLocalName(); 2683 2684 if (qnameIndex < 0) 2685 { 2686 qnameIndex = -qnameIndex; 2687 qnameIndex = m_data.elementAt(qnameIndex); 2688 } 2689 2690 return m_valuesOrPrefixes.indexToString(qnameIndex); 2691 } 2692 } 2693 2694 /** 2695 * Override SAX2DTM.getStringValue(int) 2696 * <p> 2697 * This method is only used by Xalan-J Interpretive. It is not used by XSLTC. 2698 * <p> 2699 * If the caller supplies an XMLStringFactory, the getStringValue() interface 2700 * in SAX2DTM will be called. Otherwise just calls getStringValueX() and 2701 * wraps the returned String in an XMLString. 2702 * 2703 * Get the string-value of a node as a String object 2704 * (see http://www.w3.org/TR/xpath#data-model 2705 * for the definition of a node's string-value). 2706 * 2707 * @param nodeHandle The node ID. 2708 * 2709 * @return A string object that represents the string-value of the given node. 2710 */ 2711 public XMLString getStringValue(int nodeHandle) 2712 { 2713 int identity = makeNodeIdentity(nodeHandle); 2714 if (identity == DTM.NULL) 2715 return EMPTY_XML_STR; 2716 2717 int type= _type2(identity); 2718 2719 if (type == DTM.ELEMENT_NODE || type == DTM.DOCUMENT_NODE) 2720 { 2721 int startNode = identity; 2722 identity = _firstch2(identity); 2723 if (DTM.NULL != identity) 2724 { 2725 int offset = -1; 2726 int length = 0; 2727 2728 do 2729 { 2730 type = _exptype2(identity); 2731 2732 if (type == DTM.TEXT_NODE || type == DTM.CDATA_SECTION_NODE) 2733 { 2734 int dataIndex = m_dataOrQName.elementAt(identity); 2735 if (dataIndex >= 0) 2736 { 2737 if (-1 == offset) 2738 { 2739 offset = dataIndex >>> TEXT_LENGTH_BITS; 2740 } 2741 2742 length += dataIndex & TEXT_LENGTH_MAX; 2743 } 2744 else 2745 { 2746 if (-1 == offset) 2747 { 2748 offset = m_data.elementAt(-dataIndex); 2749 } 2750 2751 length += m_data.elementAt(-dataIndex + 1); 2752 } 2753 } 2754 2755 identity++; 2756 } while (_parent2(identity) >= startNode); 2757 2758 if (length > 0) 2759 { 2760 if (m_xstrf != null) 2761 return m_xstrf.newstr(m_chars, offset, length); 2762 else 2763 return new XMLStringDefault(m_chars.getString(offset, length)); 2764 } 2765 else 2766 return EMPTY_XML_STR; 2767 } 2768 else 2769 return EMPTY_XML_STR; 2770 } 2771 else if (DTM.TEXT_NODE == type || DTM.CDATA_SECTION_NODE == type) 2772 { 2773 int dataIndex = m_dataOrQName.elementAt(identity); 2774 if (dataIndex >= 0) 2775 { 2776 if (m_xstrf != null) 2777 return m_xstrf.newstr(m_chars, dataIndex >>> TEXT_LENGTH_BITS, 2778 dataIndex & TEXT_LENGTH_MAX); 2779 else 2780 return new XMLStringDefault(m_chars.getString(dataIndex >>> TEXT_LENGTH_BITS, 2781 dataIndex & TEXT_LENGTH_MAX)); 2782 } 2783 else 2784 { 2785 if (m_xstrf != null) 2786 return m_xstrf.newstr(m_chars, m_data.elementAt(-dataIndex), 2787 m_data.elementAt(-dataIndex+1)); 2788 else 2789 return new XMLStringDefault(m_chars.getString(m_data.elementAt(-dataIndex), 2790 m_data.elementAt(-dataIndex+1))); 2791 } 2792 } 2793 else 2794 { 2795 int dataIndex = m_dataOrQName.elementAt(identity); 2796 2797 if (dataIndex < 0) 2798 { 2799 dataIndex = -dataIndex; 2800 dataIndex = m_data.elementAt(dataIndex + 1); 2801 } 2802 2803 if (m_xstrf != null) 2804 return m_xstrf.newstr(m_values.get(dataIndex)); 2805 else 2806 return new XMLStringDefault(m_values.get(dataIndex)); 2807 } 2808 } 2809 2810 /** 2811 * The optimized version of SAX2DTM.getStringValue(int). 2812 * <p> 2813 * %OPT% This is one of the most often used interfaces. Performance is 2814 * critical here. This one is different from SAX2DTM.getStringValue(int) in 2815 * that it returns a String instead of a XMLString. 2816 * 2817 * Get the string- value of a node as a String object (see http: //www. w3. 2818 * org/TR/xpath#data- model for the definition of a node's string- value). 2819 * 2820 * @param nodeHandle The node ID. 2821 * 2822 * @return A string object that represents the string-value of the given node. 2823 */ 2824 public final String getStringValueX(final int nodeHandle) 2825 { 2826 int identity = makeNodeIdentity(nodeHandle); 2827 if (identity == DTM.NULL) 2828 return EMPTY_STR; 2829 2830 int type= _type2(identity); 2831 2832 if (type == DTM.ELEMENT_NODE || type == DTM.DOCUMENT_NODE) 2833 { 2834 int startNode = identity; 2835 identity = _firstch2(identity); 2836 if (DTM.NULL != identity) 2837 { 2838 int offset = -1; 2839 int length = 0; 2840 2841 do 2842 { 2843 type = _exptype2(identity); 2844 2845 if (type == DTM.TEXT_NODE || type == DTM.CDATA_SECTION_NODE) 2846 { 2847 int dataIndex = m_dataOrQName.elementAt(identity); 2848 if (dataIndex >= 0) 2849 { 2850 if (-1 == offset) 2851 { 2852 offset = dataIndex >>> TEXT_LENGTH_BITS; 2853 } 2854 2855 length += dataIndex & TEXT_LENGTH_MAX; 2856 } 2857 else 2858 { 2859 if (-1 == offset) 2860 { 2861 offset = m_data.elementAt(-dataIndex); 2862 } 2863 2864 length += m_data.elementAt(-dataIndex + 1); 2865 } 2866 } 2867 2868 identity++; 2869 } while (_parent2(identity) >= startNode); 2870 2871 if (length > 0) 2872 { 2873 return m_chars.getString(offset, length); 2874 } 2875 else 2876 return EMPTY_STR; 2877 } 2878 else 2879 return EMPTY_STR; 2880 } 2881 else if (DTM.TEXT_NODE == type || DTM.CDATA_SECTION_NODE == type) 2882 { 2883 int dataIndex = m_dataOrQName.elementAt(identity); 2884 if (dataIndex >= 0) 2885 { 2886 return m_chars.getString(dataIndex >>> TEXT_LENGTH_BITS, 2887 dataIndex & TEXT_LENGTH_MAX); 2888 } 2889 else 2890 { 2891 return m_chars.getString(m_data.elementAt(-dataIndex), 2892 m_data.elementAt(-dataIndex+1)); 2893 } 2894 } 2895 else 2896 { 2897 int dataIndex = m_dataOrQName.elementAt(identity); 2898 2899 if (dataIndex < 0) 2900 { 2901 dataIndex = -dataIndex; 2902 dataIndex = m_data.elementAt(dataIndex + 1); 2903 } 2904 2905 return m_values.get(dataIndex); 2906 } 2907 } 2908 2909 /** 2910 * Returns the string value of the entire tree 2911 */ 2912 public String getStringValue() 2913 { 2914 int child = _firstch2(ROOTNODE); 2915 if (child == DTM.NULL) return EMPTY_STR; 2916 2917 // optimization: only create StringBuffer if > 1 child 2918 if ((_exptype2(child) == DTM.TEXT_NODE) && (_nextsib2(child) == DTM.NULL)) 2919 { 2920 int dataIndex = m_dataOrQName.elementAt(child); 2921 if (dataIndex >= 0) 2922 return m_chars.getString(dataIndex >>> TEXT_LENGTH_BITS, dataIndex & TEXT_LENGTH_MAX); 2923 else 2924 return m_chars.getString(m_data.elementAt(-dataIndex), 2925 m_data.elementAt(-dataIndex + 1)); 2926 } 2927 else 2928 return getStringValueX(getDocument()); 2929 2930 } 2931 2932 /** 2933 * The optimized version of SAX2DTM.dispatchCharactersEvents(int, ContentHandler, boolean). 2934 * <p> 2935 * Directly call the 2936 * characters method on the passed ContentHandler for the 2937 * string-value of the given node (see http://www.w3.org/TR/xpath#data-model 2938 * for the definition of a node's string-value). Multiple calls to the 2939 * ContentHandler's characters methods may well occur for a single call to 2940 * this method. 2941 * 2942 * @param nodeHandle The node ID. 2943 * @param ch A non-null reference to a ContentHandler. 2944 * @param normalize true if the content should be normalized according to 2945 * the rules for the XPath 2946 * <a href="http://www.w3.org/TR/xpath#function-normalize-space">normalize-space</a> 2947 * function. 2948 * 2949 * @throws SAXException 2950 */ 2951 public final void dispatchCharactersEvents(int nodeHandle, ContentHandler ch, 2952 boolean normalize) 2953 throws SAXException 2954 { 2955 2956 int identity = makeNodeIdentity(nodeHandle); 2957 2958 if (identity == DTM.NULL) 2959 return; 2960 2961 int type = _type2(identity); 2962 2963 if (type == DTM.ELEMENT_NODE || type == DTM.DOCUMENT_NODE) 2964 { 2965 int startNode = identity; 2966 identity = _firstch2(identity); 2967 if (DTM.NULL != identity) 2968 { 2969 int offset = -1; 2970 int length = 0; 2971 2972 do 2973 { 2974 type = _exptype2(identity); 2975 2976 if (type == DTM.TEXT_NODE || type == DTM.CDATA_SECTION_NODE) 2977 { 2978 int dataIndex = m_dataOrQName.elementAt(identity); 2979 2980 if (dataIndex >= 0) 2981 { 2982 if (-1 == offset) 2983 { 2984 offset = dataIndex >>> TEXT_LENGTH_BITS; 2985 } 2986 2987 length += dataIndex & TEXT_LENGTH_MAX; 2988 } 2989 else 2990 { 2991 if (-1 == offset) 2992 { 2993 offset = m_data.elementAt(-dataIndex); 2994 } 2995 2996 length += m_data.elementAt(-dataIndex + 1); 2997 } 2998 } 2999 3000 identity++; 3001 } while (_parent2(identity) >= startNode); 3002 3003 if (length > 0) 3004 { 3005 if(normalize) 3006 m_chars.sendNormalizedSAXcharacters(ch, offset, length); 3007 else 3008 m_chars.sendSAXcharacters(ch, offset, length); 3009 } 3010 } 3011 } 3012 else if (DTM.TEXT_NODE == type || DTM.CDATA_SECTION_NODE == type) 3013 { 3014 int dataIndex = m_dataOrQName.elementAt(identity); 3015 3016 if (dataIndex >= 0) 3017 { 3018 if (normalize) 3019 m_chars.sendNormalizedSAXcharacters(ch, dataIndex >>> TEXT_LENGTH_BITS, 3020 dataIndex & TEXT_LENGTH_MAX); 3021 else 3022 m_chars.sendSAXcharacters(ch, dataIndex >>> TEXT_LENGTH_BITS, 3023 dataIndex & TEXT_LENGTH_MAX); 3024 } 3025 else 3026 { 3027 if (normalize) 3028 m_chars.sendNormalizedSAXcharacters(ch, m_data.elementAt(-dataIndex), 3029 m_data.elementAt(-dataIndex+1)); 3030 else 3031 m_chars.sendSAXcharacters(ch, m_data.elementAt(-dataIndex), 3032 m_data.elementAt(-dataIndex+1)); 3033 } 3034 } 3035 else 3036 { 3037 int dataIndex = m_dataOrQName.elementAt(identity); 3038 3039 if (dataIndex < 0) 3040 { 3041 dataIndex = -dataIndex; 3042 dataIndex = m_data.elementAt(dataIndex + 1); 3043 } 3044 3045 String str = m_values.get(dataIndex); 3046 3047 if(normalize) 3048 FastStringBuffer.sendNormalizedSAXcharacters(str.toCharArray(), 3049 0, str.length(), ch); 3050 else 3051 ch.characters(str.toCharArray(), 0, str.length()); 3052 } 3053 } 3054 3055 /** 3056 * Given a node handle, return its node value. This is mostly 3057 * as defined by the DOM, but may ignore some conveniences. 3058 * <p> 3059 * 3060 * @param nodeHandle The node id. 3061 * @return String Value of this node, or null if not 3062 * meaningful for this node type. 3063 */ 3064 public String getNodeValue(int nodeHandle) 3065 { 3066 3067 int identity = makeNodeIdentity(nodeHandle); 3068 int type = _type2(identity); 3069 3070 if (type == DTM.TEXT_NODE || type == DTM.CDATA_SECTION_NODE) 3071 { 3072 int dataIndex = _dataOrQName(identity); 3073 if (dataIndex > 0) 3074 { 3075 return m_chars.getString(dataIndex >>> TEXT_LENGTH_BITS, 3076 dataIndex & TEXT_LENGTH_MAX); 3077 } 3078 else 3079 { 3080 return m_chars.getString(m_data.elementAt(-dataIndex), 3081 m_data.elementAt(-dataIndex+1)); 3082 } 3083 } 3084 else if (DTM.ELEMENT_NODE == type || DTM.DOCUMENT_FRAGMENT_NODE == type 3085 || DTM.DOCUMENT_NODE == type) 3086 { 3087 return null; 3088 } 3089 else 3090 { 3091 int dataIndex = m_dataOrQName.elementAt(identity); 3092 3093 if (dataIndex < 0) 3094 { 3095 dataIndex = -dataIndex; 3096 dataIndex = m_data.elementAt(dataIndex + 1); 3097 } 3098 3099 return m_values.get(dataIndex); 3100 } 3101 } 3102 3103 /** 3104 * Copy the String value of a Text node to a SerializationHandler 3105 */ 3106 protected final void copyTextNode(final int nodeID, SerializationHandler handler) 3107 throws SAXException 3108 { 3109 if (nodeID != DTM.NULL) { 3110 int dataIndex = m_dataOrQName.elementAt(nodeID); 3111 if (dataIndex >= 0) { 3112 m_chars.sendSAXcharacters(handler, 3113 dataIndex >>> TEXT_LENGTH_BITS, 3114 dataIndex & TEXT_LENGTH_MAX); 3115 } else { 3116 m_chars.sendSAXcharacters(handler, m_data.elementAt(-dataIndex), 3117 m_data.elementAt(-dataIndex+1)); 3118 } 3119 } 3120 } 3121 3122 /** 3123 * Copy an Element node to a SerializationHandler. 3124 * 3125 * @param nodeID The node identity 3126 * @param exptype The expanded type of the Element node 3127 * @param handler The SerializationHandler 3128 * @return The qualified name of the Element node. 3129 */ 3130 protected final String copyElement(int nodeID, int exptype, 3131 SerializationHandler handler) 3132 throws SAXException 3133 { 3134 final ExtendedType extType = m_extendedTypes[exptype]; 3135 String uri = extType.getNamespace(); 3136 String name = extType.getLocalName(); 3137 3138 if (uri.length() == 0) { 3139 handler.startElement(name); 3140 return name; 3141 } else { 3142 int qnameIndex = m_dataOrQName.elementAt(nodeID); 3143 3144 if (qnameIndex == 0) { 3145 handler.startElement(name); 3146 handler.namespaceAfterStartElement(EMPTY_STR, uri); 3147 return name; 3148 } 3149 3150 if (qnameIndex < 0) { 3151 qnameIndex = -qnameIndex; 3152 qnameIndex = m_data.elementAt(qnameIndex); 3153 } 3154 3155 String qName = m_valuesOrPrefixes.indexToString(qnameIndex); 3156 handler.startElement(qName); 3157 int prefixIndex = qName.indexOf(':'); 3158 String prefix; 3159 if (prefixIndex > 0) { 3160 prefix = qName.substring(0, prefixIndex); 3161 } else { 3162 prefix = null; 3163 } 3164 handler.namespaceAfterStartElement(prefix, uri); 3165 return qName; 3166 } 3167 } 3168 3169 /** 3170 * Copy namespace nodes. 3171 * 3172 * @param nodeID The Element node identity 3173 * @param handler The SerializationHandler 3174 * @param inScope true if all namespaces in scope should be copied, 3175 * false if only the namespace declarations should be copied. 3176 */ 3177 protected final void copyNS(final int nodeID, SerializationHandler handler, boolean inScope) 3178 throws SAXException 3179 { 3180 // %OPT% Optimization for documents which does not have any explicit 3181 // namespace nodes. For these documents, there is an implicit 3182 // namespace node (xmlns:xml="http://www.w3.org/XML/1998/namespace") 3183 // declared on the root element node. In this case, there is no 3184 // need to do namespace copying. We can safely return without 3185 // doing anything. 3186 if (m_namespaceDeclSetElements != null && 3187 m_namespaceDeclSetElements.size() == 1 && 3188 m_namespaceDeclSets != null && 3189 ((SuballocatedIntVector)m_namespaceDeclSets.elementAt(0)) 3190 .size() == 1) 3191 return; 3192 3193 SuballocatedIntVector nsContext = null; 3194 int nextNSNode; 3195 3196 // Find the first namespace node 3197 if (inScope) { 3198 nsContext = findNamespaceContext(nodeID); 3199 if (nsContext == null || nsContext.size() < 1) 3200 return; 3201 else 3202 nextNSNode = makeNodeIdentity(nsContext.elementAt(0)); 3203 } 3204 else 3205 nextNSNode = getNextNamespaceNode2(nodeID); 3206 3207 int nsIndex = 1; 3208 while (nextNSNode != DTM.NULL) { 3209 // Retrieve the name of the namespace node 3210 int eType = _exptype2(nextNSNode); 3211 String nodeName = m_extendedTypes[eType].getLocalName(); 3212 3213 // Retrieve the node value of the namespace node 3214 int dataIndex = m_dataOrQName.elementAt(nextNSNode); 3215 3216 if (dataIndex < 0) { 3217 dataIndex = -dataIndex; 3218 dataIndex = m_data.elementAt(dataIndex + 1); 3219 } 3220 3221 String nodeValue = m_values.get(dataIndex); 3222 3223 handler.namespaceAfterStartElement(nodeName, nodeValue); 3224 3225 if (inScope) { 3226 if (nsIndex < nsContext.size()) { 3227 nextNSNode = makeNodeIdentity(nsContext.elementAt(nsIndex)); 3228 nsIndex++; 3229 } 3230 else 3231 return; 3232 } 3233 else 3234 nextNSNode = getNextNamespaceNode2(nextNSNode); 3235 } 3236 } 3237 3238 /** 3239 * Return the next namespace node following the given base node. 3240 * 3241 * @baseID The node identity of the base node, which can be an 3242 * element, attribute or namespace node. 3243 * @return The namespace node immediately following the base node. 3244 */ 3245 protected final int getNextNamespaceNode2(int baseID) { 3246 int type; 3247 while ((type = _type2(++baseID)) == DTM.ATTRIBUTE_NODE); 3248 3249 if (type == DTM.NAMESPACE_NODE) 3250 return baseID; 3251 else 3252 return NULL; 3253 } 3254 3255 /** 3256 * Copy attribute nodes from an element . 3257 * 3258 * @param nodeID The Element node identity 3259 * @param handler The SerializationHandler 3260 */ 3261 protected final void copyAttributes(final int nodeID, SerializationHandler handler) 3262 throws SAXException{ 3263 3264 for(int current = getFirstAttributeIdentity(nodeID); current != DTM.NULL; current = getNextAttributeIdentity(current)){ 3265 int eType = _exptype2(current); 3266 copyAttribute(current, eType, handler); 3267 } 3268 } 3269 3270 3271 /** 3272 * Copy an Attribute node to a SerializationHandler 3273 * 3274 * @param nodeID The node identity 3275 * @param exptype The expanded type of the Element node 3276 * @param handler The SerializationHandler 3277 */ 3278 protected final void copyAttribute(int nodeID, int exptype, 3279 SerializationHandler handler) 3280 throws SAXException 3281 { 3282 final ExtendedType extType = m_extendedTypes[exptype]; 3283 final String uri = extType.getNamespace(); 3284 final String localName = extType.getLocalName(); 3285 3286 String prefix = null; 3287 String qname = null; 3288 int dataIndex = _dataOrQName(nodeID); 3289 int valueIndex = dataIndex; 3290 if (dataIndex <= 0) { 3291 int prefixIndex = m_data.elementAt(-dataIndex); 3292 valueIndex = m_data.elementAt(-dataIndex+1); 3293 qname = m_valuesOrPrefixes.indexToString(prefixIndex); 3294 int colonIndex = qname.indexOf(':'); 3295 if (colonIndex > 0) { 3296 prefix = qname.substring(0, colonIndex); 3297 } 3298 } 3299 if (uri.length() != 0) { 3300 handler.namespaceAfterStartElement(prefix, uri); 3301 } 3302 3303 String nodeName = (prefix != null) ? qname : localName; 3304 String nodeValue = m_values.get(valueIndex); 3305 3306 handler.addAttribute(uri, localName, nodeName, "CDATA", nodeValue); 3307 } 3308 3309 }