KickJava   Java API By Example, From Geeks To Geeks.

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


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.pattern.NoNodeTest;
8 import net.sf.saxon.trans.DynamicError;
9 import net.sf.saxon.trans.XPathException;
10 import net.sf.saxon.type.AnyItemType;
11 import net.sf.saxon.type.ItemType;
12 import net.sf.saxon.type.SchemaType;
13 import net.sf.saxon.type.Type;
14 import net.sf.saxon.value.Cardinality;
15 import net.sf.saxon.value.EmptySequence;
16 import net.sf.saxon.value.SequenceExtent;
17
18 import java.io.PrintStream JavaDoc;
19 import java.util.*;
20
21
22 /**
23 * Implements an imaginary xsl:block instruction which simply evaluates
24 * its contents. Used for top-level templates, xsl:otherwise, etc.
25 */

26
27 public class Block extends Instruction {
28
29     private Expression[] children;
30
31     public Block() {
32     }
33
34     public static Block makeBlock(Expression e1, Expression e2) {
35         if (e1 instanceof Block || e2 instanceof Block) {
36             Iterator it1 = (e1 instanceof Block ? e1.iterateSubExpressions() : new MonoIterator(e1));
37             Iterator it2 = (e2 instanceof Block ? e2.iterateSubExpressions() : new MonoIterator(e2));
38             List list = new ArrayList(10);
39             while (it1.hasNext()) {
40                 list.add(it1.next());
41             }
42             while (it2.hasNext()) {
43                 list.add(it2.next());
44             }
45             Expression[] exps = new Expression[list.size()];
46             exps = (Expression[])list.toArray(exps);
47             Block b = new Block();
48             b.setChildren(exps);
49             return b;
50         } else {
51             Expression[] exps = {e1, e2};
52             Block b = new Block();
53             b.setChildren(exps);
54             return b;
55         }
56     }
57
58     /**
59     * Set the children of this instruction
60     * @param children The instructions that are children of this instruction
61     */

62
63     public void setChildren(Expression[] children) {
64         if (children==null || children.length==0) {
65             this.children = null;
66         } else {
67             this.children = children;
68             for (int c=0; c<children.length; c++) {
69                 adoptChildExpression(children[c]);
70             }
71         }
72     }
73
74     /**
75     * Get the children of this instruction
76     * @return the children of this instruction, as an array of Instruction objects. May return either
77      * a zero-length array or null if there are no children
78     */

79
80     public Expression[] getChildren() {
81         return children;
82     }
83
84     public Iterator iterateSubExpressions() {
85         if (children == null) {
86             return Collections.EMPTY_LIST.iterator();
87         } else {
88             return Arrays.asList(children).iterator();
89         }
90     }
91
92     /**
93     * Determine the data type of the items returned by this expression
94     * @return the data type
95     */

96
97     public final ItemType getItemType() {
98         if (children==null || children.length==0) {
99             return NoNodeTest.getInstance();
100         }
101         ItemType t1 = children[0].getItemType();
102         for (int i=1; i<children.length; i++) {
103             t1 = Type.getCommonSuperType(t1, children[i].getItemType());
104             if (t1 instanceof AnyItemType) {
105                 return t1; // no point going any further
106
}
107         }
108         return t1;
109     }
110
111     /**
112      * Determine the cardinality of the expression
113      */

114
115     public final int getCardinality() {
116         if (children==null || children.length==0) {
117             return StaticProperty.EMPTY;
118         }
119         int c1 = children[0].getCardinality();
120         for (int i=1; i<children.length; i++) {
121             c1 = Cardinality.add(c1, children[i].getCardinality());
122             if (c1 == StaticProperty.ALLOWS_ZERO_OR_MORE) {
123                 break;
124             }
125         }
126         return c1;
127     }
128
129     /**
130      * Determine whether this instruction creates new nodes.
131      * This implementation returns true if any child instruction
132      * returns true.
133      */

134
135     public final boolean createsNewNodes() {
136         if (children==null) {
137             return false;
138         };
139         for (int i=0; i<children.length; i++) {
140             int props = children[i].getSpecialProperties();
141             if ((props & StaticProperty.NON_CREATIVE) == 0) {
142                 return true;
143             }
144         }
145         return false;
146     }
147
148     /**
149      * Simplify an expression. This performs any static optimization (by rewriting the expression
150      * as a different expression). The default implementation does nothing.
151      *
152      * @exception XPathException if an error is discovered during expression
153      * rewriting
154      * @return the simplified expression
155      */

156
157     public Expression simplify(StaticContext env) throws XPathException {
158         boolean allAtomic = true;
159         boolean nested = false;
160         if (children != null) {
161             for (int c=0; c<children.length; c++) {
162                 children[c] = children[c].simplify(env);
163                 if (!(children[c] instanceof Item)) {
164                     allAtomic = false;
165                 }
166                 if (children[c] instanceof Block) {
167                     nested = true;
168                 } else if (children[c] instanceof EmptySequence) {
169                     nested = true;
170                 }
171             }
172             if (children.length == 1) {
173                 return getChildren()[0];
174             }
175             if (children.length == 0) {
176                 return EmptySequence.getInstance();
177             }
178             if (nested) {
179                 List list = new ArrayList(children.length*2);
180                 flatten(list);
181                 children = new Expression[list.size()];
182                 for (int i=0; i<children.length; i++) {
183                     children[i] = (Expression)list.get(i);
184                     adoptChildExpression(children[i]);
185                 }
186             }
187             if (allAtomic) {
188                 Item[] values = new Item[children.length];
189                 for (int c=0; c<children.length; c++) {
190                     values[c] = (Item)children[c];
191                 }
192                 return new SequenceExtent(values);
193             }
194         } else {
195             return EmptySequence.getInstance();
196         }
197
198         return this;
199     }
200
201     private void flatten(List list) {
202         for (int i=0; i<children.length; i++) {
203             if (children[i] instanceof Block) {
204                 ((Block)children[i]).flatten(list);
205             } else if (children[i] instanceof EmptySequence) {
206                 // no-op
207
} else {
208                 list.add(children[i]);
209             }
210         }
211     }
212
213     public Expression typeCheck(StaticContext env, ItemType contextItemType) throws XPathException {
214         boolean nested = false;
215         if (children != null) {
216             for (int c=0; c<children.length; c++) {
217                 children[c] = children[c].typeCheck(env, contextItemType);
218                 adoptChildExpression(children[c]);
219                 if (children[c] instanceof Block) {
220                     nested = true;
221                 } else if (children[c] instanceof EmptySequence) {
222                     nested = true;
223                 }
224             }
225         }
226         if (nested) {
227             List list = new ArrayList(children.length*2);
228             flatten(list);
229             children = new Expression[list.size()];
230             for (int i=0; i<children.length; i++) {
231                 children[i] = (Expression)list.get(i);
232                 adoptChildExpression(children[i]);
233             }
234         }
235         if (children.length == 0) {
236             return EmptySequence.getInstance();
237         } else if (children.length == 1) {
238             return children[0];
239         } else {
240             return this;
241         }
242     }
243
244     public Expression optimize(Optimizer opt, StaticContext env, ItemType contextItemType) throws XPathException {
245         if (children != null) {
246             for (int c=0; c<children.length; c++) {
247                 children[c] = children[c].optimize(opt, env, contextItemType);
248                 adoptChildExpression(children[c]);
249             }
250         }
251         return this;
252     }
253
254
255
256     /**
257      * Handle promotion offers, that is, non-local tree rewrites.
258      * @param offer The type of rewrite being offered
259      * @throws XPathException
260      */

261
262     protected void promoteInst(PromotionOffer offer) throws XPathException {
263         if (children != null) {
264             for (int c=0; c<children.length; c++) {
265                 children[c] = doPromotion(children[c], offer);
266             }
267         }
268     }
269
270     /**
271      * Check that any elements and attributes constructed or returned by this expression are acceptable
272      * in the content model of a given complex type. It's always OK to say yes, since the check will be
273      * repeated at run-time. The process of checking element and attribute constructors against the content
274      * model of a complex type also registers the type of content expected of those constructors, so the
275      * static validation can continue recursively.
276      */

277
278     public void checkPermittedContents(SchemaType parentType, StaticContext env, boolean whole) throws XPathException {
279         if (children != null) {
280             for (int c=0; c<children.length; c++) {
281                 children[c].checkPermittedContents(parentType, env, false);
282             }
283         }
284     }
285
286     /**
287      * Diagnostic print of expression structure. The expression is written to the System.err
288      * output stream
289      *
290      * @param level indentation level for this expression
291      * @param out
292      */

293
294     public void display(int level, NamePool pool, PrintStream JavaDoc out) {
295         if (children != null) {
296             displayChildren(children, level+1, pool, out);
297         }
298     }
299
300     /**
301      * Display the children of an instruction for diagostics
302      */

303
304     public static void displayChildren(Expression[] children, int level, NamePool pool, PrintStream JavaDoc out) {
305         if (children != null) {
306             for (int c=0; c<children.length; c++) {
307                 children[c].display(level+1, pool, out);
308             }
309         }
310     }
311
312
313     public TailCall processLeavingTail(XPathContext context) throws XPathException {
314
315         if (children==null) {
316             return null;
317         }
318
319         TailCall tc = null;
320         for (int i=0; i<children.length; i++) {
321             try {
322                 if (children[i] instanceof TailCallReturner) {
323                     tc = ((TailCallReturner)children[i]).processLeavingTail(context);
324                 } else {
325                     children[i].process(context);
326                     tc = null;
327                 }
328             } catch (DynamicError e) {
329                 if (e.getXPathContext() == null) {
330                     e.setXPathContext(context);
331                 }
332                 if (e.getLocator()==null) {
333                     e.setLocator(ExpressionTool.getLocator(children[i]));
334                 }
335                 throw e;
336             }
337         }
338         return tc;
339     }
340
341     /**
342      * An implementation of Expression must provide at least one of the methods evaluateItem(), iterate(), or process().
343      * This method indicates which of these methods is provided. This implementation provides both iterate() and
344      * process() methods natively.
345      */

346
347     public int getImplementationMethod() {
348         return ITERATE_METHOD | PROCESS_METHOD;
349     }
350
351     /**
352      * Iterate over the results of all the child expressions
353      */

354
355     public SequenceIterator iterate(XPathContext context) throws XPathException {
356         if (children==null || children.length == 0) {
357             return EmptyIterator.getInstance();
358         } else if (children.length == 1) {
359             return children[0].iterate(context);
360         } else {
361             return new BlockIterator(context);
362         }
363     }
364
365     /**
366      * Iterate over the instructions in the Block, concatenating the result of each instruction
367      * into a single combined sequence.
368      */

369
370     private class BlockIterator implements SequenceIterator {
371
372         private int i = 0;
373         private SequenceIterator child;
374         private XPathContext context;
375         private Item current;
376         private int position = 0;
377
378         public BlockIterator(XPathContext context) {
379             this.context = context;
380         }
381
382         /**
383          * Get the next item in the sequence. <BR>
384          *
385          * @return the next item, or null if there are no more items.
386          * @throws net.sf.saxon.trans.XPathException
387          * if an error occurs retrieving the next item
388          */

389
390         public Item next() throws XPathException {
391             if (position < 0) {
392                 return null;
393             }
394             while (true) {
395                 if (child == null) {
396                     child = children[i++].iterate(context);
397                 }
398                 current = child.next();
399                 if (current != null) {
400                     position++;
401                     return current;
402                 }
403                 child = null;
404                 if (i >= children.length) {
405                     current = null;
406                     position = -1;
407                     return null;
408                 }
409             }
410         }
411
412         /**
413          * Get the current value in the sequence (the one returned by the
414          * most recent call on next()). This will be null before the first
415          * call of next().
416          *
417          * @return the current item, the one most recently returned by a call on
418          * next(); or null, if next() has not been called, or if the end
419          * of the sequence has been reached.
420          */

421
422         public Item current() {
423             return current;
424         }
425
426         /**
427          * Get the current position. This will be zero before the first call
428          * on next(), otherwise it will be the number of times that next() has
429          * been called.
430          *
431          * @return the current position, the position of the item returned by the
432          * most recent call of next()
433          */

434
435         public int position() {
436             return position;
437         }
438
439         /**
440          * Get another SequenceIterator that iterates over the same items as the original,
441          * but which is repositioned at the start of the sequence.
442          *
443          * @return a SequenceIterator that iterates over the same items,
444          * positioned before the first item
445          * @throws net.sf.saxon.trans.XPathException
446          * if any error occurs
447          */

448
449         public SequenceIterator getAnother() throws XPathException {
450             return new BlockIterator(context);
451         }
452
453         /**
454          * Get properties of this iterator, as a bit-significant integer.
455          *
456          * @return the properties of this iterator. This will be some combination of
457          * properties such as {@link GROUNDED}, {@link LAST_POSITION_FINDER},
458          * and {@link LOOKAHEAD}. It is always
459          * acceptable to return the value zero, indicating that there are no known special properties.
460          * It is acceptable for the properties of the iterator to change depending on its state.
461          */

462
463         public int getProperties() {
464             return 0;
465         }
466     }
467 }
468 //
469
// The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
470
// you may not use this file except in compliance with the License. You may obtain a copy of the
471
// License at http://www.mozilla.org/MPL/
472
//
473
// Software distributed under the License is distributed on an "AS IS" basis,
474
// WITHOUT WARRANTY OF ANY KIND, either express or implied.
475
// See the License for the specific language governing rights and limitations under the License.
476
//
477
// The Original Code is: all this file.
478
//
479
// The Initial Developer of the Original Code is Michael H. Kay.
480
//
481
// Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
482
//
483
// Contributor(s): none.
484
//
485
Popular Tags