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