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