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