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