| /* |
| * The Apache Software License, Version 1.1 |
| * |
| * |
| * Copyright (c) 1999 The Apache Software Foundation. All rights |
| * reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in |
| * the documentation and/or other materials provided with the |
| * distribution. |
| * |
| * 3. The end-user documentation included with the redistribution, |
| * if any, must include the following acknowledgment: |
| * "This product includes software developed by the |
| * Apache Software Foundation (http://www.apache.org/)." |
| * Alternately, this acknowledgment may appear in the software itself, |
| * if and wherever such third-party acknowledgments normally appear. |
| * |
| * 4. The names "Xalan" and "Apache Software Foundation" must |
| * not be used to endorse or promote products derived from this |
| * software without prior written permission. For written |
| * permission, please contact apache@apache.org. |
| * |
| * 5. Products derived from this software may not be called "Apache", |
| * nor may "Apache" appear in their name, without prior written |
| * permission of the Apache Software Foundation. |
| * |
| * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED |
| * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
| * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
| * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR |
| * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF |
| * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
| * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, |
| * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT |
| * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
| * SUCH DAMAGE. |
| * ==================================================================== |
| * |
| * This software consists of voluntary contributions made by many |
| * individuals on behalf of the Apache Software Foundation and was |
| * originally based on software copyright (c) 1999, Lotus |
| * Development Corporation., http://www.lotus.com. For more |
| * information on the Apache Software Foundation, please see |
| * <http://www.apache.org/>. |
| */ |
| package org.apache.xpath.axes; |
| |
| // Java library imports |
| import java.io.IOException; |
| import java.io.ObjectInputStream; |
| import java.io.Serializable; |
| |
| import javax.xml.transform.TransformerException; |
| import org.apache.xml.dtm.DTM; |
| import org.apache.xml.dtm.DTMFilter; |
| import org.apache.xml.dtm.DTMIterator; |
| import org.apache.xml.dtm.DTMManager; |
| import org.apache.xml.utils.PrefixResolver; |
| import org.apache.xpath.ExpressionOwner; |
| import org.apache.xpath.XPathContext; |
| import org.apache.xpath.XPathVisitor; |
| import org.apache.xpath.compiler.Compiler; |
| import org.apache.xpath.objects.XNodeSet; |
| import org.apache.xpath.objects.XObject; |
| import org.apache.xpath.res.XPATHErrorResources; |
| import org.apache.xalan.res.XSLMessages; |
| import org.xml.sax.ContentHandler; |
| import org.xml.sax.SAXException; |
| |
| /** |
| * <meta name="usage" content="advanced"/> |
| * This class extends NodeSetDTM, which implements NodeIterator, |
| * and fetches nodes one at a time in document order based on a XPath |
| * <a href="http://www.w3.org/TR/xpath#NT-LocationPath>LocationPath</a>. |
| * |
| * <p>If setShouldCacheNodes(true) is called, |
| * as each node is iterated via nextNode(), the node is also stored |
| * in the NodeVector, so that previousNode() can easily be done, except in |
| * the case where the LocPathIterator is "owned" by a UnionPathIterator, |
| * in which case the UnionPathIterator will cache the nodes.</p> |
| */ |
| public abstract class LocPathIterator extends PredicatedNodeTest |
| implements Cloneable, DTMIterator, java.io.Serializable, PathComponent |
| { |
| |
| /** |
| * Create a LocPathIterator object. |
| * |
| * @param nscontext The namespace context for this iterator, |
| * should be OK if null. |
| */ |
| protected LocPathIterator() |
| { |
| } |
| |
| |
| /** |
| * Create a LocPathIterator object. |
| * |
| * @param nscontext The namespace context for this iterator, |
| * should be OK if null. |
| */ |
| protected LocPathIterator(PrefixResolver nscontext) |
| { |
| |
| setLocPathIterator(this); |
| m_prefixResolver = nscontext; |
| } |
| |
| /** |
| * Create a LocPathIterator object, including creation |
| * of step walkers from the opcode list, and call back |
| * into the Compiler to create predicate expressions. |
| * |
| * @param compiler The Compiler which is creating |
| * this expression. |
| * @param opPos The position of this iterator in the |
| * opcode list from the compiler. |
| * |
| * @throws javax.xml.transform.TransformerException |
| */ |
| protected LocPathIterator(Compiler compiler, int opPos, int analysis) |
| throws javax.xml.transform.TransformerException |
| { |
| this(compiler, opPos, analysis, true); |
| } |
| |
| /** |
| * Create a LocPathIterator object, including creation |
| * of step walkers from the opcode list, and call back |
| * into the Compiler to create predicate expressions. |
| * |
| * @param compiler The Compiler which is creating |
| * this expression. |
| * @param opPos The position of this iterator in the |
| * opcode list from the compiler. |
| * @param shouldLoadWalkers True if walkers should be |
| * loaded, or false if this is a derived iterator and |
| * it doesn't wish to load child walkers. |
| * |
| * @throws javax.xml.transform.TransformerException |
| */ |
| protected LocPathIterator( |
| Compiler compiler, int opPos, int analysis, boolean shouldLoadWalkers) |
| throws javax.xml.transform.TransformerException |
| { |
| setLocPathIterator(this); |
| } |
| |
| /** |
| * Get the analysis bits for this walker, as defined in the WalkerFactory. |
| * @return One of WalkerFactory#BIT_DESCENDANT, etc. |
| */ |
| public int getAnalysisBits() |
| { |
| int axis = getAxis(); |
| int bit = WalkerFactory.getAnalysisBitFromAxes(axis); |
| return bit; |
| } |
| |
| /** |
| * Read the object from a serialization stream. |
| * |
| * @param stream Input stream to read from |
| * |
| * @throws java.io.IOException |
| * @throws javax.xml.transform.TransformerException |
| */ |
| private void readObject(java.io.ObjectInputStream stream) |
| throws java.io.IOException, javax.xml.transform.TransformerException |
| { |
| try |
| { |
| stream.defaultReadObject(); |
| m_clones = new IteratorPool(this); |
| } |
| catch (ClassNotFoundException cnfe) |
| { |
| throw new javax.xml.transform.TransformerException(cnfe); |
| } |
| } |
| |
| /** |
| * Set the environment in which this iterator operates, which should provide: |
| * a node (the context node... same value as "root" defined below) |
| * a pair of non-zero positive integers (the context position and the context size) |
| * a set of variable bindings |
| * a function library |
| * the set of namespace declarations in scope for the expression. |
| * |
| * <p>At this time the exact implementation of this environment is application |
| * dependent. Probably a proper interface will be created fairly soon.</p> |
| * |
| * @param environment The environment object. |
| */ |
| public void setEnvironment(Object environment) |
| { |
| // no-op for now. |
| } |
| |
| /** |
| * Get an instance of a DTM that "owns" a node handle. Since a node |
| * iterator may be passed without a DTMManager, this allows the |
| * caller to easily get the DTM using just the iterator. |
| * |
| * @param nodeHandle the nodeHandle. |
| * |
| * @return a non-null DTM reference. |
| */ |
| public DTM getDTM(int nodeHandle) |
| { |
| // %OPT% |
| return m_execContext.getDTM(nodeHandle); |
| } |
| |
| /** |
| * Get an instance of the DTMManager. Since a node |
| * iterator may be passed without a DTMManager, this allows the |
| * caller to easily get the DTMManager using just the iterator. |
| * |
| * @return a non-null DTMManager reference. |
| */ |
| public DTMManager getDTMManager() |
| { |
| return m_execContext.getDTMManager(); |
| } |
| |
| /** |
| * Execute this iterator, meaning create a clone that can |
| * store state, and initialize it for fast execution from |
| * the current runtime state. When this is called, no actual |
| * query from the current context node is performed. |
| * |
| * @param xctxt The XPath execution context. |
| * |
| * @return An XNodeSet reference that holds this iterator. |
| * |
| * @throws javax.xml.transform.TransformerException |
| */ |
| public XObject execute(XPathContext xctxt) |
| throws javax.xml.transform.TransformerException |
| { |
| |
| XNodeSet iter = new XNodeSet((LocPathIterator)m_clones.getInstance()); |
| |
| iter.setRoot(xctxt.getCurrentNode(), xctxt); |
| |
| return iter; |
| } |
| |
| /** |
| * Execute an expression in the XPath runtime context, and return the |
| * result of the expression. |
| * |
| * |
| * @param xctxt The XPath runtime context. |
| * @param handler The target content handler. |
| * |
| * @return The result of the expression in the form of a <code>XObject</code>. |
| * |
| * @throws javax.xml.transform.TransformerException if a runtime exception |
| * occurs. |
| * @throws org.xml.sax.SAXException |
| */ |
| public void executeCharsToContentHandler( |
| XPathContext xctxt, org.xml.sax.ContentHandler handler) |
| throws javax.xml.transform.TransformerException, |
| org.xml.sax.SAXException |
| { |
| LocPathIterator clone = (LocPathIterator)m_clones.getInstance(); |
| |
| int current = xctxt.getCurrentNode(); |
| clone.setRoot(current, xctxt); |
| |
| int node = clone.nextNode(); |
| DTM dtm = clone.getDTM(node); |
| clone.detach(); |
| |
| if(node != DTM.NULL) |
| { |
| dtm.dispatchCharactersEvents(node, handler, false); |
| } |
| } |
| |
| /** |
| * <meta name="usage" content="experimental"/> |
| * Given an select expression and a context, evaluate the XPath |
| * and return the resulting iterator. |
| * |
| * @param xctxt The execution context. |
| * @param contextNode The node that "." expresses. |
| * @param namespaceContext The context in which namespaces in the |
| * XPath are supposed to be expanded. |
| * |
| * @throws TransformerException thrown if the active ProblemListener decides |
| * the error condition is severe enough to halt processing. |
| * |
| * @throws javax.xml.transform.TransformerException |
| */ |
| public DTMIterator asIterator( |
| XPathContext xctxt, int contextNode) |
| throws javax.xml.transform.TransformerException |
| { |
| XNodeSet iter = new XNodeSet((LocPathIterator)m_clones.getInstance()); |
| |
| iter.setRoot(contextNode, xctxt); |
| |
| return iter; |
| } |
| |
| |
| /** |
| * Tell if the expression is a nodeset expression. In other words, tell |
| * if you can execute {@link asNode() asNode} without an exception. |
| * @return true if the expression can be represented as a nodeset. |
| */ |
| public boolean isNodesetExpr() |
| { |
| return true; |
| } |
| |
| /** |
| * Return the first node out of the nodeset, if this expression is |
| * a nodeset expression. This is the default implementation for |
| * nodesets. Derived classes should try and override this and return a |
| * value without having to do a clone operation. |
| * @param xctxt The XPath runtime context. |
| * @return the first node out of the nodeset, or DTM.NULL. |
| */ |
| public int asNode(XPathContext xctxt) |
| throws javax.xml.transform.TransformerException |
| { |
| DTMIterator iter = (DTMIterator)m_clones.getInstance(); |
| |
| int current = xctxt.getCurrentNode(); |
| |
| iter.setRoot(current, xctxt); |
| |
| int next = iter.nextNode(); |
| // m_clones.freeInstance(iter); |
| iter.detach(); |
| return next; |
| } |
| |
| /** |
| * Evaluate this operation directly to a boolean. |
| * |
| * @param xctxt The runtime execution context. |
| * |
| * @return The result of the operation as a boolean. |
| * |
| * @throws javax.xml.transform.TransformerException |
| */ |
| public boolean bool(XPathContext xctxt) |
| throws javax.xml.transform.TransformerException |
| { |
| return (asNode(xctxt) != DTM.NULL); |
| } |
| |
| |
| /** |
| * <meta name="usage" content="advanced"/> |
| * Set if this is an iterator at the upper level of |
| * the XPath. |
| * |
| * @param b true if this location path is at the top level of the |
| * expression. |
| */ |
| public void setIsTopLevel(boolean b) |
| { |
| m_isTopLevel = b; |
| } |
| |
| /** |
| * <meta name="usage" content="advanced"/> |
| * Get if this is an iterator at the upper level of |
| * the XPath. |
| * |
| * @return true if this location path is at the top level of the |
| * expression. |
| */ |
| public boolean getIsTopLevel() |
| { |
| return m_isTopLevel; |
| } |
| |
| /** |
| * Initialize the context values for this expression |
| * after it is cloned. |
| * |
| * @param execContext The XPath runtime context for this |
| * transformation. |
| */ |
| public void setRoot(int context, Object environment) |
| { |
| |
| m_context = context; |
| |
| XPathContext xctxt = (XPathContext)environment; |
| m_execContext = xctxt; |
| m_cdtm = xctxt.getDTM(context); |
| |
| m_currentContextNode = context; // only if top level? |
| |
| // Yech, shouldn't have to do this. -sb |
| if(null == m_prefixResolver) |
| m_prefixResolver = xctxt.getNamespaceContext(); |
| |
| m_lastFetched = DTM.NULL; |
| m_foundLast = false; |
| m_pos = 0; |
| m_length = -1; |
| |
| if (m_isTopLevel) |
| this.m_stackFrame = xctxt.getVarStack().getStackFrame(); |
| |
| // reset(); |
| } |
| |
| /** |
| * Set the next position index of this iterator. |
| * |
| * @param next A value greater than or equal to zero that indicates the next |
| * node position to fetch. |
| */ |
| protected void setNextPosition(int next) |
| { |
| assertion(false, "setNextPosition not supported in this iterator!"); |
| } |
| |
| /** |
| * Get the current position, which is one less than |
| * the next nextNode() call will retrieve. i.e. if |
| * you call getCurrentPos() and the return is 0, the next |
| * fetch will take place at index 1. |
| * |
| * @return A value greater than or equal to zero that indicates the next |
| * node position to fetch. |
| */ |
| public final int getCurrentPos() |
| { |
| return m_pos; |
| } |
| |
| |
| /** |
| * If setShouldCacheNodes(true) is called, then nodes will |
| * be cached. They are not cached by default. |
| * |
| * @param b True if this iterator should cache nodes. |
| */ |
| public void setShouldCacheNodes(boolean b) |
| { |
| |
| assertion(false, "setShouldCacheNodes not supported by this iterater!"); |
| } |
| |
| /** |
| * Tells if this iterator can have nodes added to it or set via |
| * the <code>setItem(int node, int index)</code> method. |
| * |
| * @return True if the nodelist can be mutated. |
| */ |
| public boolean isMutable() |
| { |
| return false; |
| } |
| |
| /** |
| * Set the current position in the node set. |
| * |
| * @param i Must be a valid index greater |
| * than or equal to zero and less than m_cachedNodes.size(). |
| */ |
| public void setCurrentPos(int i) |
| { |
| assertion(false, "setCurrentPos not supported by this iterator!"); |
| } |
| |
| /** |
| * Increment the current position in the node set. |
| */ |
| public void incrementCurrentPos() |
| { |
| m_pos++; |
| } |
| |
| |
| /** |
| * Get the length of the cached nodes. |
| * |
| * <p>Note: for the moment at least, this only returns |
| * the size of the nodes that have been fetched to date, |
| * it doesn't attempt to run to the end to make sure we |
| * have found everything. This should be reviewed.</p> |
| * |
| * @return The size of the current cache list. |
| */ |
| public int size() |
| { |
| assertion(false, "size() not supported by this iterator!"); |
| return 0; |
| } |
| |
| /** |
| * Returns the <code>index</code> th item in the collection. If |
| * <code>index</code> is greater than or equal to the number of nodes in |
| * the list, this returns <code>null</code> . |
| * @param index Index into the collection. |
| * @return The node at the <code>index</code> th position in the |
| * <code>NodeList</code> , or <code>null</code> if that is not a valid |
| * index. |
| */ |
| public int item(int index) |
| { |
| assertion(false, "item(int index) not supported by this iterator!"); |
| return 0; |
| } |
| |
| /** |
| * Sets the node at the specified index of this vector to be the |
| * specified node. The previous component at that position is discarded. |
| * |
| * <p>The index must be a value greater than or equal to 0 and less |
| * than the current size of the vector. |
| * The iterator must be in cached mode.</p> |
| * |
| * <p>Meant to be used for sorted iterators.</p> |
| * |
| * @param node Node to set |
| * @param index Index of where to set the node |
| */ |
| public void setItem(int node, int index) |
| { |
| assertion(false, "setItem not supported by this iterator!"); |
| } |
| |
| /** |
| * The number of nodes in the list. The range of valid child node indices |
| * is 0 to <code>length-1</code> inclusive. |
| * |
| * @return The number of nodes in the list, always greater or equal to zero. |
| */ |
| public int getLength() |
| { |
| // Tell if this is being called from within a predicate. |
| boolean isPredicateTest = (this == m_execContext.getSubContextList()); |
| |
| // And get how many total predicates are part of this step. |
| int predCount = getPredicateCount(); |
| |
| // If we have already calculated the length, and the current predicate |
| // is the first predicate, then return the length. We don't cache |
| // the anything but the length of the list to the first predicate. |
| if (-1 != m_length && isPredicateTest && m_predicateIndex < 1) |
| return m_length; |
| |
| // I'm a bit worried about this one, since it doesn't have the |
| // checks found above. I suspect it's fine. -sb |
| if (m_foundLast) |
| return m_pos; |
| |
| // Create a clone, and count from the current position to the end |
| // of the list, not taking into account the current predicate and |
| // predicates after the current one. |
| int pos = (m_predicateIndex >= 0) ? getProximityPosition() : m_pos; |
| |
| LocPathIterator clone; |
| |
| try |
| { |
| clone = (LocPathIterator) clone(); |
| } |
| catch (CloneNotSupportedException cnse) |
| { |
| return -1; |
| } |
| |
| // We want to clip off the last predicate, but only if we are a sub |
| // context node list, NOT if we are a context list. See pos68 test, |
| // also test against bug4638. |
| if (predCount > 0 && isPredicateTest) |
| { |
| // Don't call setPredicateCount, because it clones and is slower. |
| clone.m_predCount = m_predicateIndex; |
| // The line above used to be: |
| // clone.m_predCount = predCount - 1; |
| // ...which looks like a dumb bug to me. -sb |
| } |
| |
| int next; |
| |
| while (DTM.NULL != (next = clone.nextNode())) |
| { |
| pos++; |
| } |
| |
| if (isPredicateTest && m_predicateIndex < 1) |
| m_length = pos; |
| |
| return pos; |
| } |
| |
| /** |
| * Tells if this NodeSetDTM is "fresh", in other words, if |
| * the first nextNode() that is called will return the |
| * first node in the set. |
| * |
| * @return true of nextNode has not been called. |
| */ |
| public boolean isFresh() |
| { |
| return (m_pos == 0); |
| } |
| |
| /** |
| * Returns the previous node in the set and moves the position of the |
| * iterator backwards in the set. |
| * @return The previous <code>Node</code> in the set being iterated over, |
| * or<code>null</code> if there are no more members in that set. |
| */ |
| public int previousNode() |
| { |
| throw new RuntimeException( |
| XSLMessages.createXPATHMessage(XPATHErrorResources.ER_NODESETDTM_CANNOT_ITERATE, null)); //"This NodeSetDTM can not iterate to a previous node!"); |
| } |
| |
| /** |
| * This attribute determines which node types are presented via the |
| * iterator. The available set of constants is defined in the |
| * <code>NodeFilter</code> interface. |
| * |
| * <p>This is somewhat useless at this time, since it doesn't |
| * really return information that tells what this iterator will |
| * show. It is here only to fullfill the DOM NodeIterator |
| * interface.</p> |
| * |
| * @return For now, always NodeFilter.SHOW_ALL & ~NodeFilter.SHOW_ENTITY_REFERENCE. |
| * @see org.w3c.dom.traversal.NodeIterator |
| */ |
| public int getWhatToShow() |
| { |
| |
| // TODO: ?? |
| return DTMFilter.SHOW_ALL & ~DTMFilter.SHOW_ENTITY_REFERENCE; |
| } |
| |
| /** |
| * The filter used to screen nodes. Not used at this time, |
| * this is here only to fullfill the DOM NodeIterator |
| * interface. |
| * |
| * @return Always null. |
| * @see org.w3c.dom.traversal.NodeIterator |
| */ |
| public DTMFilter getFilter() |
| { |
| return null; |
| } |
| |
| /** |
| * The root node of the Iterator, as specified when it was created. |
| * |
| * @return The "root" of this iterator, which, in XPath terms, |
| * is the node context for this iterator. |
| */ |
| public int getRoot() |
| { |
| return m_context; |
| } |
| |
| /** |
| * The value of this flag determines whether the children of entity |
| * reference nodes are visible to the iterator. If false, they will be |
| * skipped over. |
| * <br> To produce a view of the document that has entity references |
| * expanded and does not expose the entity reference node itself, use the |
| * whatToShow flags to hide the entity reference node and set |
| * expandEntityReferences to true when creating the iterator. To produce |
| * a view of the document that has entity reference nodes but no entity |
| * expansion, use the whatToShow flags to show the entity reference node |
| * and set expandEntityReferences to false. |
| * |
| * @return Always true, since entity reference nodes are not |
| * visible in the XPath model. |
| */ |
| public boolean getExpandEntityReferences() |
| { |
| return true; |
| } |
| |
| /** Control over whether it is OK for detach to reset the iterator. */ |
| protected boolean m_allowDetach = true; |
| |
| /** |
| * Specify if it's OK for detach to release the iterator for reuse. |
| * |
| * @param allowRelease true if it is OK for detach to release this iterator |
| * for pooling. |
| */ |
| public void allowDetachToRelease(boolean allowRelease) |
| { |
| m_allowDetach = allowRelease; |
| } |
| |
| /** |
| * Detaches the iterator from the set which it iterated over, releasing |
| * any computational resources and placing the iterator in the INVALID |
| * state. After<code>detach</code> has been invoked, calls to |
| * <code>nextNode</code> or<code>previousNode</code> will raise the |
| * exception INVALID_STATE_ERR. |
| */ |
| public void detach() |
| { |
| if(m_allowDetach) |
| { |
| // sb: allow reusing of cached nodes when possible? |
| // m_cachedNodes = null; |
| m_execContext = null; |
| // m_prefixResolver = null; sb: Why would this ever want to be null? |
| m_cdtm = null; |
| m_length = -1; |
| m_pos = 0; |
| m_lastFetched = DTM.NULL; |
| m_context = DTM.NULL; |
| m_currentContextNode = DTM.NULL; |
| |
| m_clones.freeInstance(this); |
| } |
| } |
| |
| /** |
| * Reset the iterator. |
| */ |
| public void reset() |
| { |
| assertion(false, "This iterator can not reset!"); |
| } |
| |
| /** |
| * Get a cloned Iterator that is reset to the beginning |
| * of the query. |
| * |
| * @return A cloned NodeIterator set of the start of the query. |
| * |
| * @throws CloneNotSupportedException |
| */ |
| public DTMIterator cloneWithReset() throws CloneNotSupportedException |
| { |
| LocPathIterator clone; |
| // clone = (LocPathIterator) clone(); |
| clone = (LocPathIterator)m_clones.getInstanceOrThrow(); |
| clone.m_execContext = m_execContext; |
| clone.m_cdtm = m_cdtm; |
| |
| clone.m_context = m_context; |
| clone.m_currentContextNode = m_currentContextNode; |
| clone.m_stackFrame = m_stackFrame; |
| |
| // clone.reset(); |
| |
| return clone; |
| } |
| |
| // /** |
| // * Get a cloned LocPathIterator that holds the same |
| // * position as this iterator. |
| // * |
| // * @return A clone of this iterator that holds the same node position. |
| // * |
| // * @throws CloneNotSupportedException |
| // */ |
| // public Object clone() throws CloneNotSupportedException |
| // { |
| // |
| // LocPathIterator clone = (LocPathIterator) super.clone(); |
| // |
| // return clone; |
| // } |
| |
| /** |
| * Returns the next node in the set and advances the position of the |
| * iterator in the set. After a NodeIterator is created, the first call |
| * to nextNode() returns the first node in the set. |
| * @return The next <code>Node</code> in the set being iterated over, or |
| * <code>null</code> if there are no more members in that set. |
| */ |
| public abstract int nextNode(); |
| |
| /** |
| * Bottleneck the return of a next node, to make returns |
| * easier from nextNode(). |
| * |
| * @param nextNode The next node found, may be null. |
| * |
| * @return The same node that was passed as an argument. |
| */ |
| protected int returnNextNode(int nextNode) |
| { |
| |
| if (DTM.NULL != nextNode) |
| { |
| m_pos++; |
| } |
| |
| m_lastFetched = nextNode; |
| |
| if (DTM.NULL == nextNode) |
| m_foundLast = true; |
| |
| return nextNode; |
| } |
| |
| /** |
| * Return the last fetched node. Needed to support the UnionPathIterator. |
| * |
| * @return The last fetched node, or null if the last fetch was null. |
| */ |
| public int getCurrentNode() |
| { |
| return m_lastFetched; |
| } |
| |
| /** |
| * If an index is requested, NodeSetDTM will call this method |
| * to run the iterator to the index. By default this sets |
| * m_next to the index. If the index argument is -1, this |
| * signals that the iterator should be run to the end. |
| * |
| * @param index The index to run to, or -1 if the iterator |
| * should run to the end. |
| */ |
| public void runTo(int index) |
| { |
| |
| if (m_foundLast || ((index >= 0) && (index <= getCurrentPos()))) |
| return; |
| |
| int n; |
| |
| if (-1 == index) |
| { |
| while (DTM.NULL != (n = nextNode())); |
| } |
| else |
| { |
| while (DTM.NULL != (n = nextNode())) |
| { |
| if (getCurrentPos() >= index) |
| break; |
| } |
| } |
| } |
| |
| /** |
| * Tells if we've found the last node yet. |
| * |
| * @return true if the last nextNode returned null. |
| */ |
| public final boolean getFoundLast() |
| { |
| return m_foundLast; |
| } |
| |
| /** |
| * The XPath execution context we are operating on. |
| * |
| * @return XPath execution context this iterator is operating on, |
| * or null if setRoot has not been called. |
| */ |
| public final XPathContext getXPathContext() |
| { |
| return m_execContext; |
| } |
| |
| /** |
| * The node context for the iterator. |
| * |
| * @return The node context, same as getRoot(). |
| */ |
| public final int getContext() |
| { |
| return m_context; |
| } |
| |
| /** |
| * The node context from where the expression is being |
| * executed from (i.e. for current() support). |
| * |
| * @return The top-level node context of the entire expression. |
| */ |
| public final int getCurrentContextNode() |
| { |
| return m_currentContextNode; |
| } |
| |
| /** |
| * Set the current context node for this iterator. |
| * |
| * @param n Must be a non-null reference to the node context. |
| */ |
| public final void setCurrentContextNode(int n) |
| { |
| m_currentContextNode = n; |
| } |
| |
| // /** |
| // * Set the current context node for this iterator. |
| // * |
| // * @param n Must be a non-null reference to the node context. |
| // */ |
| // public void setRoot(int n) |
| // { |
| // m_context = n; |
| // m_cdtm = m_execContext.getDTM(n); |
| // } |
| |
| /** |
| * Return the saved reference to the prefix resolver that |
| * was in effect when this iterator was created. |
| * |
| * @return The prefix resolver or this iterator, which may be null. |
| */ |
| public final PrefixResolver getPrefixResolver() |
| { |
| if(null == m_prefixResolver) |
| { |
| m_prefixResolver = (PrefixResolver)getExpressionOwner(); |
| } |
| |
| return m_prefixResolver; |
| } |
| |
| // /** |
| // * Get the analysis pattern built by the WalkerFactory. |
| // * |
| // * @return The analysis pattern built by the WalkerFactory. |
| // */ |
| // int getAnalysis() |
| // { |
| // return m_analysis; |
| // } |
| |
| // /** |
| // * Set the analysis pattern built by the WalkerFactory. |
| // * |
| // * @param a The analysis pattern built by the WalkerFactory. |
| // */ |
| // void setAnalysis(int a) |
| // { |
| // m_analysis = a; |
| // } |
| |
| /** |
| * @see XPathVisitable#callVisitors(ExpressionOwner, XPathVisitor) |
| */ |
| public void callVisitors(ExpressionOwner owner, XPathVisitor visitor) |
| { |
| if(visitor.visitLocationPath(owner, this)) |
| { |
| visitor.visitStep(owner, this); |
| callPredicateVisitors(visitor); |
| } |
| } |
| |
| |
| //============= State Data ============= |
| |
| /** |
| * The pool for cloned iterators. Iterators need to be cloned |
| * because the hold running state, and thus the original iterator |
| * expression from the stylesheet pool can not be used. |
| */ |
| transient protected IteratorPool m_clones = new IteratorPool(this); |
| |
| /** |
| * The dtm of the context node. Careful about using this... it may not |
| * be the dtm of the current node. |
| */ |
| transient protected DTM m_cdtm; |
| |
| /** |
| * The stack frame index for this iterator. |
| */ |
| transient int m_stackFrame = -1; |
| |
| /** |
| * Value determined at compile time, indicates that this is an |
| * iterator at the top level of the expression, rather than inside |
| * a predicate. |
| * @serial |
| */ |
| private boolean m_isTopLevel = false; |
| |
| /** The last node that was fetched, usually by nextNode. */ |
| transient public int m_lastFetched = DTM.NULL; |
| |
| /** |
| * The context node for this iterator, which doesn't change through |
| * the course of the iteration. |
| */ |
| transient protected int m_context = DTM.NULL; |
| |
| /** |
| * The node context from where the expression is being |
| * executed from (i.e. for current() support). Different |
| * from m_context in that this is the context for the entire |
| * expression, rather than the context for the subexpression. |
| */ |
| transient protected int m_currentContextNode = DTM.NULL; |
| |
| /** |
| * The current position of the context node. |
| */ |
| transient protected int m_pos = 0; |
| |
| transient protected int m_length = -1; |
| |
| /** |
| * Fast access to the current prefix resolver. It isn't really |
| * clear that this is needed. |
| * @serial |
| */ |
| private PrefixResolver m_prefixResolver; |
| |
| /** |
| * The XPathContext reference, needed for execution of many |
| * operations. |
| */ |
| transient protected XPathContext m_execContext; |
| |
| /** |
| * Returns true if all the nodes in the iteration well be returned in document |
| * order. |
| * |
| * @return true as a default. |
| */ |
| public boolean isDocOrdered() |
| { |
| return true; |
| } |
| |
| /** |
| * Returns the axis being iterated, if it is known. |
| * |
| * @return Axis.CHILD, etc., or -1 if the axis is not known or is of multiple |
| * types. |
| */ |
| public int getAxis() |
| { |
| return -1; |
| } |
| |
| |
| // /** |
| // * The analysis pattern built by the WalkerFactory. |
| // * TODO: Move to LocPathIterator. |
| // * @see org.apache.xpath.axes.WalkerFactory |
| // * @serial |
| // */ |
| // protected int m_analysis = 0x00000000; |
| /** |
| * @see PredicatedNodeTest#getLastPos(XPathContext) |
| */ |
| public int getLastPos(XPathContext xctxt) |
| { |
| return getLength(); |
| } |
| |
| } |