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: FilterExprIteratorSimple.java,v 1.7 2005/01/23 01:02:10 mcnamara Exp $
018: */
019: package org.apache.xpath.axes;
020:
021: import org.apache.xml.dtm.Axis;
022: import org.apache.xml.dtm.DTM;
023: import org.apache.xml.utils.PrefixResolver;
024: import org.apache.xpath.Expression;
025: import org.apache.xpath.ExpressionOwner;
026: import org.apache.xpath.VariableStack;
027: import org.apache.xpath.XPathContext;
028: import org.apache.xpath.XPathVisitor;
029: import org.apache.xpath.objects.XNodeSet;
030:
031: /**
032: * Class to use for one-step iteration that doesn't have a predicate, and
033: * doesn't need to set the context.
034: */
035: public class FilterExprIteratorSimple extends LocPathIterator {
036: static final long serialVersionUID = -6978977187025375579L;
037: /** The contained expression. Should be non-null.
038: * @serial */
039: private Expression m_expr;
040:
041: /** The result of executing m_expr. Needs to be deep cloned on clone op. */
042: transient private XNodeSet m_exprObj;
043:
044: private boolean m_mustHardReset = false;
045: private boolean m_canDetachNodeset = true;
046:
047: /**
048: * Create a FilterExprIteratorSimple object.
049: *
050: */
051: public FilterExprIteratorSimple() {
052: super (null);
053: }
054:
055: /**
056: * Create a FilterExprIteratorSimple object.
057: *
058: */
059: public FilterExprIteratorSimple(Expression expr) {
060: super (null);
061: m_expr = expr;
062: }
063:
064: /**
065: * Initialize the context values for this expression
066: * after it is cloned.
067: *
068: * @param context The XPath runtime context for this
069: * transformation.
070: */
071: public void setRoot(int context, Object environment) {
072: super .setRoot(context, environment);
073: m_exprObj = executeFilterExpr(context, m_execContext,
074: getPrefixResolver(), getIsTopLevel(), m_stackFrame,
075: m_expr);
076: }
077:
078: /**
079: * Execute the expression. Meant for reuse by other FilterExpr iterators
080: * that are not derived from this object.
081: */
082: public static XNodeSet executeFilterExpr(int context,
083: XPathContext xctxt, PrefixResolver prefixResolver,
084: boolean isTopLevel, int stackFrame, Expression expr)
085: throws org.apache.xml.utils.WrappedRuntimeException {
086: PrefixResolver savedResolver = xctxt.getNamespaceContext();
087: XNodeSet result = null;
088:
089: try {
090: xctxt.pushCurrentNode(context);
091: xctxt.setNamespaceContext(prefixResolver);
092:
093: // The setRoot operation can take place with a reset operation,
094: // and so we may not be in the context of LocPathIterator#nextNode,
095: // so we have to set up the variable context, execute the expression,
096: // and then restore the variable context.
097:
098: if (isTopLevel) {
099: // System.out.println("calling m_expr.execute(getXPathContext())");
100: VariableStack vars = xctxt.getVarStack();
101:
102: // These three statements need to be combined into one operation.
103: int savedStart = vars.getStackFrame();
104: vars.setStackFrame(stackFrame);
105:
106: result = (org.apache.xpath.objects.XNodeSet) expr
107: .execute(xctxt);
108: result.setShouldCacheNodes(true);
109:
110: // These two statements need to be combined into one operation.
111: vars.setStackFrame(savedStart);
112: } else
113: result = (org.apache.xpath.objects.XNodeSet) expr
114: .execute(xctxt);
115:
116: } catch (javax.xml.transform.TransformerException se) {
117:
118: // TODO: Fix...
119: throw new org.apache.xml.utils.WrappedRuntimeException(se);
120: } finally {
121: xctxt.popCurrentNode();
122: xctxt.setNamespaceContext(savedResolver);
123: }
124: return result;
125: }
126:
127: /**
128: * Returns the next node in the set and advances the position of the
129: * iterator in the set. After a NodeIterator is created, the first call
130: * to nextNode() returns the first node in the set.
131: *
132: * @return The next <code>Node</code> in the set being iterated over, or
133: * <code>null</code> if there are no more members in that set.
134: */
135: public int nextNode() {
136: if (m_foundLast)
137: return DTM.NULL;
138:
139: int next;
140:
141: if (null != m_exprObj) {
142: m_lastFetched = next = m_exprObj.nextNode();
143: } else
144: m_lastFetched = next = DTM.NULL;
145:
146: // m_lastFetched = next;
147: if (DTM.NULL != next) {
148: m_pos++;
149: return next;
150: } else {
151: m_foundLast = true;
152:
153: return DTM.NULL;
154: }
155: }
156:
157: /**
158: * Detaches the walker from the set which it iterated over, releasing
159: * any computational resources and placing the iterator in the INVALID
160: * state.
161: */
162: public void detach() {
163: if (m_allowDetach) {
164: super .detach();
165: m_exprObj.detach();
166: m_exprObj = null;
167: }
168: }
169:
170: /**
171: * This function is used to fixup variables from QNames to stack frame
172: * indexes at stylesheet build time.
173: * @param vars List of QNames that correspond to variables. This list
174: * should be searched backwards for the first qualified name that
175: * corresponds to the variable reference qname. The position of the
176: * QName in the vector from the start of the vector will be its position
177: * in the stack frame (but variables above the globalsTop value will need
178: * to be offset to the current stack frame).
179: */
180: public void fixupVariables(java.util.Vector vars, int globalsSize) {
181: super .fixupVariables(vars, globalsSize);
182: m_expr.fixupVariables(vars, globalsSize);
183: }
184:
185: /**
186: * Get the inner contained expression of this filter.
187: */
188: public Expression getInnerExpression() {
189: return m_expr;
190: }
191:
192: /**
193: * Set the inner contained expression of this filter.
194: */
195: public void setInnerExpression(Expression expr) {
196: expr.exprSetParent(this );
197: m_expr = expr;
198: }
199:
200: /**
201: * Get the analysis bits for this walker, as defined in the WalkerFactory.
202: * @return One of WalkerFactory#BIT_DESCENDANT, etc.
203: */
204: public int getAnalysisBits() {
205: if (null != m_expr && m_expr instanceof PathComponent) {
206: return ((PathComponent) m_expr).getAnalysisBits();
207: }
208: return WalkerFactory.BIT_FILTER;
209: }
210:
211: /**
212: * Returns true if all the nodes in the iteration well be returned in document
213: * order.
214: * Warning: This can only be called after setRoot has been called!
215: *
216: * @return true as a default.
217: */
218: public boolean isDocOrdered() {
219: return m_exprObj.isDocOrdered();
220: }
221:
222: class filterExprOwner implements ExpressionOwner {
223: /**
224: * @see ExpressionOwner#getExpression()
225: */
226: public Expression getExpression() {
227: return m_expr;
228: }
229:
230: /**
231: * @see ExpressionOwner#setExpression(Expression)
232: */
233: public void setExpression(Expression exp) {
234: exp.exprSetParent(FilterExprIteratorSimple.this );
235: m_expr = exp;
236: }
237:
238: }
239:
240: /**
241: * This will traverse the heararchy, calling the visitor for
242: * each member. If the called visitor method returns
243: * false, the subtree should not be called.
244: *
245: * @param visitor The visitor whose appropriate method will be called.
246: */
247: public void callPredicateVisitors(XPathVisitor visitor) {
248: m_expr.callVisitors(new filterExprOwner(), visitor);
249:
250: super .callPredicateVisitors(visitor);
251: }
252:
253: /**
254: * @see Expression#deepEquals(Expression)
255: */
256: public boolean deepEquals(Expression expr) {
257: if (!super .deepEquals(expr))
258: return false;
259:
260: FilterExprIteratorSimple fet = (FilterExprIteratorSimple) expr;
261: if (!m_expr.deepEquals(fet.m_expr))
262: return false;
263:
264: return true;
265: }
266:
267: /**
268: * Returns the axis being iterated, if it is known.
269: *
270: * @return Axis.CHILD, etc., or -1 if the axis is not known or is of multiple
271: * types.
272: */
273: public int getAxis() {
274: if (null != m_exprObj)
275: return m_exprObj.getAxis();
276: else
277: return Axis.FILTEREDLIST;
278: }
279:
280: }
|