001: package net.sf.saxon.instruct;
002:
003: import net.sf.saxon.Controller;
004: import net.sf.saxon.expr.*;
005: import net.sf.saxon.om.Item;
006: import net.sf.saxon.om.NamePool;
007: import net.sf.saxon.om.SequenceIterator;
008: import net.sf.saxon.style.StandardNames;
009: import net.sf.saxon.trace.TraceListener;
010: import net.sf.saxon.trans.XPathException;
011: import net.sf.saxon.type.ItemType;
012: import net.sf.saxon.type.SchemaType;
013: import net.sf.saxon.type.TypeHierarchy;
014: import net.sf.saxon.value.EmptySequence;
015:
016: import java.io.PrintStream;
017: import java.util.Iterator;
018:
019: /**
020: * Handler for xsl:for-each elements in a stylesheet.
021: */
022:
023: public class ForEach extends Instruction implements MappingFunction {
024:
025: private Expression select;
026: private Expression action;
027:
028: public ForEach(Expression select, Expression action) {
029: this .select = select;
030: this .action = action;
031: adoptChildExpression(select);
032: adoptChildExpression(action);
033: }
034:
035: /**
036: * Get the name of this instruction for diagnostic and tracing purposes
037: */
038:
039: public int getInstructionNameCode() {
040: return StandardNames.XSL_FOR_EACH;
041: }
042:
043: /**
044: * Get the action expression (the content of the for-each)
045: */
046:
047: public Expression getActionExpression() {
048: return action;
049: }
050:
051: /**
052: * Determine the data type of the items returned by this expression
053: * @return the data type
054: * @param th
055: */
056:
057: public final ItemType getItemType(TypeHierarchy th) {
058: return action.getItemType(th);
059: }
060:
061: /**
062: * Determine whether this instruction creates new nodes.
063: * This implementation returns true if the "action" creates new nodes.
064: * (Nodes created by the condition can't contribute to the result).
065: */
066:
067: public final boolean createsNewNodes() {
068: int props = action.getSpecialProperties();
069: return ((props & StaticProperty.NON_CREATIVE) == 0);
070: }
071:
072: /**
073: * Simplify an expression. This performs any static optimization (by rewriting the expression
074: * as a different expression).
075: *
076: * @exception XPathException if an error is discovered during expression
077: * rewriting
078: * @return the simplified expression
079: */
080:
081: public Expression simplify(StaticContext env) throws XPathException {
082: select = select.simplify(env);
083: action = action.simplify(env);
084: return this ;
085: }
086:
087: public Expression typeCheck(StaticContext env,
088: ItemType contextItemType) throws XPathException {
089: final TypeHierarchy th = env.getNamePool().getTypeHierarchy();
090: select = select.typeCheck(env, contextItemType);
091: adoptChildExpression(select);
092: action = action.typeCheck(env, select.getItemType(th));
093: adoptChildExpression(action);
094: if (select instanceof EmptySequence) {
095: return EmptySequence.getInstance();
096: }
097: if (action instanceof EmptySequence) {
098: return EmptySequence.getInstance();
099: }
100: return this ;
101: }
102:
103: public Expression optimize(Optimizer opt, StaticContext env,
104: ItemType contextItemType) throws XPathException {
105: final TypeHierarchy th = env.getNamePool().getTypeHierarchy();
106: select = select.optimize(opt, env, contextItemType);
107: adoptChildExpression(select);
108: action = action.optimize(opt, env, select.getItemType(th));
109: adoptChildExpression(action);
110: if (select instanceof EmptySequence) {
111: return EmptySequence.getInstance();
112: }
113: if (action instanceof EmptySequence) {
114: return EmptySequence.getInstance();
115: }
116:
117: // If any subexpressions within the body of the for-each are not dependent on the focus,
118: // promote them: this causes them to be evaluated once, outside the for-each loop
119:
120: PromotionOffer offer = new PromotionOffer(opt);
121: offer.action = PromotionOffer.FOCUS_INDEPENDENT;
122: offer.promoteDocumentDependent = (select.getSpecialProperties() & StaticProperty.CONTEXT_DOCUMENT_NODESET) != 0;
123: offer.promoteXSLTFunctions = false;
124: offer.containingExpression = this ;
125: action = doPromotion(action, offer);
126:
127: if (offer.containingExpression instanceof LetExpression) {
128: offer.containingExpression = offer.containingExpression
129: .optimize(opt, env, contextItemType);
130: }
131: return offer.containingExpression;
132: }
133:
134: /**
135: * Compute the dependencies of an expression, as the union of the
136: * dependencies of its subexpressions. (This is overridden for path expressions
137: * and filter expressions, where the dependencies of a subexpression are not all
138: * propogated). This method should be called only once, to compute the dependencies;
139: * after that, getDependencies should be used.
140: *
141: * @return the depencies, as a bit-mask
142: */
143:
144: public int computeDependencies() {
145: // Some of the dependencies aren't relevant. Note that the sort keys are absorbed into the select
146: // expression.
147: int dependencies = 0;
148: dependencies |= select.getDependencies();
149: dependencies |= (action.getDependencies() & ~StaticProperty.DEPENDS_ON_FOCUS);
150: return dependencies;
151: }
152:
153: /**
154: * Handle promotion offers, that is, non-local tree rewrites.
155: * @param offer The type of rewrite being offered
156: * @throws XPathException
157: */
158:
159: protected void promoteInst(PromotionOffer offer)
160: throws XPathException {
161: select = doPromotion(select, offer);
162: action = doPromotion(action, offer);
163: }
164:
165: /**
166: * Get all the XPath expressions associated with this instruction
167: * (in XSLT terms, the expression present on attributes of the instruction,
168: * as distinct from the child instructions in a sequence construction)
169: */
170:
171: public Iterator iterateSubExpressions() {
172: return new PairIterator(select, action);
173: }
174:
175: /**
176: * An implementation of Expression must provide at least one of the methods evaluateItem(), iterate(), or process().
177: * This method indicates which of these methods is provided. This implementation provides both iterate() and
178: * process() methods natively.
179: */
180:
181: public int getImplementationMethod() {
182: return ITERATE_METHOD | PROCESS_METHOD;
183: }
184:
185: /**
186: * Check that any elements and attributes constructed or returned by this expression are acceptable
187: * in the content model of a given complex type. It's always OK to say yes, since the check will be
188: * repeated at run-time. The process of checking element and attribute constructors against the content
189: * model of a complex type also registers the type of content expected of those constructors, so the
190: * static validation can continue recursively.
191: */
192:
193: public void checkPermittedContents(SchemaType parentType,
194: StaticContext env, boolean whole) throws XPathException {
195: action.checkPermittedContents(parentType, env, false);
196: }
197:
198: public TailCall processLeavingTail(XPathContext context)
199: throws XPathException {
200: Controller controller = context.getController();
201: SequenceIterator iter = select.iterate(context);
202:
203: XPathContextMajor c2 = context.newContext();
204: c2.setOrigin(this );
205: c2.setCurrentIterator(iter);
206: c2.setCurrentTemplate(null);
207:
208: if (controller.isTracing()) {
209: TraceListener listener = controller.getTraceListener();
210: while (true) {
211: Item item = iter.next();
212: if (item == null) {
213: break;
214: }
215: listener.startCurrentItem(item);
216: action.process(c2);
217: listener.endCurrentItem(item);
218: }
219: } else {
220: while (true) {
221: Item item = iter.next();
222: if (item == null) {
223: break;
224: }
225: action.process(c2);
226: }
227: }
228: return null;
229: }
230:
231: /**
232: * Return an Iterator to iterate over the values of a sequence. The value of every
233: * expression can be regarded as a sequence, so this method is supported for all
234: * expressions. This default implementation relies on the process() method: it
235: * "pushes" the results of the instruction to a sequence in memory, and then
236: * iterates over this in-memory sequence.
237: *
238: * In principle instructions should implement a pipelined iterate() method that
239: * avoids the overhead of intermediate storage.
240: *
241: * @exception XPathException if any dynamic error occurs evaluating the
242: * expression
243: * @param context supplies the context for evaluation
244: * @return a SequenceIterator that can be used to iterate over the result
245: * of the expression
246: */
247:
248: public SequenceIterator iterate(XPathContext context)
249: throws XPathException {
250: SequenceIterator master = select.iterate(context);
251: XPathContextMajor c2 = context.newContext();
252: c2.setOrigin(this );
253: c2.setCurrentTemplate(null);
254: c2.setCurrentIterator(master);
255: master = new MappingIterator(master, this , c2);
256: return master;
257: }
258:
259: /**
260: * Map one item to a sequence.
261: * @param item The item to be mapped.
262: * If context is supplied, this must be the same as context.currentItem().
263: * @param context The processing context. This is supplied only for mapping constructs that
264: * set the context node, position, and size. Otherwise it is null.
265: * @return either (a) a SequenceIterator over the sequence of items that the supplied input
266: * item maps to, or (b) an Item if it maps to a single item, or (c) null if it maps to an empty
267: * sequence.
268: */
269:
270: public Object map(Item item, XPathContext context)
271: throws XPathException {
272: return action.iterate(context);
273: }
274:
275: /**
276: * Diagnostic print of expression structure. The expression is written to the System.err
277: * output stream
278: *
279: * @param level indentation level for this expression
280: * @param out
281: */
282:
283: public void display(int level, NamePool pool, PrintStream out) {
284: out.println(ExpressionTool.indent(level) + "for-each");
285: select.display(level + 1, pool, out);
286: out.println(ExpressionTool.indent(level) + "return");
287: action.display(level + 1, pool, out);
288: }
289:
290: }
291:
292: //
293: // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
294: // you may not use this file except in compliance with the License. You may obtain a copy of the
295: // License at http://www.mozilla.org/MPL/
296: //
297: // Software distributed under the License is distributed on an "AS IS" basis,
298: // WITHOUT WARRANTY OF ANY KIND, either express or implied.
299: // See the License for the specific language governing rights and limitations under the License.
300: //
301: // The Original Code is: all this file.
302: //
303: // The Initial Developer of the Original Code is Michael H. Kay.
304: //
305: // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
306: //
307: // Contributor(s): none.
308: //
|