001 /*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements. See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership. The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the "License");
007 * you may not use this file except in compliance with the License.
008 * You may obtain a copy of the License at
009 *
010 * http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018 /*
019 * $Id: LocPathIterator.java 468655 2006-10-28 07:12:06Z minchau $
020 */
021 package org.apache.xpath.axes;
022
023 import org.apache.xalan.res.XSLMessages;
024 import org.apache.xml.dtm.DTM;
025 import org.apache.xml.dtm.DTMFilter;
026 import org.apache.xml.dtm.DTMIterator;
027 import org.apache.xml.dtm.DTMManager;
028 import org.apache.xml.utils.PrefixResolver;
029 import org.apache.xpath.ExpressionOwner;
030 import org.apache.xpath.XPathContext;
031 import org.apache.xpath.XPathVisitor;
032 import org.apache.xpath.compiler.Compiler;
033 import org.apache.xpath.objects.XNodeSet;
034 import org.apache.xpath.objects.XObject;
035 import org.apache.xpath.res.XPATHErrorResources;
036
037 /**
038 * This class extends NodeSetDTM, which implements NodeIterator,
039 * and fetches nodes one at a time in document order based on a XPath
040 * <a href="http://www.w3.org/TR/xpath#NT-LocationPath>LocationPath</a>.
041 *
042 * <p>If setShouldCacheNodes(true) is called,
043 * as each node is iterated via nextNode(), the node is also stored
044 * in the NodeVector, so that previousNode() can easily be done, except in
045 * the case where the LocPathIterator is "owned" by a UnionPathIterator,
046 * in which case the UnionPathIterator will cache the nodes.</p>
047 * @xsl.usage advanced
048 */
049 public abstract class LocPathIterator extends PredicatedNodeTest
050 implements Cloneable, DTMIterator, java.io.Serializable, PathComponent
051 {
052 static final long serialVersionUID = -4602476357268405754L;
053
054 /**
055 * Create a LocPathIterator object.
056 *
057 */
058 protected LocPathIterator()
059 {
060 }
061
062
063 /**
064 * Create a LocPathIterator object.
065 *
066 * @param nscontext The namespace context for this iterator,
067 * should be OK if null.
068 */
069 protected LocPathIterator(PrefixResolver nscontext)
070 {
071
072 setLocPathIterator(this);
073 m_prefixResolver = nscontext;
074 }
075
076 /**
077 * Create a LocPathIterator object, including creation
078 * of step walkers from the opcode list, and call back
079 * into the Compiler to create predicate expressions.
080 *
081 * @param compiler The Compiler which is creating
082 * this expression.
083 * @param opPos The position of this iterator in the
084 * opcode list from the compiler.
085 *
086 * @throws javax.xml.transform.TransformerException
087 */
088 protected LocPathIterator(Compiler compiler, int opPos, int analysis)
089 throws javax.xml.transform.TransformerException
090 {
091 this(compiler, opPos, analysis, true);
092 }
093
094 /**
095 * Create a LocPathIterator object, including creation
096 * of step walkers from the opcode list, and call back
097 * into the Compiler to create predicate expressions.
098 *
099 * @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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
1028 public int getLastPos(XPathContext xctxt)
1029 {
1030 return getLength();
1031 }
1032
1033 }