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: LocPathIterator.java 468655 2006-10-28 07:12:06Z minchau $ 20 */ 21 package org.apache.xpath.axes; 22 23 import org.apache.xalan.res.XSLMessages; 24 import org.apache.xml.dtm.DTM; 25 import org.apache.xml.dtm.DTMFilter; 26 import org.apache.xml.dtm.DTMIterator; 27 import org.apache.xml.dtm.DTMManager; 28 import org.apache.xml.utils.PrefixResolver; 29 import org.apache.xpath.ExpressionOwner; 30 import org.apache.xpath.XPathContext; 31 import org.apache.xpath.XPathVisitor; 32 import org.apache.xpath.compiler.Compiler; 33 import org.apache.xpath.objects.XNodeSet; 34 import org.apache.xpath.objects.XObject; 35 import org.apache.xpath.res.XPATHErrorResources; 36 37 /** 38 * This class extends NodeSetDTM, which implements NodeIterator, 39 * and fetches nodes one at a time in document order based on a XPath 40 * <a href="http://www.w3.org/TR/xpath#NT-LocationPath>LocationPath</a>. 41 * 42 * <p>If setShouldCacheNodes(true) is called, 43 * as each node is iterated via nextNode(), the node is also stored 44 * in the NodeVector, so that previousNode() can easily be done, except in 45 * the case where the LocPathIterator is "owned" by a UnionPathIterator, 46 * in which case the UnionPathIterator will cache the nodes.</p> 47 * @xsl.usage advanced 48 */ 49 public abstract class LocPathIterator extends PredicatedNodeTest 50 implements Cloneable, DTMIterator, java.io.Serializable, PathComponent 51 { 52 static final long serialVersionUID = -4602476357268405754L; 53 54 /** 55 * Create a LocPathIterator object. 56 * 57 */ LocPathIterator()58 protected LocPathIterator() 59 { 60 } 61 62 63 /** 64 * Create a LocPathIterator object. 65 * 66 * @param nscontext The namespace context for this iterator, 67 * should be OK if null. 68 */ LocPathIterator(PrefixResolver nscontext)69 protected LocPathIterator(PrefixResolver nscontext) 70 { 71 72 setLocPathIterator(this); 73 m_prefixResolver = nscontext; 74 } 75 76 /** 77 * Create a LocPathIterator object, including creation 78 * of step walkers from the opcode list, and call back 79 * into the Compiler to create predicate expressions. 80 * 81 * @param compiler The Compiler which is creating 82 * this expression. 83 * @param opPos The position of this iterator in the 84 * opcode list from the compiler. 85 * 86 * @throws javax.xml.transform.TransformerException 87 */ LocPathIterator(Compiler compiler, int opPos, int analysis)88 protected LocPathIterator(Compiler compiler, int opPos, int analysis) 89 throws javax.xml.transform.TransformerException 90 { 91 this(compiler, opPos, analysis, true); 92 } 93 94 /** 95 * Create a LocPathIterator object, including creation 96 * of step walkers from the opcode list, and call back 97 * into the Compiler to create predicate expressions. 98 * 99 * @param compiler The Compiler which is creating 100 * this expression. 101 * @param opPos The position of this iterator in the 102 * opcode list from the compiler. 103 * @param shouldLoadWalkers True if walkers should be 104 * loaded, or false if this is a derived iterator and 105 * it doesn't wish to load child walkers. 106 * 107 * @throws javax.xml.transform.TransformerException 108 */ LocPathIterator( Compiler compiler, int opPos, int analysis, boolean shouldLoadWalkers)109 protected LocPathIterator( 110 Compiler compiler, int opPos, int analysis, boolean shouldLoadWalkers) 111 throws javax.xml.transform.TransformerException 112 { 113 setLocPathIterator(this); 114 } 115 116 /** 117 * Get the analysis bits for this walker, as defined in the WalkerFactory. 118 * @return One of WalkerFactory#BIT_DESCENDANT, etc. 119 */ getAnalysisBits()120 public int getAnalysisBits() 121 { 122 int axis = getAxis(); 123 int bit = WalkerFactory.getAnalysisBitFromAxes(axis); 124 return bit; 125 } 126 127 /** 128 * Read the object from a serialization stream. 129 * 130 * @param stream Input stream to read from 131 * 132 * @throws java.io.IOException 133 * @throws javax.xml.transform.TransformerException 134 */ readObject(java.io.ObjectInputStream stream)135 private void readObject(java.io.ObjectInputStream stream) 136 throws java.io.IOException, javax.xml.transform.TransformerException 137 { 138 try 139 { 140 stream.defaultReadObject(); 141 m_clones = new IteratorPool(this); 142 } 143 catch (ClassNotFoundException cnfe) 144 { 145 throw new javax.xml.transform.TransformerException(cnfe); 146 } 147 } 148 149 /** 150 * Set the environment in which this iterator operates, which should provide: 151 * a node (the context node... same value as "root" defined below) 152 * a pair of non-zero positive integers (the context position and the context size) 153 * a set of variable bindings 154 * a function library 155 * the set of namespace declarations in scope for the expression. 156 * 157 * <p>At this time the exact implementation of this environment is application 158 * dependent. Probably a proper interface will be created fairly soon.</p> 159 * 160 * @param environment The environment object. 161 */ setEnvironment(Object environment)162 public void setEnvironment(Object environment) 163 { 164 // no-op for now. 165 } 166 167 /** 168 * Get an instance of a DTM that "owns" a node handle. Since a node 169 * iterator may be passed without a DTMManager, this allows the 170 * caller to easily get the DTM using just the iterator. 171 * 172 * @param nodeHandle the nodeHandle. 173 * 174 * @return a non-null DTM reference. 175 */ getDTM(int nodeHandle)176 public DTM getDTM(int nodeHandle) 177 { 178 // %OPT% 179 return m_execContext.getDTM(nodeHandle); 180 } 181 182 /** 183 * Get an instance of the DTMManager. Since a node 184 * iterator may be passed without a DTMManager, this allows the 185 * caller to easily get the DTMManager using just the iterator. 186 * 187 * @return a non-null DTMManager reference. 188 */ getDTMManager()189 public DTMManager getDTMManager() 190 { 191 return m_execContext.getDTMManager(); 192 } 193 194 /** 195 * Execute this iterator, meaning create a clone that can 196 * store state, and initialize it for fast execution from 197 * the current runtime state. When this is called, no actual 198 * query from the current context node is performed. 199 * 200 * @param xctxt The XPath execution context. 201 * 202 * @return An XNodeSet reference that holds this iterator. 203 * 204 * @throws javax.xml.transform.TransformerException 205 */ execute(XPathContext xctxt)206 public XObject execute(XPathContext xctxt) 207 throws javax.xml.transform.TransformerException 208 { 209 210 XNodeSet iter = new XNodeSet((LocPathIterator)m_clones.getInstance()); 211 212 iter.setRoot(xctxt.getCurrentNode(), xctxt); 213 214 return iter; 215 } 216 217 /** 218 * Execute an expression in the XPath runtime context, and return the 219 * result of the expression. 220 * 221 * 222 * @param xctxt The XPath runtime context. 223 * @param handler The target content handler. 224 * 225 * @return The result of the expression in the form of a <code>XObject</code>. 226 * 227 * @throws javax.xml.transform.TransformerException if a runtime exception 228 * occurs. 229 * @throws org.xml.sax.SAXException 230 */ executeCharsToContentHandler( XPathContext xctxt, org.xml.sax.ContentHandler handler)231 public void executeCharsToContentHandler( 232 XPathContext xctxt, org.xml.sax.ContentHandler handler) 233 throws javax.xml.transform.TransformerException, 234 org.xml.sax.SAXException 235 { 236 LocPathIterator clone = (LocPathIterator)m_clones.getInstance(); 237 238 int current = xctxt.getCurrentNode(); 239 clone.setRoot(current, xctxt); 240 241 int node = clone.nextNode(); 242 DTM dtm = clone.getDTM(node); 243 clone.detach(); 244 245 if(node != DTM.NULL) 246 { 247 dtm.dispatchCharactersEvents(node, handler, false); 248 } 249 } 250 251 /** 252 * Given an select expression and a context, evaluate the XPath 253 * and return the resulting iterator. 254 * 255 * @param xctxt The execution context. 256 * @param contextNode The node that "." expresses. 257 * @throws TransformerException thrown if the active ProblemListener decides 258 * the error condition is severe enough to halt processing. 259 * 260 * @throws javax.xml.transform.TransformerException 261 * @xsl.usage experimental 262 */ asIterator( XPathContext xctxt, int contextNode)263 public DTMIterator asIterator( 264 XPathContext xctxt, int contextNode) 265 throws javax.xml.transform.TransformerException 266 { 267 XNodeSet iter = new XNodeSet((LocPathIterator)m_clones.getInstance()); 268 269 iter.setRoot(contextNode, xctxt); 270 271 return iter; 272 } 273 274 275 /** 276 * Tell if the expression is a nodeset expression. 277 * 278 * @return true if the expression can be represented as a nodeset. 279 */ isNodesetExpr()280 public boolean isNodesetExpr() 281 { 282 return true; 283 } 284 285 /** 286 * Return the first node out of the nodeset, if this expression is 287 * a nodeset expression. This is the default implementation for 288 * nodesets. Derived classes should try and override this and return a 289 * value without having to do a clone operation. 290 * @param xctxt The XPath runtime context. 291 * @return the first node out of the nodeset, or DTM.NULL. 292 */ asNode(XPathContext xctxt)293 public int asNode(XPathContext xctxt) 294 throws javax.xml.transform.TransformerException 295 { 296 DTMIterator iter = (DTMIterator)m_clones.getInstance(); 297 298 int current = xctxt.getCurrentNode(); 299 300 iter.setRoot(current, xctxt); 301 302 int next = iter.nextNode(); 303 // m_clones.freeInstance(iter); 304 iter.detach(); 305 return next; 306 } 307 308 /** 309 * Evaluate this operation directly to a boolean. 310 * 311 * @param xctxt The runtime execution context. 312 * 313 * @return The result of the operation as a boolean. 314 * 315 * @throws javax.xml.transform.TransformerException 316 */ bool(XPathContext xctxt)317 public boolean bool(XPathContext xctxt) 318 throws javax.xml.transform.TransformerException 319 { 320 return (asNode(xctxt) != DTM.NULL); 321 } 322 323 324 /** 325 * Set if this is an iterator at the upper level of 326 * the XPath. 327 * 328 * @param b true if this location path is at the top level of the 329 * expression. 330 * @xsl.usage advanced 331 */ setIsTopLevel(boolean b)332 public void setIsTopLevel(boolean b) 333 { 334 m_isTopLevel = b; 335 } 336 337 /** 338 * Get if this is an iterator at the upper level of 339 * the XPath. 340 * 341 * @return true if this location path is at the top level of the 342 * expression. 343 * @xsl.usage advanced 344 */ getIsTopLevel()345 public boolean getIsTopLevel() 346 { 347 return m_isTopLevel; 348 } 349 350 /** 351 * Initialize the context values for this expression 352 * after it is cloned. 353 * 354 * @param context The XPath runtime context for this 355 * transformation. 356 */ setRoot(int context, Object environment)357 public void setRoot(int context, Object environment) 358 { 359 360 m_context = context; 361 362 XPathContext xctxt = (XPathContext)environment; 363 m_execContext = xctxt; 364 m_cdtm = xctxt.getDTM(context); 365 366 m_currentContextNode = context; // only if top level? 367 368 // Yech, shouldn't have to do this. -sb 369 if(null == m_prefixResolver) 370 m_prefixResolver = xctxt.getNamespaceContext(); 371 372 m_lastFetched = DTM.NULL; 373 m_foundLast = false; 374 m_pos = 0; 375 m_length = -1; 376 377 if (m_isTopLevel) 378 this.m_stackFrame = xctxt.getVarStack().getStackFrame(); 379 380 // reset(); 381 } 382 383 /** 384 * Set the next position index of this iterator. 385 * 386 * @param next A value greater than or equal to zero that indicates the next 387 * node position to fetch. 388 */ setNextPosition(int next)389 protected void setNextPosition(int next) 390 { 391 assertion(false, "setNextPosition not supported in this iterator!"); 392 } 393 394 /** 395 * Get the current position, which is one less than 396 * the next nextNode() call will retrieve. i.e. if 397 * you call getCurrentPos() and the return is 0, the next 398 * fetch will take place at index 1. 399 * 400 * @return A value greater than or equal to zero that indicates the next 401 * node position to fetch. 402 */ getCurrentPos()403 public final int getCurrentPos() 404 { 405 return m_pos; 406 } 407 408 409 /** 410 * If setShouldCacheNodes(true) is called, then nodes will 411 * be cached. They are not cached by default. 412 * 413 * @param b True if this iterator should cache nodes. 414 */ setShouldCacheNodes(boolean b)415 public void setShouldCacheNodes(boolean b) 416 { 417 418 assertion(false, "setShouldCacheNodes not supported by this iterater!"); 419 } 420 421 /** 422 * Tells if this iterator can have nodes added to it or set via 423 * the <code>setItem(int node, int index)</code> method. 424 * 425 * @return True if the nodelist can be mutated. 426 */ isMutable()427 public boolean isMutable() 428 { 429 return false; 430 } 431 432 /** 433 * Set the current position in the node set. 434 * 435 * @param i Must be a valid index greater 436 * than or equal to zero and less than m_cachedNodes.size(). 437 */ setCurrentPos(int i)438 public void setCurrentPos(int i) 439 { 440 assertion(false, "setCurrentPos not supported by this iterator!"); 441 } 442 443 /** 444 * Increment the current position in the node set. 445 */ incrementCurrentPos()446 public void incrementCurrentPos() 447 { 448 m_pos++; 449 } 450 451 452 /** 453 * Get the length of the cached nodes. 454 * 455 * <p>Note: for the moment at least, this only returns 456 * the size of the nodes that have been fetched to date, 457 * it doesn't attempt to run to the end to make sure we 458 * have found everything. This should be reviewed.</p> 459 * 460 * @return The size of the current cache list. 461 */ size()462 public int size() 463 { 464 assertion(false, "size() not supported by this iterator!"); 465 return 0; 466 } 467 468 /** 469 * Returns the <code>index</code> th item in the collection. If 470 * <code>index</code> is greater than or equal to the number of nodes in 471 * the list, this returns <code>null</code> . 472 * @param index Index into the collection. 473 * @return The node at the <code>index</code> th position in the 474 * <code>NodeList</code> , or <code>null</code> if that is not a valid 475 * index. 476 */ item(int index)477 public int item(int index) 478 { 479 assertion(false, "item(int index) not supported by this iterator!"); 480 return 0; 481 } 482 483 /** 484 * Sets the node at the specified index of this vector to be the 485 * specified node. The previous component at that position is discarded. 486 * 487 * <p>The index must be a value greater than or equal to 0 and less 488 * than the current size of the vector. 489 * The iterator must be in cached mode.</p> 490 * 491 * <p>Meant to be used for sorted iterators.</p> 492 * 493 * @param node Node to set 494 * @param index Index of where to set the node 495 */ setItem(int node, int index)496 public void setItem(int node, int index) 497 { 498 assertion(false, "setItem not supported by this iterator!"); 499 } 500 501 /** 502 * The number of nodes in the list. The range of valid child node indices 503 * is 0 to <code>length-1</code> inclusive. 504 * 505 * @return The number of nodes in the list, always greater or equal to zero. 506 */ getLength()507 public int getLength() 508 { 509 // Tell if this is being called from within a predicate. 510 boolean isPredicateTest = (this == m_execContext.getSubContextList()); 511 512 // And get how many total predicates are part of this step. 513 int predCount = getPredicateCount(); 514 515 // If we have already calculated the length, and the current predicate 516 // is the first predicate, then return the length. We don't cache 517 // the anything but the length of the list to the first predicate. 518 if (-1 != m_length && isPredicateTest && m_predicateIndex < 1) 519 return m_length; 520 521 // I'm a bit worried about this one, since it doesn't have the 522 // checks found above. I suspect it's fine. -sb 523 if (m_foundLast) 524 return m_pos; 525 526 // Create a clone, and count from the current position to the end 527 // of the list, not taking into account the current predicate and 528 // predicates after the current one. 529 int pos = (m_predicateIndex >= 0) ? getProximityPosition() : m_pos; 530 531 LocPathIterator clone; 532 533 try 534 { 535 clone = (LocPathIterator) clone(); 536 } 537 catch (CloneNotSupportedException cnse) 538 { 539 return -1; 540 } 541 542 // We want to clip off the last predicate, but only if we are a sub 543 // context node list, NOT if we are a context list. See pos68 test, 544 // also test against bug4638. 545 if (predCount > 0 && isPredicateTest) 546 { 547 // Don't call setPredicateCount, because it clones and is slower. 548 clone.m_predCount = m_predicateIndex; 549 // The line above used to be: 550 // clone.m_predCount = predCount - 1; 551 // ...which looks like a dumb bug to me. -sb 552 } 553 554 int next; 555 556 while (DTM.NULL != (next = clone.nextNode())) 557 { 558 pos++; 559 } 560 561 if (isPredicateTest && m_predicateIndex < 1) 562 m_length = pos; 563 564 return pos; 565 } 566 567 /** 568 * Tells if this NodeSetDTM is "fresh", in other words, if 569 * the first nextNode() that is called will return the 570 * first node in the set. 571 * 572 * @return true of nextNode has not been called. 573 */ isFresh()574 public boolean isFresh() 575 { 576 return (m_pos == 0); 577 } 578 579 /** 580 * Returns the previous node in the set and moves the position of the 581 * iterator backwards in the set. 582 * @return The previous <code>Node</code> in the set being iterated over, 583 * or<code>null</code> if there are no more members in that set. 584 */ previousNode()585 public int previousNode() 586 { 587 throw new RuntimeException( 588 XSLMessages.createXPATHMessage(XPATHErrorResources.ER_NODESETDTM_CANNOT_ITERATE, null)); //"This NodeSetDTM can not iterate to a previous node!"); 589 } 590 591 /** 592 * This attribute determines which node types are presented via the 593 * iterator. The available set of constants is defined in the 594 * <code>NodeFilter</code> interface. 595 * 596 * <p>This is somewhat useless at this time, since it doesn't 597 * really return information that tells what this iterator will 598 * show. It is here only to fullfill the DOM NodeIterator 599 * interface.</p> 600 * 601 * @return For now, always NodeFilter.SHOW_ALL & ~NodeFilter.SHOW_ENTITY_REFERENCE. 602 * @see org.w3c.dom.traversal.NodeIterator 603 */ getWhatToShow()604 public int getWhatToShow() 605 { 606 607 // TODO: ?? 608 return DTMFilter.SHOW_ALL & ~DTMFilter.SHOW_ENTITY_REFERENCE; 609 } 610 611 /** 612 * The filter used to screen nodes. Not used at this time, 613 * this is here only to fullfill the DOM NodeIterator 614 * interface. 615 * 616 * @return Always null. 617 * @see org.w3c.dom.traversal.NodeIterator 618 */ getFilter()619 public DTMFilter getFilter() 620 { 621 return null; 622 } 623 624 /** 625 * The root node of the Iterator, as specified when it was created. 626 * 627 * @return The "root" of this iterator, which, in XPath terms, 628 * is the node context for this iterator. 629 */ getRoot()630 public int getRoot() 631 { 632 return m_context; 633 } 634 635 /** 636 * The value of this flag determines whether the children of entity 637 * reference nodes are visible to the iterator. If false, they will be 638 * skipped over. 639 * <br> To produce a view of the document that has entity references 640 * expanded and does not expose the entity reference node itself, use the 641 * whatToShow flags to hide the entity reference node and set 642 * expandEntityReferences to true when creating the iterator. To produce 643 * a view of the document that has entity reference nodes but no entity 644 * expansion, use the whatToShow flags to show the entity reference node 645 * and set expandEntityReferences to false. 646 * 647 * @return Always true, since entity reference nodes are not 648 * visible in the XPath model. 649 */ getExpandEntityReferences()650 public boolean getExpandEntityReferences() 651 { 652 return true; 653 } 654 655 /** Control over whether it is OK for detach to reset the iterator. */ 656 protected boolean m_allowDetach = true; 657 658 /** 659 * Specify if it's OK for detach to release the iterator for reuse. 660 * 661 * @param allowRelease true if it is OK for detach to release this iterator 662 * for pooling. 663 */ allowDetachToRelease(boolean allowRelease)664 public void allowDetachToRelease(boolean allowRelease) 665 { 666 m_allowDetach = allowRelease; 667 } 668 669 /** 670 * Detaches the iterator from the set which it iterated over, releasing 671 * any computational resources and placing the iterator in the INVALID 672 * state. After<code>detach</code> has been invoked, calls to 673 * <code>nextNode</code> or<code>previousNode</code> will raise the 674 * exception INVALID_STATE_ERR. 675 */ detach()676 public void detach() 677 { 678 if(m_allowDetach) 679 { 680 // sb: allow reusing of cached nodes when possible? 681 // m_cachedNodes = null; 682 m_execContext = null; 683 // m_prefixResolver = null; sb: Why would this ever want to be null? 684 m_cdtm = null; 685 m_length = -1; 686 m_pos = 0; 687 m_lastFetched = DTM.NULL; 688 m_context = DTM.NULL; 689 m_currentContextNode = DTM.NULL; 690 691 m_clones.freeInstance(this); 692 } 693 } 694 695 /** 696 * Reset the iterator. 697 */ reset()698 public void reset() 699 { 700 assertion(false, "This iterator can not reset!"); 701 } 702 703 /** 704 * Get a cloned Iterator that is reset to the beginning 705 * of the query. 706 * 707 * @return A cloned NodeIterator set of the start of the query. 708 * 709 * @throws CloneNotSupportedException 710 */ cloneWithReset()711 public DTMIterator cloneWithReset() throws CloneNotSupportedException 712 { 713 LocPathIterator clone; 714 // clone = (LocPathIterator) clone(); 715 clone = (LocPathIterator)m_clones.getInstanceOrThrow(); 716 clone.m_execContext = m_execContext; 717 clone.m_cdtm = m_cdtm; 718 719 clone.m_context = m_context; 720 clone.m_currentContextNode = m_currentContextNode; 721 clone.m_stackFrame = m_stackFrame; 722 723 // clone.reset(); 724 725 return clone; 726 } 727 728 // /** 729 // * Get a cloned LocPathIterator that holds the same 730 // * position as this iterator. 731 // * 732 // * @return A clone of this iterator that holds the same node position. 733 // * 734 // * @throws CloneNotSupportedException 735 // */ 736 // public Object clone() throws CloneNotSupportedException 737 // { 738 // 739 // LocPathIterator clone = (LocPathIterator) super.clone(); 740 // 741 // return clone; 742 // } 743 744 /** 745 * Returns the next node in the set and advances the position of the 746 * iterator in the set. After a NodeIterator is created, the first call 747 * to nextNode() returns the first node in the set. 748 * @return The next <code>Node</code> in the set being iterated over, or 749 * <code>null</code> if there are no more members in that set. 750 */ nextNode()751 public abstract int nextNode(); 752 753 /** 754 * Bottleneck the return of a next node, to make returns 755 * easier from nextNode(). 756 * 757 * @param nextNode The next node found, may be null. 758 * 759 * @return The same node that was passed as an argument. 760 */ returnNextNode(int nextNode)761 protected int returnNextNode(int nextNode) 762 { 763 764 if (DTM.NULL != nextNode) 765 { 766 m_pos++; 767 } 768 769 m_lastFetched = nextNode; 770 771 if (DTM.NULL == nextNode) 772 m_foundLast = true; 773 774 return nextNode; 775 } 776 777 /** 778 * Return the last fetched node. Needed to support the UnionPathIterator. 779 * 780 * @return The last fetched node, or null if the last fetch was null. 781 */ getCurrentNode()782 public int getCurrentNode() 783 { 784 return m_lastFetched; 785 } 786 787 /** 788 * If an index is requested, NodeSetDTM will call this method 789 * to run the iterator to the index. By default this sets 790 * m_next to the index. If the index argument is -1, this 791 * signals that the iterator should be run to the end. 792 * 793 * @param index The index to run to, or -1 if the iterator 794 * should run to the end. 795 */ runTo(int index)796 public void runTo(int index) 797 { 798 799 if (m_foundLast || ((index >= 0) && (index <= getCurrentPos()))) 800 return; 801 802 int n; 803 804 if (-1 == index) 805 { 806 while (DTM.NULL != (n = nextNode())); 807 } 808 else 809 { 810 while (DTM.NULL != (n = nextNode())) 811 { 812 if (getCurrentPos() >= index) 813 break; 814 } 815 } 816 } 817 818 /** 819 * Tells if we've found the last node yet. 820 * 821 * @return true if the last nextNode returned null. 822 */ getFoundLast()823 public final boolean getFoundLast() 824 { 825 return m_foundLast; 826 } 827 828 /** 829 * The XPath execution context we are operating on. 830 * 831 * @return XPath execution context this iterator is operating on, 832 * or null if setRoot has not been called. 833 */ getXPathContext()834 public final XPathContext getXPathContext() 835 { 836 return m_execContext; 837 } 838 839 /** 840 * The node context for the iterator. 841 * 842 * @return The node context, same as getRoot(). 843 */ getContext()844 public final int getContext() 845 { 846 return m_context; 847 } 848 849 /** 850 * The node context from where the expression is being 851 * executed from (i.e. for current() support). 852 * 853 * @return The top-level node context of the entire expression. 854 */ getCurrentContextNode()855 public final int getCurrentContextNode() 856 { 857 return m_currentContextNode; 858 } 859 860 /** 861 * Set the current context node for this iterator. 862 * 863 * @param n Must be a non-null reference to the node context. 864 */ setCurrentContextNode(int n)865 public final void setCurrentContextNode(int n) 866 { 867 m_currentContextNode = n; 868 } 869 870 // /** 871 // * Set the current context node for this iterator. 872 // * 873 // * @param n Must be a non-null reference to the node context. 874 // */ 875 // public void setRoot(int n) 876 // { 877 // m_context = n; 878 // m_cdtm = m_execContext.getDTM(n); 879 // } 880 881 /** 882 * Return the saved reference to the prefix resolver that 883 * was in effect when this iterator was created. 884 * 885 * @return The prefix resolver or this iterator, which may be null. 886 */ getPrefixResolver()887 public final PrefixResolver getPrefixResolver() 888 { 889 if(null == m_prefixResolver) 890 { 891 m_prefixResolver = (PrefixResolver)getExpressionOwner(); 892 } 893 894 return m_prefixResolver; 895 } 896 897 // /** 898 // * Get the analysis pattern built by the WalkerFactory. 899 // * 900 // * @return The analysis pattern built by the WalkerFactory. 901 // */ 902 // int getAnalysis() 903 // { 904 // return m_analysis; 905 // } 906 907 // /** 908 // * Set the analysis pattern built by the WalkerFactory. 909 // * 910 // * @param a The analysis pattern built by the WalkerFactory. 911 // */ 912 // void setAnalysis(int a) 913 // { 914 // m_analysis = a; 915 // } 916 917 /** 918 * @see org.apache.xpath.XPathVisitable#callVisitors(ExpressionOwner, XPathVisitor) 919 */ callVisitors(ExpressionOwner owner, XPathVisitor visitor)920 public void callVisitors(ExpressionOwner owner, XPathVisitor visitor) 921 { 922 if(visitor.visitLocationPath(owner, this)) 923 { 924 visitor.visitStep(owner, this); 925 callPredicateVisitors(visitor); 926 } 927 } 928 929 930 //============= State Data ============= 931 932 /** 933 * The pool for cloned iterators. Iterators need to be cloned 934 * because the hold running state, and thus the original iterator 935 * expression from the stylesheet pool can not be used. 936 */ 937 transient protected IteratorPool m_clones = new IteratorPool(this); 938 939 /** 940 * The dtm of the context node. Careful about using this... it may not 941 * be the dtm of the current node. 942 */ 943 transient protected DTM m_cdtm; 944 945 /** 946 * The stack frame index for this iterator. 947 */ 948 transient int m_stackFrame = -1; 949 950 /** 951 * Value determined at compile time, indicates that this is an 952 * iterator at the top level of the expression, rather than inside 953 * a predicate. 954 * @serial 955 */ 956 private boolean m_isTopLevel = false; 957 958 /** The last node that was fetched, usually by nextNode. */ 959 transient public int m_lastFetched = DTM.NULL; 960 961 /** 962 * The context node for this iterator, which doesn't change through 963 * the course of the iteration. 964 */ 965 transient protected int m_context = DTM.NULL; 966 967 /** 968 * The node context from where the expression is being 969 * executed from (i.e. for current() support). Different 970 * from m_context in that this is the context for the entire 971 * expression, rather than the context for the subexpression. 972 */ 973 transient protected int m_currentContextNode = DTM.NULL; 974 975 /** 976 * The current position of the context node. 977 */ 978 transient protected int m_pos = 0; 979 980 transient protected int m_length = -1; 981 982 /** 983 * Fast access to the current prefix resolver. It isn't really 984 * clear that this is needed. 985 * @serial 986 */ 987 private PrefixResolver m_prefixResolver; 988 989 /** 990 * The XPathContext reference, needed for execution of many 991 * operations. 992 */ 993 transient protected XPathContext m_execContext; 994 995 /** 996 * Returns true if all the nodes in the iteration well be returned in document 997 * order. 998 * 999 * @return true as a default. 1000 */ isDocOrdered()1001 public boolean isDocOrdered() 1002 { 1003 return true; 1004 } 1005 1006 /** 1007 * Returns the axis being iterated, if it is known. 1008 * 1009 * @return Axis.CHILD, etc., or -1 if the axis is not known or is of multiple 1010 * types. 1011 */ getAxis()1012 public int getAxis() 1013 { 1014 return -1; 1015 } 1016 1017 1018 // /** 1019 // * The analysis pattern built by the WalkerFactory. 1020 // * TODO: Move to LocPathIterator. 1021 // * @see org.apache.xpath.axes.WalkerFactory 1022 // * @serial 1023 // */ 1024 // protected int m_analysis = 0x00000000; 1025 /** 1026 * @see PredicatedNodeTest#getLastPos(XPathContext) 1027 */ getLastPos(XPathContext xctxt)1028 public int getLastPos(XPathContext xctxt) 1029 { 1030 return getLength(); 1031 } 1032 1033 } 1034