1/* 2 * reserved comment block 3 * DO NOT REMOVE OR ALTER! 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 22package com.sun.org.apache.xml.internal.dtm.ref; 23 24import com.sun.org.apache.xml.internal.dtm.*; 25 26import javax.xml.transform.Source; 27 28import com.sun.org.apache.xml.internal.utils.XMLStringFactory; 29 30import com.sun.org.apache.xml.internal.res.XMLErrorResources; 31import com.sun.org.apache.xml.internal.res.XMLMessages; 32import com.sun.org.apache.xalan.internal.xsltc.dom.NodeCounter; 33 34/** 35 * This class implements the traversers for DTMDefaultBase. 36 * 37 * PLEASE NOTE that the public interface for all traversers should be 38 * in terms of DTM Node Handles... but they may use the internal node 39 * identity indices within their logic, for efficiency's sake. Be very 40 * careful to avoid confusing these when maintaining this code. 41 * */ 42public abstract class DTMDefaultBaseTraversers extends DTMDefaultBase 43{ 44 45 /** 46 * Construct a DTMDefaultBaseTraversers object from a DOM node. 47 * 48 * @param mgr The DTMManager who owns this DTM. 49 * @param source The object that is used to specify the construction source. 50 * @param dtmIdentity The DTM identity ID for this DTM. 51 * @param whiteSpaceFilter The white space filter for this DTM, which may 52 * be null. 53 * @param xstringfactory The factory to use for creating XMLStrings. 54 * @param doIndexing true if the caller considers it worth it to use 55 * indexing schemes. 56 */ 57 public DTMDefaultBaseTraversers(DTMManager mgr, Source source, 58 int dtmIdentity, 59 DTMWSFilter whiteSpaceFilter, 60 XMLStringFactory xstringfactory, 61 boolean doIndexing) 62 { 63 super(mgr, source, dtmIdentity, whiteSpaceFilter, xstringfactory, 64 doIndexing); 65 } 66 67 /** 68 * Construct a DTMDefaultBaseTraversers object from a DOM node. 69 * 70 * @param mgr The DTMManager who owns this DTM. 71 * @param source The object that is used to specify the construction source. 72 * @param dtmIdentity The DTM identity ID for this DTM. 73 * @param whiteSpaceFilter The white space filter for this DTM, which may 74 * be null. 75 * @param xstringfactory The factory to use for creating XMLStrings. 76 * @param doIndexing true if the caller considers it worth it to use 77 * indexing schemes. 78 * @param blocksize The block size of the DTM. 79 * @param usePrevsib true if we want to build the previous sibling node array. 80 * @param newNameTable true if we want to use a new ExpandedNameTable for this DTM. 81 */ 82 public DTMDefaultBaseTraversers(DTMManager mgr, Source source, 83 int dtmIdentity, 84 DTMWSFilter whiteSpaceFilter, 85 XMLStringFactory xstringfactory, 86 boolean doIndexing, 87 int blocksize, 88 boolean usePrevsib, 89 boolean newNameTable) 90 { 91 super(mgr, source, dtmIdentity, whiteSpaceFilter, xstringfactory, 92 doIndexing, blocksize, usePrevsib, newNameTable); 93 } 94 95 /** 96 * This returns a stateless "traverser", that can navigate 97 * over an XPath axis, though perhaps not in document order. 98 * 99 * @param axis One of Axes.ANCESTORORSELF, etc. 100 * 101 * @return A DTMAxisTraverser, or null if the given axis isn't supported. 102 */ 103 public DTMAxisTraverser getAxisTraverser(final int axis) 104 { 105 106 DTMAxisTraverser traverser; 107 108 if (null == m_traversers) // Cache of stateless traversers for this DTM 109 { 110 m_traversers = new DTMAxisTraverser[Axis.getNamesLength()]; 111 traverser = null; 112 } 113 else 114 { 115 traverser = m_traversers[axis]; // Share/reuse existing traverser 116 117 if (traverser != null) 118 return traverser; 119 } 120 121 switch (axis) // Generate new traverser 122 { 123 case Axis.ANCESTOR : 124 traverser = new AncestorTraverser(); 125 break; 126 case Axis.ANCESTORORSELF : 127 traverser = new AncestorOrSelfTraverser(); 128 break; 129 case Axis.ATTRIBUTE : 130 traverser = new AttributeTraverser(); 131 break; 132 case Axis.CHILD : 133 traverser = new ChildTraverser(); 134 break; 135 case Axis.DESCENDANT : 136 traverser = new DescendantTraverser(); 137 break; 138 case Axis.DESCENDANTORSELF : 139 traverser = new DescendantOrSelfTraverser(); 140 break; 141 case Axis.FOLLOWING : 142 traverser = new FollowingTraverser(); 143 break; 144 case Axis.FOLLOWINGSIBLING : 145 traverser = new FollowingSiblingTraverser(); 146 break; 147 case Axis.NAMESPACE : 148 traverser = new NamespaceTraverser(); 149 break; 150 case Axis.NAMESPACEDECLS : 151 traverser = new NamespaceDeclsTraverser(); 152 break; 153 case Axis.PARENT : 154 traverser = new ParentTraverser(); 155 break; 156 case Axis.PRECEDING : 157 traverser = new PrecedingTraverser(); 158 break; 159 case Axis.PRECEDINGSIBLING : 160 traverser = new PrecedingSiblingTraverser(); 161 break; 162 case Axis.SELF : 163 traverser = new SelfTraverser(); 164 break; 165 case Axis.ALL : 166 traverser = new AllFromRootTraverser(); 167 break; 168 case Axis.ALLFROMNODE : 169 traverser = new AllFromNodeTraverser(); 170 break; 171 case Axis.PRECEDINGANDANCESTOR : 172 traverser = new PrecedingAndAncestorTraverser(); 173 break; 174 case Axis.DESCENDANTSFROMROOT : 175 traverser = new DescendantFromRootTraverser(); 176 break; 177 case Axis.DESCENDANTSORSELFFROMROOT : 178 traverser = new DescendantOrSelfFromRootTraverser(); 179 break; 180 case Axis.ROOT : 181 traverser = new RootTraverser(); 182 break; 183 case Axis.FILTEREDLIST : 184 return null; // Don't want to throw an exception for this one. 185 default : 186 throw new DTMException(XMLMessages.createXMLMessage(XMLErrorResources.ER_UNKNOWN_AXIS_TYPE, new Object[]{Integer.toString(axis)})); //"Unknown axis traversal type: "+axis); 187 } 188 189 if (null == traverser) 190 throw new DTMException(XMLMessages.createXMLMessage(XMLErrorResources.ER_AXIS_TRAVERSER_NOT_SUPPORTED, new Object[]{Axis.getNames(axis)})); 191 // "Axis traverser not supported: " 192 // + Axis.names[axis]); 193 194 m_traversers[axis] = traverser; 195 196 return traverser; 197 } 198 199 /** 200 * Implements traversal of the Ancestor access, in reverse document order. 201 */ 202 private class AncestorTraverser extends DTMAxisTraverser 203 { 204 205 /** 206 * Traverse to the next node after the current node. 207 * 208 * @param context The context node if this iteration. 209 * @param current The current node of the iteration. 210 * 211 * @return the next node in the iteration, or DTM.NULL. 212 */ 213 public int next(int context, int current) 214 { 215 return getParent(current); 216 } 217 218 /** 219 * Traverse to the next node after the current node that is matched 220 * by the expanded type ID. 221 * 222 * @param context The context node of this iteration. 223 * @param current The current node of the iteration. 224 * @param expandedTypeID The expanded type ID that must match. 225 * 226 * @return the next node in the iteration, or DTM.NULL. 227 */ 228 public int next(int context, int current, int expandedTypeID) 229 { 230 // Process using identities 231 current = makeNodeIdentity(current); 232 233 while (DTM.NULL != (current = m_parent.elementAt(current))) 234 { 235 if (m_exptype.elementAt(current) == expandedTypeID) 236 return makeNodeHandle(current); 237 } 238 239 return NULL; 240 } 241 } 242 243 /** 244 * Implements traversal of the Ancestor access, in reverse document order. 245 */ 246 private class AncestorOrSelfTraverser extends AncestorTraverser 247 { 248 249 /** 250 * By the nature of the stateless traversal, the context node can not be 251 * returned or the iteration will go into an infinate loop. To see if 252 * the self node should be processed, use this function. 253 * 254 * @param context The context node of this traversal. 255 * 256 * @return the first node in the traversal. 257 */ 258 public int first(int context) 259 { 260 return context; 261 } 262 263 /** 264 * By the nature of the stateless traversal, the context node can not be 265 * returned or the iteration will go into an infinate loop. To see if 266 * the self node should be processed, use this function. If the context 267 * node does not match the expanded type ID, this function will return 268 * false. 269 * 270 * @param context The context node of this traversal. 271 * @param expandedTypeID The expanded type ID that must match. 272 * 273 * @return the first node in the traversal. 274 */ 275 public int first(int context, int expandedTypeID) 276 { 277 return (getExpandedTypeID(context) == expandedTypeID) 278 ? context : next(context, context, expandedTypeID); 279 } 280 } 281 282 /** 283 * Implements traversal of the Attribute access 284 */ 285 private class AttributeTraverser extends DTMAxisTraverser 286 { 287 288 /** 289 * Traverse to the next node after the current node. 290 * 291 * @param context The context node of this iteration. 292 * @param current The current node of the iteration. 293 * 294 * @return the next node in the iteration, or DTM.NULL. 295 */ 296 public int next(int context, int current) 297 { 298 return (context == current) 299 ? getFirstAttribute(context) : getNextAttribute(current); 300 } 301 302 /** 303 * Traverse to the next node after the current node that is matched 304 * by the expanded type ID. 305 * 306 * @param context The context node of this iteration. 307 * @param current The current node of the iteration. 308 * @param expandedTypeID The expanded type ID that must match. 309 * 310 * @return the next node in the iteration, or DTM.NULL. 311 */ 312 public int next(int context, int current, int expandedTypeID) 313 { 314 315 current = (context == current) 316 ? getFirstAttribute(context) : getNextAttribute(current); 317 318 do 319 { 320 if (getExpandedTypeID(current) == expandedTypeID) 321 return current; 322 } 323 while (DTM.NULL != (current = getNextAttribute(current))); 324 325 return NULL; 326 } 327 } 328 329 /** 330 * Implements traversal of the Ancestor access, in reverse document order. 331 */ 332 private class ChildTraverser extends DTMAxisTraverser 333 { 334 335 /** 336 * Get the next indexed node that matches the expanded type ID. Before 337 * calling this function, one should first call 338 * {@link #isIndexed(int) isIndexed} to make sure that the index can 339 * contain nodes that match the given expanded type ID. 340 * 341 * @param axisRoot The root identity of the axis. 342 * @param nextPotential The node found must match or occur after this node. 343 * @param expandedTypeID The expanded type ID for the request. 344 * 345 * @return The node ID or NULL if not found. 346 */ 347 protected int getNextIndexed(int axisRoot, int nextPotential, 348 int expandedTypeID) 349 { 350 351 int nsIndex = m_expandedNameTable.getNamespaceID(expandedTypeID); 352 int lnIndex = m_expandedNameTable.getLocalNameID(expandedTypeID); 353 354 for (; ; ) 355 { 356 int nextID = findElementFromIndex(nsIndex, lnIndex, nextPotential); 357 358 if (NOTPROCESSED != nextID) 359 { 360 int parentID = m_parent.elementAt(nextID); 361 362 // Is it a child? 363 if(parentID == axisRoot) 364 return nextID; 365 366 // If the parent occured before the subtree root, then 367 // we know it is past the child axis. 368 if(parentID < axisRoot) 369 return NULL; 370 371 // Otherwise, it could be a descendant below the subtree root 372 // children, or it could be after the subtree root. So we have 373 // to climb up until the parent is less than the subtree root, in 374 // which case we return NULL, or until it is equal to the subtree 375 // root, in which case we continue to look. 376 do 377 { 378 parentID = m_parent.elementAt(parentID); 379 if(parentID < axisRoot) 380 return NULL; 381 } 382 while(parentID > axisRoot); 383 384 // System.out.println("Found node via index: "+first); 385 nextPotential = nextID+1; 386 continue; 387 } 388 389 nextNode(); 390 391 if(!(m_nextsib.elementAt(axisRoot) == NOTPROCESSED)) 392 break; 393 } 394 395 return DTM.NULL; 396 } 397 398 /** 399 * By the nature of the stateless traversal, the context node can not be 400 * returned or the iteration will go into an infinate loop. So to traverse 401 * an axis, the first function must be used to get the first node. 402 * 403 * <p>This method needs to be overloaded only by those axis that process 404 * the self node. <\p> 405 * 406 * @param context The context node of this traversal. This is the point 407 * that the traversal starts from. 408 * @return the first node in the traversal. 409 */ 410 public int first(int context) 411 { 412 return getFirstChild(context); 413 } 414 415 /** 416 * By the nature of the stateless traversal, the context node can not be 417 * returned or the iteration will go into an infinate loop. So to traverse 418 * an axis, the first function must be used to get the first node. 419 * 420 * <p>This method needs to be overloaded only by those axis that process 421 * the self node. <\p> 422 * 423 * @param context The context node of this traversal. This is the point 424 * of origin for the traversal -- its "root node" or starting point. 425 * @param expandedTypeID The expanded type ID that must match. 426 * 427 * @return the first node in the traversal. 428 */ 429 public int first(int context, int expandedTypeID) 430 { 431 if(true) 432 { 433 int identity = makeNodeIdentity(context); 434 435 int firstMatch = getNextIndexed(identity, _firstch(identity), 436 expandedTypeID); 437 438 return makeNodeHandle(firstMatch); 439 } 440 else 441 { 442 // %REVIEW% Dead code. Eliminate? 443 for (int current = _firstch(makeNodeIdentity(context)); 444 DTM.NULL != current; 445 current = _nextsib(current)) 446 { 447 if (m_exptype.elementAt(current) == expandedTypeID) 448 return makeNodeHandle(current); 449 } 450 return NULL; 451 } 452 } 453 454 /** 455 * Traverse to the next node after the current node. 456 * 457 * @param context The context node of this iteration. 458 * @param current The current node of the iteration. 459 * 460 * @return the next node in the iteration, or DTM.NULL. 461 */ 462 public int next(int context, int current) 463 { 464 return getNextSibling(current); 465 } 466 467 /** 468 * Traverse to the next node after the current node that is matched 469 * by the expanded type ID. 470 * 471 * @param context The context node of this iteration. 472 * @param current The current node of the iteration. 473 * @param expandedTypeID The expanded type ID that must match. 474 * 475 * @return the next node in the iteration, or DTM.NULL. 476 */ 477 public int next(int context, int current, int expandedTypeID) 478 { 479 // Process in Identifier space 480 for (current = _nextsib(makeNodeIdentity(current)); 481 DTM.NULL != current; 482 current = _nextsib(current)) 483 { 484 if (m_exptype.elementAt(current) == expandedTypeID) 485 return makeNodeHandle(current); 486 } 487 488 return NULL; 489 } 490 } 491 492 /** 493 * Super class for derived classes that want a convenient way to access 494 * the indexing mechanism. 495 */ 496 private abstract class IndexedDTMAxisTraverser extends DTMAxisTraverser 497 { 498 499 /** 500 * Tell if the indexing is on and the given expanded type ID matches 501 * what is in the indexes. Derived classes should call this before 502 * calling {@link #getNextIndexed(int, int, int) getNextIndexed} method. 503 * 504 * @param expandedTypeID The expanded type ID being requested. 505 * 506 * @return true if it is OK to call the 507 * {@link #getNextIndexed(int, int, int) getNextIndexed} method. 508 */ 509 protected final boolean isIndexed(int expandedTypeID) 510 { 511 return (m_indexing 512 && ExpandedNameTable.ELEMENT 513 == m_expandedNameTable.getType(expandedTypeID)); 514 } 515 516 /** 517 * Tell if a node is outside the axis being traversed. This method must be 518 * implemented by derived classes, and must be robust enough to handle any 519 * node that occurs after the axis root. 520 * 521 * @param axisRoot The root identity of the axis. 522 * @param identity The node in question. 523 * 524 * @return true if the given node falls outside the axis being traversed. 525 */ 526 protected abstract boolean isAfterAxis(int axisRoot, int identity); 527 528 /** 529 * Tell if the axis has been fully processed to tell if a the wait for 530 * an arriving node should terminate. This method must be implemented 531 * be a derived class. 532 * 533 * @param axisRoot The root identity of the axis. 534 * 535 * @return true if the axis has been fully processed. 536 */ 537 protected abstract boolean axisHasBeenProcessed(int axisRoot); 538 539 /** 540 * Get the next indexed node that matches the expanded type ID. Before 541 * calling this function, one should first call 542 * {@link #isIndexed(int) isIndexed} to make sure that the index can 543 * contain nodes that match the given expanded type ID. 544 * 545 * @param axisRoot The root identity of the axis. 546 * @param nextPotential The node found must match or occur after this node. 547 * @param expandedTypeID The expanded type ID for the request. 548 * 549 * @return The node ID or NULL if not found. 550 */ 551 protected int getNextIndexed(int axisRoot, int nextPotential, 552 int expandedTypeID) 553 { 554 555 int nsIndex = m_expandedNameTable.getNamespaceID(expandedTypeID); 556 int lnIndex = m_expandedNameTable.getLocalNameID(expandedTypeID); 557 558 while(true) 559 { 560 int next = findElementFromIndex(nsIndex, lnIndex, nextPotential); 561 562 if (NOTPROCESSED != next) 563 { 564 if (isAfterAxis(axisRoot, next)) 565 return NULL; 566 567 // System.out.println("Found node via index: "+first); 568 return next; 569 } 570 else if(axisHasBeenProcessed(axisRoot)) 571 break; 572 573 nextNode(); 574 } 575 576 return DTM.NULL; 577 } 578 } 579 580 /** 581 * Implements traversal of the Ancestor access, in reverse document order. 582 */ 583 private class DescendantTraverser extends IndexedDTMAxisTraverser 584 { 585 /** 586 * Get the first potential identity that can be returned. This should 587 * be overridded by classes that need to return the self node. 588 * 589 * @param identity The node identity of the root context of the traversal. 590 * 591 * @return The first potential node that can be in the traversal. 592 */ 593 protected int getFirstPotential(int identity) 594 { 595 return identity + 1; 596 } 597 598 /** 599 * Tell if the axis has been fully processed to tell if a the wait for 600 * an arriving node should terminate. 601 * 602 * @param axisRoot The root identity of the axis. 603 * 604 * @return true if the axis has been fully processed. 605 */ 606 protected boolean axisHasBeenProcessed(int axisRoot) 607 { 608 return !(m_nextsib.elementAt(axisRoot) == NOTPROCESSED); 609 } 610 611 /** 612 * Get the subtree root identity from the handle that was passed in by 613 * the caller. Derived classes may override this to change the root 614 * context of the traversal. 615 * 616 * @param handle handle to the root context. 617 * @return identity of the root of the subtree. 618 */ 619 protected int getSubtreeRoot(int handle) 620 { 621 return makeNodeIdentity(handle); 622 } 623 624 /** 625 * Tell if this node identity is a descendant. Assumes that 626 * the node info for the element has already been obtained. 627 * 628 * %REVIEW% This is really parentFollowsRootInDocumentOrder ... 629 * which fails if the parent starts after the root ends. 630 * May be sufficient for this class's logic, but misleadingly named! 631 * 632 * @param subtreeRootIdentity The root context of the subtree in question. 633 * @param identity The index number of the node in question. 634 * @return true if the index is a descendant of _startNode. 635 */ 636 protected boolean isDescendant(int subtreeRootIdentity, int identity) 637 { 638 return _parent(identity) >= subtreeRootIdentity; 639 } 640 641 /** 642 * Tell if a node is outside the axis being traversed. This method must be 643 * implemented by derived classes, and must be robust enough to handle any 644 * node that occurs after the axis root. 645 * 646 * @param axisRoot The root identity of the axis. 647 * @param identity The node in question. 648 * 649 * @return true if the given node falls outside the axis being traversed. 650 */ 651 protected boolean isAfterAxis(int axisRoot, int identity) 652 { 653 // %REVIEW% Is there *any* cheaper way to do this? 654 // Yes. In ID space, compare to axisRoot's successor 655 // (next-sib or ancestor's-next-sib). Probably shallower search. 656 do 657 { 658 if(identity == axisRoot) 659 return false; 660 identity = m_parent.elementAt(identity); 661 } 662 while(identity >= axisRoot); 663 664 return true; 665 } 666 667 /** 668 * By the nature of the stateless traversal, the context node can not be 669 * returned or the iteration will go into an infinate loop. So to traverse 670 * an axis, the first function must be used to get the first node. 671 * 672 * <p>This method needs to be overloaded only by those axis that process 673 * the self node. <\p> 674 * 675 * @param context The context node of this traversal. This is the point 676 * of origin for the traversal -- its "root node" or starting point. 677 * @param expandedTypeID The expanded type ID that must match. 678 * 679 * @return the first node in the traversal. 680 */ 681 public int first(int context, int expandedTypeID) 682 { 683 684 if (isIndexed(expandedTypeID)) 685 { 686 int identity = getSubtreeRoot(context); 687 int firstPotential = getFirstPotential(identity); 688 689 return makeNodeHandle(getNextIndexed(identity, firstPotential, expandedTypeID)); 690 } 691 692 return next(context, context, expandedTypeID); 693 } 694 695 /** 696 * Traverse to the next node after the current node. 697 * 698 * @param context The context node of this iteration. 699 * @param current The current node of the iteration. 700 * 701 * @return the next node in the iteration, or DTM.NULL. 702 */ 703 public int next(int context, int current) 704 { 705 706 int subtreeRootIdent = getSubtreeRoot(context); 707 708 for (current = makeNodeIdentity(current) + 1; ; current++) 709 { 710 int type = _type(current); // may call nextNode() 711 712 if (!isDescendant(subtreeRootIdent, current)) 713 return NULL; 714 715 if (ATTRIBUTE_NODE == type || NAMESPACE_NODE == type) 716 continue; 717 718 return makeNodeHandle(current); // make handle. 719 } 720 } 721 722 /** 723 * Traverse to the next node after the current node that is matched 724 * by the expanded type ID. 725 * 726 * @param context The context node of this iteration. 727 * @param current The current node of the iteration. 728 * @param expandedTypeID The expanded type ID that must match. 729 * 730 * @return the next node in the iteration, or DTM.NULL. 731 */ 732 public int next(int context, int current, int expandedTypeID) 733 { 734 735 int subtreeRootIdent = getSubtreeRoot(context); 736 737 current = makeNodeIdentity(current) + 1; 738 739 if (isIndexed(expandedTypeID)) 740 { 741 return makeNodeHandle(getNextIndexed(subtreeRootIdent, current, expandedTypeID)); 742 } 743 744 for (; ; current++) 745 { 746 int exptype = _exptype(current); // may call nextNode() 747 748 if (!isDescendant(subtreeRootIdent, current)) 749 return NULL; 750 751 if (exptype != expandedTypeID) 752 continue; 753 754 return makeNodeHandle(current); // make handle. 755 } 756 } 757 } 758 759 /** 760 * Implements traversal of the Ancestor access, in reverse document order. 761 */ 762 private class DescendantOrSelfTraverser extends DescendantTraverser 763 { 764 765 /** 766 * Get the first potential identity that can be returned, which is the 767 * axis context, in this case. 768 * 769 * @param identity The node identity of the root context of the traversal. 770 * 771 * @return The axis context. 772 */ 773 protected int getFirstPotential(int identity) 774 { 775 return identity; 776 } 777 778 /** 779 * By the nature of the stateless traversal, the context node can not be 780 * returned or the iteration will go into an infinate loop. To see if 781 * the self node should be processed, use this function. 782 * 783 * @param context The context node of this traversal. 784 * 785 * @return the first node in the traversal. 786 */ 787 public int first(int context) 788 { 789 return context; 790 } 791 } 792 793 /** 794 * Implements traversal of the entire subtree, including the root node. 795 */ 796 private class AllFromNodeTraverser extends DescendantOrSelfTraverser 797 { 798 799 /** 800 * Traverse to the next node after the current node. 801 * 802 * @param context The context node of this iteration. 803 * @param current The current node of the iteration. 804 * 805 * @return the next node in the iteration, or DTM.NULL. 806 */ 807 public int next(int context, int current) 808 { 809 810 int subtreeRootIdent = makeNodeIdentity(context); 811 812 for (current = makeNodeIdentity(current) + 1; ; current++) 813 { 814 // Trickological code: _exptype() has the side-effect of 815 // running nextNode until the specified node has been loaded, 816 // and thus can be used to ensure that incremental construction of 817 // the DTM has gotten this far. Using it just for that side-effect 818 // is quite a kluge... 819 _exptype(current); // make sure it's here. 820 821 if (!isDescendant(subtreeRootIdent, current)) 822 return NULL; 823 824 return makeNodeHandle(current); // make handle. 825 } 826 } 827 } 828 829 /** 830 * Implements traversal of the following access, in document order. 831 */ 832 private class FollowingTraverser extends DescendantTraverser 833 { 834 835 /** 836 * Get the first of the following. 837 * 838 * @param context The context node of this traversal. This is the point 839 * that the traversal starts from. 840 * @return the first node in the traversal. 841 */ 842 public int first(int context) 843 { 844 // Compute in ID space 845 context=makeNodeIdentity(context); 846 847 int first; 848 int type = _type(context); 849 850 if ((DTM.ATTRIBUTE_NODE == type) || (DTM.NAMESPACE_NODE == type)) 851 { 852 context = _parent(context); 853 first = _firstch(context); 854 855 if (NULL != first) 856 return makeNodeHandle(first); 857 } 858 859 do 860 { 861 first = _nextsib(context); 862 863 if (NULL == first) 864 context = _parent(context); 865 } 866 while (NULL == first && NULL != context); 867 868 return makeNodeHandle(first); 869 } 870 871 /** 872 * Get the first of the following. 873 * 874 * @param context The context node of this traversal. This is the point 875 * of origin for the traversal -- its "root node" or starting point. 876 * @param expandedTypeID The expanded type ID that must match. 877 * 878 * @return the first node in the traversal. 879 */ 880 public int first(int context, int expandedTypeID) 881 { 882 // %REVIEW% This looks like it might want shift into identity space 883 // to avoid repeated conversion in the individual functions 884 int first; 885 int type = getNodeType(context); 886 887 if ((DTM.ATTRIBUTE_NODE == type) || (DTM.NAMESPACE_NODE == type)) 888 { 889 context = getParent(context); 890 first = getFirstChild(context); 891 892 if (NULL != first) 893 { 894 if (getExpandedTypeID(first) == expandedTypeID) 895 return first; 896 else 897 return next(context, first, expandedTypeID); 898 } 899 } 900 901 do 902 { 903 first = getNextSibling(context); 904 905 if (NULL == first) 906 context = getParent(context); 907 else 908 { 909 if (getExpandedTypeID(first) == expandedTypeID) 910 return first; 911 else 912 return next(context, first, expandedTypeID); 913 } 914 } 915 while (NULL == first && NULL != context); 916 917 return first; 918 } 919 920 /** 921 * Traverse to the next node after the current node. 922 * 923 * @param context The context node of this iteration. 924 * @param current The current node of the iteration. 925 * 926 * @return the next node in the iteration, or DTM.NULL. 927 */ 928 public int next(int context, int current) 929 { 930 // Compute in identity space 931 current=makeNodeIdentity(current); 932 933 while (true) 934 { 935 current++; // Only works on IDs, not handles. 936 937 // %REVIEW% Are we using handles or indexes? 938 int type = _type(current); // may call nextNode() 939 940 if (NULL == type) 941 return NULL; 942 943 if (ATTRIBUTE_NODE == type || NAMESPACE_NODE == type) 944 continue; 945 946 return makeNodeHandle(current); // make handle. 947 } 948 } 949 950 /** 951 * Traverse to the next node after the current node that is matched 952 * by the expanded type ID. 953 * 954 * @param context The context node of this iteration. 955 * @param current The current node of the iteration. 956 * @param expandedTypeID The expanded type ID that must match. 957 * 958 * @return the next node in the iteration, or DTM.NULL. 959 */ 960 public int next(int context, int current, int expandedTypeID) 961 { 962 // Compute in ID space 963 current=makeNodeIdentity(current); 964 965 while (true) 966 { 967 current++; 968 969 int etype = _exptype(current); // may call nextNode() 970 971 if (NULL == etype) 972 return NULL; 973 974 if (etype != expandedTypeID) 975 continue; 976 977 return makeNodeHandle(current); // make handle. 978 } 979 } 980 } 981 982 /** 983 * Implements traversal of the Ancestor access, in reverse document order. 984 */ 985 private class FollowingSiblingTraverser extends DTMAxisTraverser 986 { 987 988 /** 989 * Traverse to the next node after the current node. 990 * 991 * @param context The context node of this iteration. 992 * @param current The current node of the iteration. 993 * 994 * @return the next node in the iteration, or DTM.NULL. 995 */ 996 public int next(int context, int current) 997 { 998 return getNextSibling(current); 999 } 1000 1001 /** 1002 * Traverse to the next node after the current node that is matched 1003 * by the expanded type ID. 1004 * 1005 * @param context The context node of this iteration. 1006 * @param current The current node of the iteration. 1007 * @param expandedTypeID The expanded type ID that must match. 1008 * 1009 * @return the next node in the iteration, or DTM.NULL. 1010 */ 1011 public int next(int context, int current, int expandedTypeID) 1012 { 1013 1014 while (DTM.NULL != (current = getNextSibling(current))) 1015 { 1016 if (getExpandedTypeID(current) == expandedTypeID) 1017 return current; 1018 } 1019 1020 return NULL; 1021 } 1022 } 1023 1024 /** 1025 * Implements traversal of the Ancestor access, in reverse document order. 1026 */ 1027 private class NamespaceDeclsTraverser extends DTMAxisTraverser 1028 { 1029 1030 /** 1031 * Traverse to the next node after the current node. 1032 * 1033 * @param context The context node of this iteration. 1034 * @param current The current node of the iteration. 1035 * 1036 * @return the next node in the iteration, or DTM.NULL. 1037 */ 1038 public int next(int context, int current) 1039 { 1040 1041 return (context == current) 1042 ? getFirstNamespaceNode(context, false) 1043 : getNextNamespaceNode(context, current, false); 1044 } 1045 1046 /** 1047 * Traverse to the next node after the current node that is matched 1048 * by the expanded type ID. 1049 * 1050 * @param context The context node of this iteration. 1051 * @param current The current node of the iteration. 1052 * @param expandedTypeID The expanded type ID that must match. 1053 * 1054 * @return the next node in the iteration, or DTM.NULL. 1055 */ 1056 public int next(int context, int current, int expandedTypeID) 1057 { 1058 1059 current = (context == current) 1060 ? getFirstNamespaceNode(context, false) 1061 : getNextNamespaceNode(context, current, false); 1062 1063 do 1064 { 1065 if (getExpandedTypeID(current) == expandedTypeID) 1066 return current; 1067 } 1068 while (DTM.NULL 1069 != (current = getNextNamespaceNode(context, current, false))); 1070 1071 return NULL; 1072 } 1073 } 1074 1075 /** 1076 * Implements traversal of the Ancestor access, in reverse document order. 1077 */ 1078 private class NamespaceTraverser extends DTMAxisTraverser 1079 { 1080 1081 /** 1082 * Traverse to the next node after the current node. 1083 * 1084 * @param context The context node of this iteration. 1085 * @param current The current node of the iteration. 1086 * 1087 * @return the next node in the iteration, or DTM.NULL. 1088 */ 1089 public int next(int context, int current) 1090 { 1091 1092 return (context == current) 1093 ? getFirstNamespaceNode(context, true) 1094 : getNextNamespaceNode(context, current, true); 1095 } 1096 1097 /** 1098 * Traverse to the next node after the current node that is matched 1099 * by the expanded type ID. 1100 * 1101 * @param context The context node of this iteration. 1102 * @param current The current node of the iteration. 1103 * @param expandedTypeID The expanded type ID that must match. 1104 * 1105 * @return the next node in the iteration, or DTM.NULL. 1106 */ 1107 public int next(int context, int current, int expandedTypeID) 1108 { 1109 1110 current = (context == current) 1111 ? getFirstNamespaceNode(context, true) 1112 : getNextNamespaceNode(context, current, true); 1113 1114 do 1115 { 1116 if (getExpandedTypeID(current) == expandedTypeID) 1117 return current; 1118 } 1119 while (DTM.NULL 1120 != (current = getNextNamespaceNode(context, current, true))); 1121 1122 return NULL; 1123 } 1124 } 1125 1126 /** 1127 * Implements traversal of the Ancestor access, in reverse document order. 1128 */ 1129 private class ParentTraverser extends DTMAxisTraverser 1130 { 1131 /** 1132 * By the nature of the stateless traversal, the context node can not be 1133 * returned or the iteration will go into an infinate loop. So to traverse 1134 * an axis, the first function must be used to get the first node. 1135 * 1136 * <p>This method needs to be overloaded only by those axis that process 1137 * the self node. <\p> 1138 * 1139 * @param context The context node of this traversal. This is the point 1140 * that the traversal starts from. 1141 * @return the first node in the traversal. 1142 */ 1143 public int first(int context) 1144 { 1145 return getParent(context); 1146 } 1147 1148 /** 1149 * By the nature of the stateless traversal, the context node can not be 1150 * returned or the iteration will go into an infinate loop. So to traverse 1151 * an axis, the first function must be used to get the first node. 1152 * 1153 * <p>This method needs to be overloaded only by those axis that process 1154 * the self node. <\p> 1155 * 1156 * @param context The context node of this traversal. This is the point 1157 * of origin for the traversal -- its "root node" or starting point. 1158 * @param expandedTypeID The expanded type ID that must match. 1159 * 1160 * @return the first node in the traversal. 1161 */ 1162 public int first(int current, int expandedTypeID) 1163 { 1164 // Compute in ID space 1165 current = makeNodeIdentity(current); 1166 1167 while (NULL != (current = m_parent.elementAt(current))) 1168 { 1169 if (m_exptype.elementAt(current) == expandedTypeID) 1170 return makeNodeHandle(current); 1171 } 1172 1173 return NULL; 1174 } 1175 1176 1177 /** 1178 * Traverse to the next node after the current node. 1179 * 1180 * @param context The context node of this iteration. 1181 * @param current The current node of the iteration. 1182 * 1183 * @return the next node in the iteration, or DTM.NULL. 1184 */ 1185 public int next(int context, int current) 1186 { 1187 1188 return NULL; 1189 } 1190 1191 1192 1193 /** 1194 * Traverse to the next node after the current node that is matched 1195 * by the expanded type ID. 1196 * 1197 * @param context The context node of this iteration. 1198 * @param current The current node of the iteration. 1199 * @param expandedTypeID The expanded type ID that must match. 1200 * 1201 * @return the next node in the iteration, or DTM.NULL. 1202 */ 1203 public int next(int context, int current, int expandedTypeID) 1204 { 1205 1206 return NULL; 1207 } 1208 } 1209 1210 /** 1211 * Implements traversal of the Ancestor access, in reverse document order. 1212 */ 1213 private class PrecedingTraverser extends DTMAxisTraverser 1214 { 1215 1216 /** 1217 * Tell if the current identity is an ancestor of the context identity. 1218 * This is an expensive operation, made worse by the stateless traversal. 1219 * But the preceding axis is used fairly infrequently. 1220 * 1221 * @param contextIdent The context node of the axis traversal. 1222 * @param currentIdent The node in question. 1223 * @return true if the currentIdent node is an ancestor of contextIdent. 1224 */ 1225 protected boolean isAncestor(int contextIdent, int currentIdent) 1226 { 1227 // %REVIEW% See comments in IsAfterAxis; using the "successor" of 1228 // contextIdent is probably more efficient. 1229 for (contextIdent = m_parent.elementAt(contextIdent); DTM.NULL != contextIdent; 1230 contextIdent = m_parent.elementAt(contextIdent)) 1231 { 1232 if (contextIdent == currentIdent) 1233 return true; 1234 } 1235 1236 return false; 1237 } 1238 1239 /** 1240 * Traverse to the next node after the current node. 1241 * 1242 * @param context The context node of this iteration. 1243 * @param current The current node of the iteration. 1244 * 1245 * @return the next node in the iteration, or DTM.NULL. 1246 */ 1247 public int next(int context, int current) 1248 { 1249 // compute in ID space 1250 int subtreeRootIdent = makeNodeIdentity(context); 1251 1252 for (current = makeNodeIdentity(current) - 1; current >= 0; current--) 1253 { 1254 short type = _type(current); 1255 1256 if (ATTRIBUTE_NODE == type || NAMESPACE_NODE == type 1257 || isAncestor(subtreeRootIdent, current)) 1258 continue; 1259 1260 return makeNodeHandle(current); // make handle. 1261 } 1262 1263 return NULL; 1264 } 1265 1266 /** 1267 * Traverse to the next node after the current node that is matched 1268 * by the expanded type ID. 1269 * 1270 * @param context The context node of this iteration. 1271 * @param current The current node of the iteration. 1272 * @param expandedTypeID The expanded type ID that must match. 1273 * 1274 * @return the next node in the iteration, or DTM.NULL. 1275 */ 1276 public int next(int context, int current, int expandedTypeID) 1277 { 1278 // Compute in ID space 1279 int subtreeRootIdent = makeNodeIdentity(context); 1280 1281 for (current = makeNodeIdentity(current) - 1; current >= 0; current--) 1282 { 1283 int exptype = m_exptype.elementAt(current); 1284 1285 if (exptype != expandedTypeID 1286 || isAncestor(subtreeRootIdent, current)) 1287 continue; 1288 1289 return makeNodeHandle(current); // make handle. 1290 } 1291 1292 return NULL; 1293 } 1294 } 1295 1296 /** 1297 * Implements traversal of the Ancestor and the Preceding axis, 1298 * in reverse document order. 1299 */ 1300 private class PrecedingAndAncestorTraverser extends DTMAxisTraverser 1301 { 1302 1303 /** 1304 * Traverse to the next node after the current node. 1305 * 1306 * @param context The context node of this iteration. 1307 * @param current The current node of the iteration. 1308 * 1309 * @return the next node in the iteration, or DTM.NULL. 1310 */ 1311 public int next(int context, int current) 1312 { 1313 // Compute in ID space 1314 int subtreeRootIdent = makeNodeIdentity(context ); 1315 1316 for (current = makeNodeIdentity(current) - 1; current >= 0; current--) 1317 { 1318 short type = _type(current); 1319 1320 if (ATTRIBUTE_NODE == type || NAMESPACE_NODE == type) 1321 continue; 1322 1323 return makeNodeHandle(current); // make handle. 1324 } 1325 1326 return NULL; 1327 } 1328 1329 /** 1330 * Traverse to the next node after the current node that is matched 1331 * by the expanded type ID. 1332 * 1333 * @param context The context node of this iteration. 1334 * @param current The current node of the iteration. 1335 * @param expandedTypeID The expanded type ID that must match. 1336 * 1337 * @return the next node in the iteration, or DTM.NULL. 1338 */ 1339 public int next(int context, int current, int expandedTypeID) 1340 { 1341 // Compute in ID space 1342 int subtreeRootIdent = makeNodeIdentity(context); 1343 1344 for (current = makeNodeIdentity(current) - 1; current >= 0; current--) 1345 { 1346 int exptype = m_exptype.elementAt(current); 1347 1348 if (exptype != expandedTypeID) 1349 continue; 1350 1351 return makeNodeHandle(current); // make handle. 1352 } 1353 1354 return NULL; 1355 } 1356 } 1357 1358 /** 1359 * Implements traversal of the Ancestor access, in reverse document order. 1360 */ 1361 private class PrecedingSiblingTraverser extends DTMAxisTraverser 1362 { 1363 1364 /** 1365 * Traverse to the next node after the current node. 1366 * 1367 * @param context The context node of this iteration. 1368 * @param current The current node of the iteration. 1369 * 1370 * @return the next node in the iteration, or DTM.NULL. 1371 */ 1372 public int next(int context, int current) 1373 { 1374 return getPreviousSibling(current); 1375 } 1376 1377 /** 1378 * Traverse to the next node after the current node that is matched 1379 * by the expanded type ID. 1380 * 1381 * @param context The context node of this iteration. 1382 * @param current The current node of the iteration. 1383 * @param expandedTypeID The expanded type ID that must match. 1384 * 1385 * @return the next node in the iteration, or DTM.NULL. 1386 */ 1387 public int next(int context, int current, int expandedTypeID) 1388 { 1389 1390 while (DTM.NULL != (current = getPreviousSibling(current))) 1391 { 1392 if (getExpandedTypeID(current) == expandedTypeID) 1393 return current; 1394 } 1395 1396 return NULL; 1397 } 1398 } 1399 1400 /** 1401 * Implements traversal of the Self axis. 1402 */ 1403 private class SelfTraverser extends DTMAxisTraverser 1404 { 1405 1406 /** 1407 * By the nature of the stateless traversal, the context node can not be 1408 * returned or the iteration will go into an infinate loop. To see if 1409 * the self node should be processed, use this function. 1410 * 1411 * @param context The context node of this traversal. 1412 * 1413 * @return the first node in the traversal. 1414 */ 1415 public int first(int context) 1416 { 1417 return context; 1418 } 1419 1420 /** 1421 * By the nature of the stateless traversal, the context node can not be 1422 * returned or the iteration will go into an infinate loop. To see if 1423 * the self node should be processed, use this function. If the context 1424 * node does not match the expanded type ID, this function will return 1425 * false. 1426 * 1427 * @param context The context node of this traversal. 1428 * @param expandedTypeID The expanded type ID that must match. 1429 * 1430 * @return the first node in the traversal. 1431 */ 1432 public int first(int context, int expandedTypeID) 1433 { 1434 return (getExpandedTypeID(context) == expandedTypeID) ? context : NULL; 1435 } 1436 1437 /** 1438 * Traverse to the next node after the current node. 1439 * 1440 * @param context The context node of this iteration. 1441 * @param current The current node of the iteration. 1442 * 1443 * @return Always return NULL for this axis. 1444 */ 1445 public int next(int context, int current) 1446 { 1447 return NULL; 1448 } 1449 1450 /** 1451 * Traverse to the next node after the current node that is matched 1452 * by the expanded type ID. 1453 * 1454 * @param context The context node of this iteration. 1455 * @param current The current node of the iteration. 1456 * @param expandedTypeID The expanded type ID that must match. 1457 * 1458 * @return the next node in the iteration, or DTM.NULL. 1459 */ 1460 public int next(int context, int current, int expandedTypeID) 1461 { 1462 return NULL; 1463 } 1464 } 1465 1466 /** 1467 * Implements traversal of the Ancestor access, in reverse document order. 1468 */ 1469 private class AllFromRootTraverser extends AllFromNodeTraverser 1470 { 1471 1472 /** 1473 * Return the root. 1474 * 1475 * @param context The context node of this traversal. 1476 * 1477 * @return the first node in the traversal. 1478 */ 1479 public int first(int context) 1480 { 1481 return getDocumentRoot(context); 1482 } 1483 1484 /** 1485 * Return the root if it matches the expanded type ID. 1486 * 1487 * @param context The context node of this traversal. 1488 * @param expandedTypeID The expanded type ID that must match. 1489 * 1490 * @return the first node in the traversal. 1491 */ 1492 public int first(int context, int expandedTypeID) 1493 { 1494 return (getExpandedTypeID(getDocumentRoot(context)) == expandedTypeID) 1495 ? context : next(context, context, expandedTypeID); 1496 } 1497 1498 /** 1499 * Traverse to the next node after the current node. 1500 * 1501 * @param context The context node of this iteration. 1502 * @param current The current node of the iteration. 1503 * 1504 * @return the next node in the iteration, or DTM.NULL. 1505 */ 1506 public int next(int context, int current) 1507 { 1508 // Compute in ID space 1509 int subtreeRootIdent = makeNodeIdentity(context); 1510 1511 for (current = makeNodeIdentity(current) + 1; ; current++) 1512 { 1513 // Kluge test: Just make sure +1 yielded a real node 1514 int type = _type(current); // may call nextNode() 1515 if (type == NULL) 1516 return NULL; 1517 1518 return makeNodeHandle(current); // make handle. 1519 } 1520 } 1521 1522 /** 1523 * Traverse to the next node after the current node that is matched 1524 * by the expanded type ID. 1525 * 1526 * @param context The context node of this iteration. 1527 * @param current The current node of the iteration. 1528 * @param expandedTypeID The expanded type ID that must match. 1529 * 1530 * @return the next node in the iteration, or DTM.NULL. 1531 */ 1532 public int next(int context, int current, int expandedTypeID) 1533 { 1534 // Compute in ID space 1535 int subtreeRootIdent = makeNodeIdentity(context); 1536 1537 for (current = makeNodeIdentity(current) + 1; ; current++) 1538 { 1539 int exptype = _exptype(current); // may call nextNode() 1540 1541 if (exptype == NULL) 1542 return NULL; 1543 1544 if (exptype != expandedTypeID) 1545 continue; 1546 1547 return makeNodeHandle(current); // make handle. 1548 } 1549 } 1550 } 1551 1552 /** 1553 * Implements traversal of the Self axis. 1554 */ 1555 private class RootTraverser extends AllFromRootTraverser 1556 { 1557 /** 1558 * Return the root if it matches the expanded type ID, 1559 * else return null (nothing found) 1560 * 1561 * @param context The context node of this traversal. 1562 * @param expandedTypeID The expanded type ID that must match. 1563 * 1564 * @return the first node in the traversal. 1565 */ 1566 public int first(int context, int expandedTypeID) 1567 { 1568 int root=getDocumentRoot(context); 1569 return (getExpandedTypeID(root) == expandedTypeID) 1570 ? root : NULL; 1571 } 1572 1573 /** 1574 * Traverse to the next node after the current node. 1575 * 1576 * @param context The context node of this iteration. 1577 * @param current The current node of the iteration. 1578 * 1579 * @return Always return NULL for this axis. 1580 */ 1581 public int next(int context, int current) 1582 { 1583 return NULL; 1584 } 1585 1586 /** 1587 * Traverse to the next node after the current node that is matched 1588 * by the expanded type ID. 1589 * 1590 * @param context The context node of this iteration. 1591 * @param current The current node of the iteration. 1592 * @param expandedTypeID The expanded type ID that must match. 1593 * 1594 * @return the next node in the iteration, or DTM.NULL. 1595 */ 1596 public int next(int context, int current, int expandedTypeID) 1597 { 1598 return NULL; 1599 } 1600 } 1601 1602 /** 1603 * A non-xpath axis, returns all nodes that aren't namespaces or attributes, 1604 * from and including the root. 1605 */ 1606 private class DescendantOrSelfFromRootTraverser extends DescendantTraverser 1607 { 1608 1609 /** 1610 * Get the first potential identity that can be returned, which is the axis 1611 * root context in this case. 1612 * 1613 * @param identity The node identity of the root context of the traversal. 1614 * 1615 * @return The identity argument. 1616 */ 1617 protected int getFirstPotential(int identity) 1618 { 1619 return identity; 1620 } 1621 1622 /** 1623 * Get the first potential identity that can be returned. 1624 * @param handle handle to the root context. 1625 * @return identity of the root of the subtree. 1626 */ 1627 protected int getSubtreeRoot(int handle) 1628 { 1629 // %REVIEW% Shouldn't this always be 0? 1630 return makeNodeIdentity(getDocument()); 1631 } 1632 1633 /** 1634 * Return the root. 1635 * 1636 * @param context The context node of this traversal. 1637 * 1638 * @return the first node in the traversal. 1639 */ 1640 public int first(int context) 1641 { 1642 return getDocumentRoot(context); 1643 } 1644 1645 /** 1646 * By the nature of the stateless traversal, the context node can not be 1647 * returned or the iteration will go into an infinate loop. So to traverse 1648 * an axis, the first function must be used to get the first node. 1649 * 1650 * <p>This method needs to be overloaded only by those axis that process 1651 * the self node. <\p> 1652 * 1653 * @param context The context node of this traversal. This is the point 1654 * of origin for the traversal -- its "root node" or starting point. 1655 * @param expandedTypeID The expanded type ID that must match. 1656 * 1657 * @return the first node in the traversal. 1658 */ 1659 public int first(int context, int expandedTypeID) 1660 { 1661 if (isIndexed(expandedTypeID)) 1662 { 1663 int identity = 0; 1664 int firstPotential = getFirstPotential(identity); 1665 1666 return makeNodeHandle(getNextIndexed(identity, firstPotential, expandedTypeID)); 1667 } 1668 1669 int root = first(context); 1670 return next(root, root, expandedTypeID); 1671 } 1672 } 1673 1674 /** 1675 * A non-xpath axis, returns all nodes that aren't namespaces or attributes, 1676 * from but not including the root. 1677 */ 1678 private class DescendantFromRootTraverser extends DescendantTraverser 1679 { 1680 1681 /** 1682 * Get the first potential identity that can be returned, which is the axis 1683 * root context in this case. 1684 * 1685 * @param identity The node identity of the root context of the traversal. 1686 * 1687 * @return The identity argument. 1688 */ 1689 protected int getFirstPotential(int identity) 1690 { 1691 return _firstch(0); 1692 } 1693 1694 /** 1695 * Get the first potential identity that can be returned. 1696 * @param handle handle to the root context. 1697 * @return identity of the root of the subtree. 1698 */ 1699 protected int getSubtreeRoot(int handle) 1700 { 1701 return 0; 1702 } 1703 1704 /** 1705 * Return the root. 1706 * 1707 * @param context The context node of this traversal. 1708 * 1709 * @return the first node in the traversal. 1710 */ 1711 public int first(int context) 1712 { 1713 return makeNodeHandle(_firstch(0)); 1714 } 1715 1716 /** 1717 * By the nature of the stateless traversal, the context node can not be 1718 * returned or the iteration will go into an infinate loop. So to traverse 1719 * an axis, the first function must be used to get the first node. 1720 * 1721 * <p>This method needs to be overloaded only by those axis that process 1722 * the self node. <\p> 1723 * 1724 * @param context The context node of this traversal. This is the point 1725 * of origin for the traversal -- its "root node" or starting point. 1726 * @param expandedTypeID The expanded type ID that must match. 1727 * 1728 * @return the first node in the traversal. 1729 */ 1730 public int first(int context, int expandedTypeID) 1731 { 1732 if (isIndexed(expandedTypeID)) 1733 { 1734 int identity = 0; 1735 int firstPotential = getFirstPotential(identity); 1736 1737 return makeNodeHandle(getNextIndexed(identity, firstPotential, expandedTypeID)); 1738 } 1739 1740 int root = getDocumentRoot(context); 1741 return next(root, root, expandedTypeID); 1742 } 1743 1744 } 1745 1746} 1747