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 */ DTMDefaultBaseTraversers(DTMManager mgr, Source source, int dtmIdentity, DTMWSFilter whiteSpaceFilter, XMLStringFactory xstringfactory, boolean doIndexing)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 */ DTMDefaultBaseTraversers(DTMManager mgr, Source source, int dtmIdentity, DTMWSFilter whiteSpaceFilter, XMLStringFactory xstringfactory, boolean doIndexing, int blocksize, boolean usePrevsib, boolean newNameTable)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 */ getAxisTraverser(final int axis)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 */ next(int context, int current)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 */ next(int context, int current, int expandedTypeID)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 */ first(int context)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 */ first(int context, int expandedTypeID)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 */ next(int context, int current)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 */ next(int context, int current, int expandedTypeID)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 */ getNextIndexed(int axisRoot, int nextPotential, int expandedTypeID)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 */ first(int context)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 */ first(int context, int expandedTypeID)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 */ next(int context, int current)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 */ next(int context, int current, int expandedTypeID)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 */ isIndexed(int expandedTypeID)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 */ isAfterAxis(int axisRoot, int identity)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 */ axisHasBeenProcessed(int axisRoot)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 */ getNextIndexed(int axisRoot, int nextPotential, int expandedTypeID)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 */ getFirstPotential(int identity)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 */ axisHasBeenProcessed(int axisRoot)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 */ getSubtreeRoot(int handle)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 */ isDescendant(int subtreeRootIdentity, int identity)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 */ isAfterAxis(int axisRoot, int identity)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 */ first(int context, int expandedTypeID)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 */ next(int context, int current)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 */ next(int context, int current, int expandedTypeID)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 */ getFirstPotential(int identity)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 */ first(int context)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 */ next(int context, int current)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 */ first(int context)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 */ first(int context, int expandedTypeID)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 */ next(int context, int current)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 */ next(int context, int current, int expandedTypeID)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 */ next(int context, int current)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 */ next(int context, int current, int expandedTypeID)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 */ next(int context, int current)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 */ next(int context, int current, int expandedTypeID)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 */ next(int context, int current)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 */ next(int context, int current, int expandedTypeID)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 */ first(int context)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 */ first(int current, int expandedTypeID)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 */ next(int context, int current)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 */ next(int context, int current, int expandedTypeID)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 */ isAncestor(int contextIdent, int currentIdent)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 */ next(int context, int current)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 */ next(int context, int current, int expandedTypeID)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 */ next(int context, int current)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 */ next(int context, int current, int expandedTypeID)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 */ next(int context, int current)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 */ next(int context, int current, int expandedTypeID)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 */ first(int context)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 */ first(int context, int expandedTypeID)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 */ next(int context, int current)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 */ next(int context, int current, int expandedTypeID)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 */ first(int context)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 */ first(int context, int expandedTypeID)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 */ next(int context, int current)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 */ next(int context, int current, int expandedTypeID)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 */ first(int context, int expandedTypeID)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 */ next(int context, int current)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 */ next(int context, int current, int expandedTypeID)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 */ getFirstPotential(int identity)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 */ getSubtreeRoot(int handle)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 */ first(int context)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 */ first(int context, int expandedTypeID)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 */ getFirstPotential(int identity)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 */ getSubtreeRoot(int handle)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 */ first(int context)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 */ first(int context, int expandedTypeID)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