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: WalkingIterator.java,v 1.12 2005/01/23 01:02:11 mcnamara Exp $
018: */
019: package org.apache.xpath.axes;
020:
021: import org.apache.xml.dtm.DTM;
022: import org.apache.xml.utils.PrefixResolver;
023: import org.apache.xpath.Expression;
024: import org.apache.xpath.ExpressionOwner;
025: import org.apache.xpath.VariableStack;
026: import org.apache.xpath.XPathVisitor;
027: import org.apache.xpath.compiler.Compiler;
028:
029: /**
030: * Location path iterator that uses Walkers.
031: */
032:
033: public class WalkingIterator extends LocPathIterator implements
034: ExpressionOwner {
035: static final long serialVersionUID = 9110225941815665906L;
036:
037: /**
038: * Create a WalkingIterator iterator, including creation
039: * of step walkers from the opcode list, and call back
040: * into the Compiler to create predicate expressions.
041: *
042: * @param compiler The Compiler which is creating
043: * this expression.
044: * @param opPos The position of this iterator in the
045: * opcode list from the compiler.
046: * @param shouldLoadWalkers True if walkers should be
047: * loaded, or false if this is a derived iterator and
048: * it doesn't wish to load child walkers.
049: *
050: * @throws javax.xml.transform.TransformerException
051: */
052: WalkingIterator(Compiler compiler, int opPos, int analysis,
053: boolean shouldLoadWalkers)
054: throws javax.xml.transform.TransformerException {
055: super (compiler, opPos, analysis, shouldLoadWalkers);
056:
057: int firstStepPos = compiler.getFirstChildPos(opPos);
058:
059: if (shouldLoadWalkers) {
060: m_firstWalker = WalkerFactory.loadWalkers(this , compiler,
061: firstStepPos, 0);
062: m_lastUsedWalker = m_firstWalker;
063: }
064: }
065:
066: /**
067: * Create a WalkingIterator object.
068: *
069: * @param nscontext The namespace context for this iterator,
070: * should be OK if null.
071: */
072: public WalkingIterator(PrefixResolver nscontext) {
073:
074: super (nscontext);
075: }
076:
077: /**
078: * Get the analysis bits for this walker, as defined in the WalkerFactory.
079: * @return One of WalkerFactory#BIT_DESCENDANT, etc.
080: */
081: public int getAnalysisBits() {
082: int bits = 0;
083: if (null != m_firstWalker) {
084: AxesWalker walker = m_firstWalker;
085:
086: while (null != walker) {
087: int bit = walker.getAnalysisBits();
088: bits |= bit;
089: walker = walker.getNextWalker();
090: }
091: }
092: return bits;
093: }
094:
095: /**
096: * Get a cloned WalkingIterator that holds the same
097: * position as this iterator.
098: *
099: * @return A clone of this iterator that holds the same node position.
100: *
101: * @throws CloneNotSupportedException
102: */
103: public Object clone() throws CloneNotSupportedException {
104:
105: WalkingIterator clone = (WalkingIterator) super .clone();
106:
107: // clone.m_varStackPos = this.m_varStackPos;
108: // clone.m_varStackContext = this.m_varStackContext;
109: if (null != m_firstWalker) {
110: clone.m_firstWalker = m_firstWalker.cloneDeep(clone, null);
111: }
112:
113: return clone;
114: }
115:
116: /**
117: * Reset the iterator.
118: */
119: public void reset() {
120:
121: super .reset();
122:
123: if (null != m_firstWalker) {
124: m_lastUsedWalker = m_firstWalker;
125:
126: m_firstWalker.setRoot(m_context);
127: }
128:
129: }
130:
131: /**
132: * Initialize the context values for this expression
133: * after it is cloned.
134: *
135: * @param context The XPath runtime context for this
136: * transformation.
137: */
138: public void setRoot(int context, Object environment) {
139:
140: super .setRoot(context, environment);
141:
142: if (null != m_firstWalker) {
143: m_firstWalker.setRoot(context);
144: m_lastUsedWalker = m_firstWalker;
145: }
146: }
147:
148: /**
149: * Returns the next node in the set and advances the position of the
150: * iterator in the set. After a NodeIterator is created, the first call
151: * to nextNode() returns the first node in the set.
152: * @return The next <code>Node</code> in the set being iterated over, or
153: * <code>null</code> if there are no more members in that set.
154: */
155: public int nextNode() {
156: if (m_foundLast)
157: return DTM.NULL;
158:
159: // If the variable stack position is not -1, we'll have to
160: // set our position in the variable stack, so our variable access
161: // will be correct. Iterators that are at the top level of the
162: // expression need to reset the variable stack, while iterators
163: // in predicates do not need to, and should not, since their execution
164: // may be much later than top-level iterators.
165: // m_varStackPos is set in setRoot, which is called
166: // from the execute method.
167: if (-1 == m_stackFrame) {
168: return returnNextNode(m_firstWalker.nextNode());
169: } else {
170: VariableStack vars = m_execContext.getVarStack();
171:
172: // These three statements need to be combined into one operation.
173: int savedStart = vars.getStackFrame();
174:
175: vars.setStackFrame(m_stackFrame);
176:
177: int n = returnNextNode(m_firstWalker.nextNode());
178:
179: // These two statements need to be combined into one operation.
180: vars.setStackFrame(savedStart);
181:
182: return n;
183: }
184: }
185:
186: /**
187: * Get the head of the walker list.
188: *
189: * @return The head of the walker list, or null
190: * if this iterator does not implement walkers.
191: * @xsl.usage advanced
192: */
193: public final AxesWalker getFirstWalker() {
194: return m_firstWalker;
195: }
196:
197: /**
198: * Set the head of the walker list.
199: *
200: * @param walker Should be a valid AxesWalker.
201: * @xsl.usage advanced
202: */
203: public final void setFirstWalker(AxesWalker walker) {
204: m_firstWalker = walker;
205: }
206:
207: /**
208: * Set the last used walker.
209: *
210: * @param walker The last used walker, or null.
211: * @xsl.usage advanced
212: */
213: public final void setLastUsedWalker(AxesWalker walker) {
214: m_lastUsedWalker = walker;
215: }
216:
217: /**
218: * Get the last used walker.
219: *
220: * @return The last used walker, or null.
221: * @xsl.usage advanced
222: */
223: public final AxesWalker getLastUsedWalker() {
224: return m_lastUsedWalker;
225: }
226:
227: /**
228: * Detaches the iterator from the set which it iterated over, releasing
229: * any computational resources and placing the iterator in the INVALID
230: * state. After<code>detach</code> has been invoked, calls to
231: * <code>nextNode</code> or<code>previousNode</code> will raise the
232: * exception INVALID_STATE_ERR.
233: */
234: public void detach() {
235: if (m_allowDetach) {
236: AxesWalker walker = m_firstWalker;
237: while (null != walker) {
238: walker.detach();
239: walker = walker.getNextWalker();
240: }
241:
242: m_lastUsedWalker = null;
243:
244: // Always call the superclass detach last!
245: super .detach();
246: }
247: }
248:
249: /**
250: * This function is used to fixup variables from QNames to stack frame
251: * indexes at stylesheet build time.
252: * @param vars List of QNames that correspond to variables. This list
253: * should be searched backwards for the first qualified name that
254: * corresponds to the variable reference qname. The position of the
255: * QName in the vector from the start of the vector will be its position
256: * in the stack frame (but variables above the globalsTop value will need
257: * to be offset to the current stack frame).
258: */
259: public void fixupVariables(java.util.Vector vars, int globalsSize) {
260: m_predicateIndex = -1;
261:
262: AxesWalker walker = m_firstWalker;
263:
264: while (null != walker) {
265: walker.fixupVariables(vars, globalsSize);
266: walker = walker.getNextWalker();
267: }
268: }
269:
270: /**
271: * @see org.apache.xpath.XPathVisitable#callVisitors(ExpressionOwner, XPathVisitor)
272: */
273: public void callVisitors(ExpressionOwner owner, XPathVisitor visitor) {
274: if (visitor.visitLocationPath(owner, this )) {
275: if (null != m_firstWalker) {
276: m_firstWalker.callVisitors(this , visitor);
277: }
278: }
279: }
280:
281: /** The last used step walker in the walker list.
282: * @serial */
283: protected AxesWalker m_lastUsedWalker;
284:
285: /** The head of the step walker list.
286: * @serial */
287: protected AxesWalker m_firstWalker;
288:
289: /**
290: * @see ExpressionOwner#getExpression()
291: */
292: public Expression getExpression() {
293: return m_firstWalker;
294: }
295:
296: /**
297: * @see ExpressionOwner#setExpression(Expression)
298: */
299: public void setExpression(Expression exp) {
300: exp.exprSetParent(this );
301: m_firstWalker = (AxesWalker) exp;
302: }
303:
304: /**
305: * @see Expression#deepEquals(Expression)
306: */
307: public boolean deepEquals(Expression expr) {
308: if (!super .deepEquals(expr))
309: return false;
310:
311: AxesWalker walker1 = m_firstWalker;
312: AxesWalker walker2 = ((WalkingIterator) expr).m_firstWalker;
313: while ((null != walker1) && (null != walker2)) {
314: if (!walker1.deepEquals(walker2))
315: return false;
316: walker1 = walker1.getNextWalker();
317: walker2 = walker2.getNextWalker();
318: }
319:
320: if ((null != walker1) || (null != walker2))
321: return false;
322:
323: return true;
324: }
325:
326: }
|