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