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: FilterExprWalker.java,v 1.26 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.dtm.DTMIterator;
024: import org.apache.xpath.Expression;
025: import org.apache.xpath.ExpressionOwner;
026: import org.apache.xpath.XPathContext;
027: import org.apache.xpath.XPathVisitor;
028: import org.apache.xpath.compiler.Compiler;
029: import org.apache.xpath.compiler.OpCodes;
030: import org.apache.xpath.objects.XNodeSet;
031:
032: /**
033: * Walker for the OP_VARIABLE, or OP_EXTFUNCTION, or OP_FUNCTION, or OP_GROUP,
034: * op codes.
035: * @see <a href="http://www.w3.org/TR/xpath#NT-FilterExpr">XPath FilterExpr descriptions</a>
036: */
037: public class FilterExprWalker extends AxesWalker {
038: static final long serialVersionUID = 5457182471424488375L;
039:
040: /**
041: * Construct a FilterExprWalker using a LocPathIterator.
042: *
043: * @param locPathIterator non-null reference to the parent iterator.
044: */
045: public FilterExprWalker(WalkingIterator locPathIterator) {
046: super (locPathIterator, Axis.FILTEREDLIST);
047: }
048:
049: /**
050: * Init a FilterExprWalker.
051: *
052: * @param compiler non-null reference to the Compiler that is constructing.
053: * @param opPos positive opcode position for this step.
054: * @param stepType The type of step.
055: *
056: * @throws javax.xml.transform.TransformerException
057: */
058: public void init(Compiler compiler, int opPos, int stepType)
059: throws javax.xml.transform.TransformerException {
060:
061: super .init(compiler, opPos, stepType);
062:
063: // Smooth over an anomily in the opcode map...
064: switch (stepType) {
065: case OpCodes.OP_FUNCTION:
066: case OpCodes.OP_EXTFUNCTION:
067: m_mustHardReset = true;
068: case OpCodes.OP_GROUP:
069: case OpCodes.OP_VARIABLE:
070: m_expr = compiler.compile(opPos);
071: m_expr.exprSetParent(this );
072: //if((OpCodes.OP_FUNCTION == stepType) && (m_expr instanceof org.apache.xalan.templates.FuncKey))
073: if (m_expr instanceof org.apache.xpath.operations.Variable) {
074: // hack/temp workaround
075: m_canDetachNodeset = false;
076: }
077: break;
078: default:
079: m_expr = compiler.compile(opPos + 2);
080: m_expr.exprSetParent(this );
081: }
082: // if(m_expr instanceof WalkingIterator)
083: // {
084: // WalkingIterator wi = (WalkingIterator)m_expr;
085: // if(wi.getFirstWalker() instanceof FilterExprWalker)
086: // {
087: // FilterExprWalker fw = (FilterExprWalker)wi.getFirstWalker();
088: // if(null == fw.getNextWalker())
089: // {
090: // m_expr = fw.m_expr;
091: // m_expr.exprSetParent(this);
092: // }
093: // }
094: //
095: // }
096: }
097:
098: /**
099: * Detaches the walker from the set which it iterated over, releasing
100: * any computational resources and placing the iterator in the INVALID
101: * state.
102: */
103: public void detach() {
104: super .detach();
105: if (m_canDetachNodeset) {
106: m_exprObj.detach();
107: }
108: m_exprObj = null;
109: }
110:
111: /**
112: * Set the root node of the TreeWalker.
113: *
114: * @param root non-null reference to the root, or starting point of
115: * the query.
116: */
117: public void setRoot(int root) {
118:
119: super .setRoot(root);
120:
121: m_exprObj = FilterExprIteratorSimple.executeFilterExpr(root,
122: m_lpi.getXPathContext(), m_lpi.getPrefixResolver(),
123: m_lpi.getIsTopLevel(), m_lpi.m_stackFrame, m_expr);
124:
125: }
126:
127: /**
128: * Get a cloned FilterExprWalker.
129: *
130: * @return A new FilterExprWalker that can be used without mutating this one.
131: *
132: * @throws CloneNotSupportedException
133: */
134: public Object clone() throws CloneNotSupportedException {
135:
136: FilterExprWalker clone = (FilterExprWalker) super .clone();
137:
138: // clone.m_expr = (Expression)((Expression)m_expr).clone();
139: if (null != m_exprObj)
140: clone.m_exprObj = (XNodeSet) m_exprObj.clone();
141:
142: return clone;
143: }
144:
145: /**
146: * This method needs to override AxesWalker.acceptNode because FilterExprWalkers
147: * don't need to, and shouldn't, do a node test.
148: * @param n The node to check to see if it passes the filter or not.
149: * @return a constant to determine whether the node is accepted,
150: * rejected, or skipped, as defined above .
151: */
152: public short acceptNode(int n) {
153:
154: try {
155: if (getPredicateCount() > 0) {
156: countProximityPosition(0);
157:
158: if (!executePredicates(n, m_lpi.getXPathContext()))
159: return DTMIterator.FILTER_SKIP;
160: }
161:
162: return DTMIterator.FILTER_ACCEPT;
163: } catch (javax.xml.transform.TransformerException se) {
164: throw new RuntimeException(se.getMessage());
165: }
166: }
167:
168: /**
169: * Moves the <code>TreeWalker</code> to the next visible node in document
170: * order relative to the current node, and returns the new node. If the
171: * current node has no next node, or if the search for nextNode attempts
172: * to step upward from the TreeWalker's root node, returns
173: * <code>null</code> , and retains the current node.
174: * @return The new node, or <code>null</code> if the current node has no
175: * next node in the TreeWalker's logical view.
176: */
177: public int getNextNode() {
178:
179: if (null != m_exprObj) {
180: int next = m_exprObj.nextNode();
181: return next;
182: } else
183: return DTM.NULL;
184: }
185:
186: /**
187: * Get the index of the last node that can be itterated to.
188: *
189: *
190: * @param xctxt XPath runtime context.
191: *
192: * @return the index of the last node that can be itterated to.
193: */
194: public int getLastPos(XPathContext xctxt) {
195: return m_exprObj.getLength();
196: }
197:
198: /** The contained expression. Should be non-null.
199: * @serial */
200: private Expression m_expr;
201:
202: /** The result of executing m_expr. Needs to be deep cloned on clone op. */
203: transient private XNodeSet m_exprObj;
204:
205: private boolean m_mustHardReset = false;
206: private boolean m_canDetachNodeset = true;
207:
208: /**
209: * This function is used to fixup variables from QNames to stack frame
210: * indexes at stylesheet build time.
211: * @param vars List of QNames that correspond to variables. This list
212: * should be searched backwards for the first qualified name that
213: * corresponds to the variable reference qname. The position of the
214: * QName in the vector from the start of the vector will be its position
215: * in the stack frame (but variables above the globalsTop value will need
216: * to be offset to the current stack frame).
217: */
218: public void fixupVariables(java.util.Vector vars, int globalsSize) {
219: super .fixupVariables(vars, globalsSize);
220: m_expr.fixupVariables(vars, globalsSize);
221: }
222:
223: /**
224: * Get the inner contained expression of this filter.
225: */
226: public Expression getInnerExpression() {
227: return m_expr;
228: }
229:
230: /**
231: * Set the inner contained expression of this filter.
232: */
233: public void setInnerExpression(Expression expr) {
234: expr.exprSetParent(this );
235: m_expr = expr;
236: }
237:
238: /**
239: * Get the analysis bits for this walker, as defined in the WalkerFactory.
240: * @return One of WalkerFactory#BIT_DESCENDANT, etc.
241: */
242: public int getAnalysisBits() {
243: if (null != m_expr && m_expr instanceof PathComponent) {
244: return ((PathComponent) m_expr).getAnalysisBits();
245: }
246: return WalkerFactory.BIT_FILTER;
247: }
248:
249: /**
250: * Returns true if all the nodes in the iteration well be returned in document
251: * order.
252: * Warning: This can only be called after setRoot has been called!
253: *
254: * @return true as a default.
255: */
256: public boolean isDocOrdered() {
257: return m_exprObj.isDocOrdered();
258: }
259:
260: /**
261: * Returns the axis being iterated, if it is known.
262: *
263: * @return Axis.CHILD, etc., or -1 if the axis is not known or is of multiple
264: * types.
265: */
266: public int getAxis() {
267: return m_exprObj.getAxis();
268: }
269:
270: class filterExprOwner implements ExpressionOwner {
271: /**
272: * @see ExpressionOwner#getExpression()
273: */
274: public Expression getExpression() {
275: return m_expr;
276: }
277:
278: /**
279: * @see ExpressionOwner#setExpression(Expression)
280: */
281: public void setExpression(Expression exp) {
282: exp.exprSetParent(FilterExprWalker.this );
283: m_expr = exp;
284: }
285: }
286:
287: /**
288: * This will traverse the heararchy, calling the visitor for
289: * each member. If the called visitor method returns
290: * false, the subtree should not be called.
291: *
292: * @param visitor The visitor whose appropriate method will be called.
293: */
294: public void callPredicateVisitors(XPathVisitor visitor) {
295: m_expr.callVisitors(new filterExprOwner(), visitor);
296:
297: super .callPredicateVisitors(visitor);
298: }
299:
300: /**
301: * @see Expression#deepEquals(Expression)
302: */
303: public boolean deepEquals(Expression expr) {
304: if (!super .deepEquals(expr))
305: return false;
306:
307: FilterExprWalker walker = (FilterExprWalker) expr;
308: if (!m_expr.deepEquals(walker.m_expr))
309: return false;
310:
311: return true;
312: }
313:
314: }
|