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