KickJava   Java API By Example, From Geeks To Geeks.

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


1 package net.sf.saxon.instruct;
2 import net.sf.saxon.expr.*;
3 import net.sf.saxon.om.EmptyIterator;
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.trans.XPathException;
9 import net.sf.saxon.type.ItemType;
10 import net.sf.saxon.type.SchemaType;
11 import net.sf.saxon.type.Type;
12 import net.sf.saxon.value.Value;
13
14 import java.io.PrintStream JavaDoc;
15 import java.util.ArrayList JavaDoc;
16 import java.util.Iterator JavaDoc;
17
18 /**
19  * Compiled representation of an xsl:choose or xsl:if element in the stylesheet.
20  * Also used for typeswitch in XQuery.
21 */

22
23 public class Choose extends Instruction {
24
25     // The class implements both xsl:choose and xsl:if. There is a list of boolean
26
// expressions (conditions) and a list of corresponding actions: the conditions
27
// are evaluated in turn, and when one is found that is true, the corresponding
28
// action is evaluated. For xsl:if, there is always one condition and one action.
29
// An xsl:otherwise is compiled as if it were xsl:when test="true()". If no
30
// condition is satisfied, the instruction returns without doing anything.
31

32     private Expression[] conditions;
33     private Expression[] actions;
34
35
36     /**
37     * Construct an xsl:choose instruction
38     * @param conditions the conditions to be tested, in order
39     * @param actions the actions to be taken when the corresponding condition is true
40     */

41
42     public Choose(Expression[] conditions, Expression[] actions) {
43         this.conditions = conditions;
44         this.actions = actions;
45         for (int i=0; i<conditions.length; i++) {
46             adoptChildExpression(conditions[i]);
47         }
48         for (int i=0; i<actions.length; i++) {
49             adoptChildExpression(actions[i]);
50         }
51     }
52
53     /**
54     * Get the name of this instruction for diagnostic and tracing purposes
55     * We assume that if there was
56      * only one condition then it was an xsl:if; this is not necessarily so, but
57      * it's adequate for tracing purposes.
58     */

59
60
61     public int getInstructionNameCode() {
62         return (conditions.length==1 ? StandardNames.XSL_IF : StandardNames.XSL_CHOOSE);
63     }
64
65     /**
66      * Simplify an expression. This performs any static optimization (by rewriting the expression
67      * as a different expression).
68      *
69      * @exception XPathException if an error is discovered during expression
70      * rewriting
71      * @return the simplified expression
72      */

73
74     public Expression simplify(StaticContext env) throws XPathException {
75         for (int i=0; i<conditions.length; i++) {
76             conditions[i] = conditions[i].simplify(env);
77         }
78         for (int i=0; i<actions.length; i++) {
79             actions[i] = actions[i].simplify(env);
80         }
81         return this;
82     }
83
84     public Expression typeCheck(StaticContext env, ItemType contextItemType) throws XPathException {
85         for (int i=0; i<conditions.length; i++) {
86             conditions[i] = conditions[i].typeCheck(env, contextItemType);
87             adoptChildExpression(conditions[i]);
88         }
89         for (int i=0; i<actions.length; i++) {
90             actions[i] = actions[i].typeCheck(env, contextItemType);
91             adoptChildExpression(actions[i]);
92         }
93         return this;
94     }
95
96     public Expression optimize(Optimizer opt, StaticContext env, ItemType contextItemType) throws XPathException {
97         for (int i=0; i<conditions.length; i++) {
98             conditions[i] = conditions[i].optimize(opt, env, contextItemType);
99             adoptChildExpression(conditions[i]);
100             if (conditions[i] instanceof Value) {
101                 try {
102                     boolean b = ExpressionTool.effectiveBooleanValue(conditions[i].iterate(null));
103                     if (b) {
104                         // if condition is always true, remove all the subsequent conditions and actions
105
if (i==0) {
106                             return actions[0];
107                         } else if (i != conditions.length - 1) {
108                             Expression[] c2 = new Expression[i+1];
109                             Expression[] a2 = new Expression[i+1];
110                             System.arraycopy(conditions, 0, c2, 0, i+1);
111                             System.arraycopy(actions, 0, a2, 0, i+1);
112                             conditions = c2;
113                             actions = a2;
114                             break;
115                         }
116                     } else {
117                         // if condition is false, skip this test
118
Expression[] c2 = new Expression[conditions.length - 1];
119                         Expression[] a2 = new Expression[conditions.length - 1];
120                         System.arraycopy(conditions, 0, c2, 0, i);
121                         System.arraycopy(actions, 0, a2, 0, i);
122                         System.arraycopy(conditions, i+1, c2, i, conditions.length - i - 1);
123                         System.arraycopy(actions, i+1, a2, i, conditions.length - i - 1);
124                         conditions = c2;
125                         actions = a2;
126                         i--;
127                     }
128                 } catch (Exception JavaDoc e) {};
129             }
130         }
131         for (int i=0; i<actions.length; i++) {
132             actions[i] = actions[i].optimize(opt, env, contextItemType);
133             adoptChildExpression(actions[i]);
134         }
135         return this;
136     }
137
138
139     /**
140      * Get the item type of the items returned by evaluating this instruction
141      * @return the static item type of the instruction
142      */

143
144     public ItemType getItemType() {
145         ItemType type = actions[0].getItemType();
146         for (int i=1; i<actions.length; i++) {
147             type = Type.getCommonSuperType(type, actions[i].getItemType());
148         }
149         return type;
150     }
151
152     /**
153      * Determine whether this instruction creates new nodes.
154      * This implementation returns true if any of the "actions" creates new nodes.
155      * (Nodes created by the conditions can't contribute to the result).
156      */

157
158     public final boolean createsNewNodes() {
159         for (int i=0; i<actions.length; i++) {
160             int props = actions[i].getSpecialProperties();
161             if ((props & StaticProperty.NON_CREATIVE) == 0) {
162                 return true;
163             };
164         }
165         return false;
166     }
167
168     /**
169      * Get all the XPath expressions associated with this instruction
170      * (in XSLT terms, the expression present on attributes of the instruction,
171      * as distinct from the child instructions in a sequence construction)
172      */

173
174     public Iterator iterateSubExpressions() {
175         ArrayList JavaDoc list = new ArrayList JavaDoc(conditions.length + actions.length);
176         for (int i=0; i<conditions.length; i++) {
177             list.add(conditions[i]);
178         }
179         for (int i=0; i<actions.length; i++) {
180             list.add(actions[i]);
181         }
182         return list.iterator();
183     }
184
185     /**
186      * Handle promotion offers, that is, non-local tree rewrites.
187      * @param offer The type of rewrite being offered
188      * @throws XPathException
189      */

190
191     protected void promoteInst(PromotionOffer offer) throws XPathException {
192         // xsl:when acts as a guard: expressions inside the when mustn't be evaluated if the when is false,
193
// and conditions after the first mustn't be evaluated if a previous condition is true. So we
194
// don't pass all promotion offers on
195
if (offer.action == PromotionOffer.UNORDERED ||
196                 offer.action == PromotionOffer.INLINE_VARIABLE_REFERENCES ||
197                 offer.action == PromotionOffer.REPLACE_CURRENT) {
198             for (int i=0; i<conditions.length; i++) {
199                 conditions[i] = doPromotion(conditions[i], offer);
200             }
201             for (int i=0; i<actions.length; i++) {
202                 actions[i] = doPromotion(actions[i], offer);
203             }
204         } else {
205             // in other cases, only the first xsl:when condition is promoted
206
conditions[0] = doPromotion(conditions[0], offer);
207         }
208     }
209
210     /**
211      * Check that any elements and attributes constructed or returned by this expression are acceptable
212      * in the content model of a given complex type. It's always OK to say yes, since the check will be
213      * repeated at run-time. The process of checking element and attribute constructors against the content
214      * model of a complex type also registers the type of content expected of those constructors, so the
215      * static validation can continue recursively.
216      */

217
218     public void checkPermittedContents(SchemaType parentType, StaticContext env, boolean whole) throws XPathException {
219         for (int i=0; i<actions.length; i++) {
220             actions[i].checkPermittedContents(parentType, env, whole);
221         }
222     }
223
224     /**
225      * Diagnostic print of expression structure. The expression is written to the System.err
226      * output stream
227      *
228      * @param level indentation level for this expression
229      * @param out
230      */

231
232     public void display(int level, NamePool pool, PrintStream JavaDoc out) {
233         for (int i=0; i<conditions.length; i++) {
234             out.println(ExpressionTool.indent(level) + (i==0 ? "if" : "else if"));
235             conditions[i].display(level+1, pool, out);
236             out.println(ExpressionTool.indent(level) + "then");
237             actions[i].display(level+1, pool, out);
238         }
239     }
240
241     /**
242     * Process this instruction, that is, choose an xsl:when or xsl:otherwise child
243     * and process it.
244     * @param context the dynamic context of this transformation
245     * @throws XPathException if any non-recoverable dynamic error occurs
246     * @return a TailCall, if the chosen branch ends with a call of call-template or
247     * apply-templates. It is the caller's responsibility to execute such a TailCall.
248     * If there is no TailCall, returns null.
249     */

250
251     public TailCall processLeavingTail(XPathContext context) throws XPathException {
252         for (int i=0; i<conditions.length; i++) {
253             if (conditions[i].effectiveBooleanValue(context)) {
254                 if (actions[i] instanceof TailCallReturner) {
255                     return ((TailCallReturner)actions[i]).processLeavingTail(context);
256                 } else {
257                     actions[i].process(context);
258                     return null;
259                 }
260             }
261         }
262         return null;
263     }
264
265     /**
266      * Evaluate an expression as a single item. This always returns either a single Item or
267      * null (denoting the empty sequence). No conversion is done. This method should not be
268      * used unless the static type of the expression is a subtype of "item" or "item?": that is,
269      * it should not be called if the expression may return a sequence. There is no guarantee that
270      * this condition will be detected.
271      *
272      * @param context The context in which the expression is to be evaluated
273      * @exception XPathException if any dynamic error occurs evaluating the
274      * expression
275      * @return the node or atomic value that results from evaluating the
276      * expression; or null to indicate that the result is an empty
277      * sequence
278      */

279
280     public Item evaluateItem(XPathContext context) throws XPathException {
281         for (int i=0; i<conditions.length; i++) {
282             if (conditions[i].effectiveBooleanValue(context)) {
283                 return actions[i].evaluateItem(context);
284             }
285         }
286         return null;
287     }
288
289     /**
290      * Return an Iterator to iterate over the values of a sequence. The value of every
291      * expression can be regarded as a sequence, so this method is supported for all
292      * expressions. This default implementation relies on the process() method: it
293      * "pushes" the results of the instruction to a sequence in memory, and then
294      * iterates over this in-memory sequence.
295      *
296      * In principle instructions should implement a pipelined iterate() method that
297      * avoids the overhead of intermediate storage.
298      *
299      * @exception XPathException if any dynamic error occurs evaluating the
300      * expression
301      * @param context supplies the context for evaluation
302      * @return a SequenceIterator that can be used to iterate over the result
303      * of the expression
304      */

305
306     public SequenceIterator iterate(XPathContext context) throws XPathException {
307         for (int i=0; i<conditions.length; i++) {
308             if (conditions[i].effectiveBooleanValue(context)) {
309                 return (actions[i]).iterate(context);
310             }
311         }
312         return EmptyIterator.getInstance();
313     }
314 }
315
316 //
317
// The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
318
// you may not use this file except in compliance with the License. You may obtain a copy of the
319
// License at http://www.mozilla.org/MPL/
320
//
321
// Software distributed under the License is distributed on an "AS IS" basis,
322
// WITHOUT WARRANTY OF ANY KIND, either express or implied.
323
// See the License for the specific language governing rights and limitations under the License.
324
//
325
// The Original Code is: all this file.
326
//
327
// The Initial Developer of the Original Code is Michael H. Kay.
328
//
329
// Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
330
//
331
// Contributor(s):
332
// Portions marked "e.g." are from Edwin Glaser (edwin@pannenleiter.de)
333
//
334
Popular Tags