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