KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > net > sf > saxon > instruct > ForEach


1 package net.sf.saxon.instruct;
2 import net.sf.saxon.Controller;
3 import net.sf.saxon.expr.*;
4 import net.sf.saxon.om.Item;
5 import net.sf.saxon.om.NamePool;
6 import net.sf.saxon.om.SequenceIterator;
7 import net.sf.saxon.style.StandardNames;
8 import net.sf.saxon.trace.TraceListener;
9 import net.sf.saxon.trans.XPathException;
10 import net.sf.saxon.type.ItemType;
11 import net.sf.saxon.type.SchemaType;
12 import net.sf.saxon.value.EmptySequence;
13
14 import java.io.PrintStream JavaDoc;
15 import java.util.Iterator JavaDoc;
16
17
18 /**
19 * Handler for xsl:for-each elements in a stylesheet.
20 */

21
22 public class ForEach extends Instruction implements MappingFunction {
23
24     private Expression select;
25     private Expression action;
26
27     public ForEach(Expression select, Expression action) {
28         this.select = select;
29         this.action = action;
30         adoptChildExpression(select);
31         adoptChildExpression(action);
32     }
33
34     /**
35     * Get the name of this instruction for diagnostic and tracing purposes
36     */

37
38     public int getInstructionNameCode() {
39         return StandardNames.XSL_FOR_EACH;
40     }
41
42     /**
43      * Get the action expression (the content of the for-each)
44      */

45
46     public Expression getActionExpression() {
47         return action;
48     }
49
50     /**
51     * Determine the data type of the items returned by this expression
52     * @return the data type
53     */

54
55     public final ItemType getItemType() {
56         return action.getItemType();
57     }
58
59     /**
60      * Determine whether this instruction creates new nodes.
61      * This implementation returns true if the "action" creates new nodes.
62      * (Nodes created by the condition can't contribute to the result).
63      */

64
65     public final boolean createsNewNodes() {
66         int props = action.getSpecialProperties();
67         return ((props & StaticProperty.NON_CREATIVE) == 0);
68     }
69
70     /**
71      * Simplify an expression. This performs any static optimization (by rewriting the expression
72      * as a different expression).
73      *
74      * @exception XPathException if an error is discovered during expression
75      * rewriting
76      * @return the simplified expression
77      */

78
79     public Expression simplify(StaticContext env) throws XPathException {
80         select = select.simplify(env);
81         action = action.simplify(env);
82         return this;
83     }
84
85     public Expression typeCheck(StaticContext env, ItemType contextItemType) throws XPathException {
86         select = select.typeCheck(env, contextItemType);
87         adoptChildExpression(select);
88         action = action.typeCheck(env, select.getItemType());
89         adoptChildExpression(action);
90         if (select instanceof EmptySequence) {
91             return EmptySequence.getInstance();
92         }
93         if (action instanceof EmptySequence) {
94             return EmptySequence.getInstance();
95         }
96         return this;
97     }
98
99     public Expression optimize(Optimizer opt, StaticContext env, ItemType contextItemType) throws XPathException {
100         select = select.optimize(opt, env, contextItemType);
101         adoptChildExpression(select);
102         action = action.optimize(opt, env, select.getItemType());
103         adoptChildExpression(action);
104         if (select instanceof EmptySequence) {
105             return EmptySequence.getInstance();
106         }
107         if (action instanceof EmptySequence) {
108             return EmptySequence.getInstance();
109         }
110
111         // If any subexpressions within the body of the for-each are not dependent on the focus,
112
// promote them: this causes them to be evaluated once, outside the for-each loop
113

114         PromotionOffer offer = new PromotionOffer(opt);
115         offer.action = PromotionOffer.FOCUS_INDEPENDENT;
116         offer.promoteDocumentDependent = (select.getSpecialProperties() & StaticProperty.CONTEXT_DOCUMENT_NODESET) != 0;
117         offer.promoteXSLTFunctions = false;
118         offer.containingExpression = this;
119         action = doPromotion(action, offer);
120
121         if (offer.containingExpression instanceof LetExpression) {
122             offer.containingExpression =
123                     offer.containingExpression.typeCheck(env, contextItemType).optimize(opt, env, contextItemType);
124         }
125         return offer.containingExpression;
126     }
127
128
129     /**
130      * Compute the dependencies of an expression, as the union of the
131      * dependencies of its subexpressions. (This is overridden for path expressions
132      * and filter expressions, where the dependencies of a subexpression are not all
133      * propogated). This method should be called only once, to compute the dependencies;
134      * after that, getDependencies should be used.
135      *
136      * @return the depencies, as a bit-mask
137      */

138
139     public int computeDependencies() {
140         // Some of the dependencies aren't relevant. Note that the sort keys are absorbed into the select
141
// expression.
142
int dependencies = 0;
143         dependencies |= select.getDependencies();
144         dependencies |= (action.getDependencies() & ~StaticProperty.DEPENDS_ON_FOCUS);
145         return dependencies;
146     }
147
148
149     /**
150      * Handle promotion offers, that is, non-local tree rewrites.
151      * @param offer The type of rewrite being offered
152      * @throws XPathException
153      */

154
155     protected void promoteInst(PromotionOffer offer) throws XPathException {
156         select = doPromotion(select, offer);
157         action = doPromotion(action, offer);
158     }
159
160     /**
161      * Get all the XPath expressions associated with this instruction
162      * (in XSLT terms, the expression present on attributes of the instruction,
163      * as distinct from the child instructions in a sequence construction)
164      */

165
166     public Iterator iterateSubExpressions() {
167         return new PairIterator(select, action);
168     }
169
170     /**
171      * An implementation of Expression must provide at least one of the methods evaluateItem(), iterate(), or process().
172      * This method indicates which of these methods is provided. This implementation provides both iterate() and
173      * process() methods natively.
174      */

175
176     public int getImplementationMethod() {
177         return ITERATE_METHOD | PROCESS_METHOD;
178     }
179
180     /**
181      * Check that any elements and attributes constructed or returned by this expression are acceptable
182      * in the content model of a given complex type. It's always OK to say yes, since the check will be
183      * repeated at run-time. The process of checking element and attribute constructors against the content
184      * model of a complex type also registers the type of content expected of those constructors, so the
185      * static validation can continue recursively.
186      */

187
188     public void checkPermittedContents(SchemaType parentType, StaticContext env, boolean whole) throws XPathException {
189         action.checkPermittedContents(parentType, env, false);
190     }
191
192     public TailCall processLeavingTail(XPathContext context) throws XPathException {
193         Controller controller = context.getController();
194         SequenceIterator iter = select.iterate(context);
195
196         XPathContextMajor c2 = context.newContext();
197         c2.setOrigin(this);
198         c2.setCurrentIterator(iter);
199         c2.setCurrentTemplate(null);
200
201         if (controller.isTracing()) {
202             TraceListener listener = controller.getTraceListener();
203             while(true) {
204                 Item item = iter.next();
205                 if (item == null) {
206                     break;
207                 }
208                 listener.startCurrentItem(item);
209                 action.process(c2);
210                 listener.endCurrentItem(item);
211             }
212         } else {
213             while(true) {
214                 Item item = iter.next();
215                 if (item == null) {
216                     break;
217                 }
218                 action.process(c2);
219             }
220         }
221         return null;
222     }
223
224     /**
225      * Return an Iterator to iterate over the values of a sequence. The value of every
226      * expression can be regarded as a sequence, so this method is supported for all
227      * expressions. This default implementation relies on the process() method: it
228      * "pushes" the results of the instruction to a sequence in memory, and then
229      * iterates over this in-memory sequence.
230      *
231      * In principle instructions should implement a pipelined iterate() method that
232      * avoids the overhead of intermediate storage.
233      *
234      * @exception XPathException if any dynamic error occurs evaluating the
235      * expression
236      * @param context supplies the context for evaluation
237      * @return a SequenceIterator that can be used to iterate over the result
238      * of the expression
239      */

240
241     public SequenceIterator iterate(XPathContext context) throws XPathException {
242         SequenceIterator master = select.iterate(context);
243         XPathContextMajor c2 = context.newContext();
244         c2.setOrigin(this);
245         c2.setCurrentTemplate(null);
246         c2.setCurrentIterator(master);
247         master = new MappingIterator(master, this, c2);
248         return master;
249     }
250
251     /**
252      * Map one item to a sequence.
253      * @param item The item to be mapped.
254      * If context is supplied, this must be the same as context.currentItem().
255      * @param context The processing context. This is supplied only for mapping constructs that
256      * set the context node, position, and size. Otherwise it is null.
257      * @return either (a) a SequenceIterator over the sequence of items that the supplied input
258      * item maps to, or (b) an Item if it maps to a single item, or (c) null if it maps to an empty
259      * sequence.
260      */

261
262     public Object JavaDoc map(Item item, XPathContext context) throws XPathException {
263         return action.iterate(context);
264     }
265
266     /**
267      * Diagnostic print of expression structure. The expression is written to the System.err
268      * output stream
269      *
270      * @param level indentation level for this expression
271      * @param out
272      */

273
274     public void display(int level, NamePool pool, PrintStream JavaDoc out) {
275         out.println(ExpressionTool.indent(level) + "for-each");
276         select.display(level+1, pool, out);
277         out.println(ExpressionTool.indent(level) + "return");
278         action.display(level+1, pool, out);
279     }
280
281 }
282
283 //
284
// The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
285
// you may not use this file except in compliance with the License. You may obtain a copy of the
286
// License at http://www.mozilla.org/MPL/
287
//
288
// Software distributed under the License is distributed on an "AS IS" basis,
289
// WITHOUT WARRANTY OF ANY KIND, either express or implied.
290
// See the License for the specific language governing rights and limitations under the License.
291
//
292
// The Original Code is: all this file.
293
//
294
// The Initial Developer of the Original Code is Michael H. Kay.
295
//
296
// Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
297
//
298
// Contributor(s): none.
299
//
300
Popular Tags