KickJava   Java API By Example, From Geeks To Geeks.

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


1 package net.sf.saxon.instruct;
2
3 import net.sf.saxon.Controller;
4 import net.sf.saxon.expr.*;
5 import net.sf.saxon.om.Item;
6 import net.sf.saxon.om.NamePool;
7 import net.sf.saxon.om.SequenceIterator;
8 import net.sf.saxon.pattern.PatternSponsor;
9 import net.sf.saxon.sort.*;
10 import net.sf.saxon.style.StandardNames;
11 import net.sf.saxon.trace.TraceListener;
12 import net.sf.saxon.trans.XPathException;
13 import net.sf.saxon.type.ItemType;
14 import net.sf.saxon.type.SchemaType;
15 import net.sf.saxon.value.EmptySequence;
16 import net.sf.saxon.value.Value;
17
18 import java.io.PrintStream JavaDoc;
19 import java.util.ArrayList JavaDoc;
20 import java.util.Comparator JavaDoc;
21 import java.util.Iterator JavaDoc;
22
23 /**
24  * Handler for xsl:for-each-group elements in stylesheet. This is a new instruction
25  * defined in XSLT 2.0
26  */

27
28 public class ForEachGroup extends Instruction implements MappingFunction {
29
30     public static final int GROUP_BY = 0;
31     public static final int GROUP_ADJACENT = 1;
32     public static final int GROUP_STARTING = 2;
33     public static final int GROUP_ENDING = 3;
34
35
36     private Expression select;
37     private Expression action;
38     private byte algorithm;
39     private Expression key; // for group-starting and group-ending, this is a PatternSponsor
40
private Comparator JavaDoc collator = null;
41     private SortKeyDefinition[] sortKeys = null;
42
43     public ForEachGroup(Expression select,
44                         Expression action,
45                         byte algorithm,
46                         Expression key,
47                         Comparator JavaDoc collator,
48                         SortKeyDefinition[] sortKeys) {
49         this.select = select;
50         this.action = action;
51         this.algorithm = algorithm;
52         this.key = key;
53         this.collator = collator;
54         this.sortKeys = sortKeys;
55         Iterator kids = iterateSubExpressions();
56         while (kids.hasNext()) {
57             Expression child = (Expression)kids.next();
58             adoptChildExpression(child);
59         }
60     }
61
62     /**
63      * Get the name of this instruction for diagnostic and tracing purposes
64      */

65
66     public int getInstructionNameCode() {
67         return StandardNames.XSL_FOR_EACH_GROUP;
68     }
69
70     /**
71      * Get the action expression (the content of the for-each)
72      */

73
74     public Expression getActionExpression() {
75         return action;
76     }
77
78     /**
79      * Simplify an expression. This performs any static optimization (by rewriting the expression
80      * as a different expression).
81      *
82      * @return the simplified expression
83      * @throws XPathException if an error is discovered during expression
84      * rewriting
85      */

86
87     public Expression simplify(StaticContext env) throws XPathException {
88         select = select.simplify(env);
89         action = action.simplify(env);
90         key = key.simplify(env);
91         return this;
92     }
93
94     public Expression typeCheck(StaticContext env, ItemType contextItemType) throws XPathException {
95         select = select.typeCheck(env, contextItemType);
96         action = action.typeCheck(env, select.getItemType());
97         key = key.typeCheck(env, select.getItemType());
98         adoptChildExpression(select);
99         adoptChildExpression(action);
100         adoptChildExpression(key);
101         if (select instanceof EmptySequence) {
102             return EmptySequence.getInstance();
103         }
104         if (action instanceof EmptySequence) {
105             return EmptySequence.getInstance();
106         }
107         return this;
108     }
109
110     public Expression optimize(Optimizer opt, StaticContext env, ItemType contextItemType) throws XPathException {
111         select = select.optimize(opt, env, contextItemType);
112         action = action.optimize(opt, env, select.getItemType());
113         key = key.optimize(opt, env, select.getItemType());
114         adoptChildExpression(select);
115         adoptChildExpression(action);
116         adoptChildExpression(key);
117         if (select instanceof EmptySequence) {
118             return EmptySequence.getInstance();
119         }
120         if (action instanceof EmptySequence) {
121             return EmptySequence.getInstance();
122         }
123         return this;
124     }
125
126     /**
127      * Get the item type of the items returned by evaluating this instruction
128      *
129      * @return the static item type of the instruction
130      */

131
132     public ItemType getItemType() {
133         return action.getItemType();
134     }
135
136     /**
137      * Compute the dependencies of an expression, as the union of the
138      * dependencies of its subexpressions. (This is overridden for path expressions
139      * and filter expressions, where the dependencies of a subexpression are not all
140      * propogated). This method should be called only once, to compute the dependencies;
141      * after that, getDependencies should be used.
142      *
143      * @return the depencies, as a bit-mask
144      */

145
146     public int computeDependencies() {
147         // some of the dependencies in the "action" part and in the grouping and sort keys aren't relevant,
148
// because they don't depend on values set outside the for-each-group expression
149
int dependencies = 0;
150         dependencies |= select.getDependencies();
151         dependencies |= key.getDependencies() & ~StaticProperty.DEPENDS_ON_FOCUS;
152         dependencies |= (action.getDependencies()
153                     &~ (StaticProperty.DEPENDS_ON_FOCUS | StaticProperty.DEPENDS_ON_CURRENT_GROUP));
154         if (sortKeys != null) {
155             for (int i = 0; i < sortKeys.length; i++) {
156                 dependencies |= (sortKeys[i].getSortKey().getDependencies() &~ StaticProperty.DEPENDS_ON_FOCUS);
157                 Expression e = sortKeys[i].getCaseOrder();
158                 if (e != null && !(e instanceof Value)) {
159                     dependencies |= (e.getDependencies());
160                 }
161                 e = sortKeys[i].getDataTypeExpression();
162                 if (e != null && !(e instanceof Value)) {
163                     dependencies |= (e.getDependencies());
164                 }
165                 e = sortKeys[i].getLanguage();
166                 if (e != null && !(e instanceof Value)) {
167                     dependencies |= (e.getDependencies());
168                 }
169             }
170         }
171         return dependencies;
172     }
173
174     /**
175      * Determine whether this instruction creates new nodes.
176      * This implementation returns true if the "action" creates new nodes.
177      * (Nodes created by the condition can't contribute to the result).
178      */

179
180     public final boolean createsNewNodes() {
181         int props = action.getSpecialProperties();
182         return ((props & StaticProperty.NON_CREATIVE) == 0);
183     }
184
185     /**
186      * Handle promotion offers, that is, non-local tree rewrites.
187      *
188      * @param offer The type of rewrite being offered
189      * @throws XPathException
190      */

191
192     protected void promoteInst(PromotionOffer offer) throws XPathException {
193         select = doPromotion(select, offer);
194         action = doPromotion(action, offer);
195         key = doPromotion(key, offer);
196     }
197
198     /**
199      * Get all the XPath expressions associated with this instruction
200      * (in XSLT terms, the expression present on attributes of the instruction,
201      * as distinct from the child instructions in a sequence construction)
202      */

203
204     public Iterator iterateSubExpressions() {
205         ArrayList JavaDoc list = new ArrayList JavaDoc(3);
206         list.add(select);
207         list.add(action);
208         list.add(key);
209         if (sortKeys != null) {
210             for (int i = 0; i < sortKeys.length; i++) {
211                 list.add(sortKeys[i].getSortKey());
212                 Expression e = sortKeys[i].getOrder();
213                 if (e != null && !(e instanceof Value)) {
214                     list.add(e);
215                 }
216                 e = sortKeys[i].getCaseOrder();
217                 if (e != null && !(e instanceof Value)) {
218                     list.add(e);
219                 }
220                 e = sortKeys[i].getDataTypeExpression();
221                 if (e != null && !(e instanceof Value)) {
222                     list.add(e);
223                 }
224                 e = sortKeys[i].getLanguage();
225                 if (e != null && !(e instanceof Value)) {
226                     list.add(e);
227                 }
228             }
229         }
230         return list.iterator();
231     }
232
233     /**
234      * Check that any elements and attributes constructed or returned by this expression are acceptable
235      * in the content model of a given complex type. It's always OK to say yes, since the check will be
236      * repeated at run-time. The process of checking element and attribute constructors against the content
237      * model of a complex type also registers the type of content expected of those constructors, so the
238      * static validation can continue recursively.
239      */

240
241     public void checkPermittedContents(SchemaType parentType, StaticContext env, boolean whole) throws XPathException {
242         action.checkPermittedContents(parentType, env, false);
243     }
244
245     public TailCall processLeavingTail(XPathContext context) throws XPathException {
246         Controller controller = context.getController();
247
248         GroupIterator groupIterator = getGroupIterator(context);
249
250         XPathContextMajor c2 = context.newContext();
251         c2.setOrigin(this);
252         c2.setCurrentIterator(groupIterator);
253         c2.setCurrentGroupIterator(groupIterator);
254         c2.setCurrentTemplate(null);
255
256         if (controller.isTracing()) {
257             TraceListener listener = controller.getTraceListener();
258             while (true) {
259                 Item item = groupIterator.next();
260                 if (item == null) {
261                     break;
262                 }
263                 listener.startCurrentItem(item);
264                 action.process(c2);
265                 listener.endCurrentItem(item);
266             }
267         } else {
268             while (true) {
269                 Item item = groupIterator.next();
270                 if (item == null) {
271                     break;
272                 }
273                 action.process(c2);
274             }
275         }
276
277         return null;
278     }
279
280     private GroupIterator getGroupIterator(XPathContext context) throws XPathException {
281         SequenceIterator population = select.iterate(context);
282
283         // get an iterator over the groups in "order of first appearance"
284

285         GroupIterator groupIterator;
286         switch (algorithm) {
287             case GROUP_BY:
288                 {
289                     XPathContext c2 = context.newMinorContext();
290                     c2.setOrigin(this);
291                     c2.setCurrentIterator(population);
292                     groupIterator = new GroupByIterator(population, key, c2, collator);
293                     break;
294                 }
295             case GROUP_ADJACENT:
296                 {
297                     groupIterator = new GroupAdjacentIterator(population, key, context, collator);
298                     break;
299                 }
300             case GROUP_STARTING:
301                 groupIterator = new GroupStartingIterator(population,
302                         ((PatternSponsor)key).getPattern(),
303                         context);
304                 break;
305             case GROUP_ENDING:
306                 groupIterator = new GroupEndingIterator(population,
307                         ((PatternSponsor)key).getPattern(),
308                         context);
309                 break;
310             default:
311                 throw new AssertionError JavaDoc("Unknown grouping algorithm");
312         }
313
314
315         // now iterate over the leading nodes of the groups
316

317         if (sortKeys != null) {
318             // TODO: avoid reducing the sort keys if they have no dependencies
319
FixedSortKeyDefinition[] reducedSortKeys = new FixedSortKeyDefinition[sortKeys.length];
320             XPathContext xpc = context.newMinorContext();
321             for (int s = 0; s < sortKeys.length; s++) {
322                 reducedSortKeys[s] = sortKeys[s].reduce(xpc);
323             }
324             groupIterator = new SortedGroupIterator(xpc,
325                     groupIterator,
326                     reducedSortKeys,
327                     this);
328         }
329         return groupIterator;
330     }
331
332     /**
333      * Return an Iterator to iterate over the values of a sequence. The value of every
334      * expression can be regarded as a sequence, so this method is supported for all
335      * expressions. This default implementation relies on the process() method: it
336      * "pushes" the results of the instruction to a sequence in memory, and then
337      * iterates over this in-memory sequence.
338      * <p/>
339      * In principle instructions should implement a pipelined iterate() method that
340      * avoids the overhead of intermediate storage.
341      *
342      * @param context supplies the context for evaluation
343      * @return a SequenceIterator that can be used to iterate over the result
344      * of the expression
345      * @throws XPathException if any dynamic error occurs evaluating the
346      * expression
347      */

348
349     public SequenceIterator iterate(XPathContext context) throws XPathException {
350         GroupIterator master = getGroupIterator(context);
351         XPathContextMajor c2 = context.newContext();
352         c2.setOrigin(this);
353         c2.setCurrentIterator(master);
354         c2.setCurrentGroupIterator(master);
355         c2.setCurrentTemplate(null);
356         return new MappingIterator(master, this, c2);
357     }
358
359     /**
360      * Map one item to a sequence.
361      *
362      * @param item The item to be mapped.
363      * If context is supplied, this must be the same as context.currentItem().
364      * @param context The processing context. This is supplied only for mapping constructs that
365      * set the context node, position, and size. Otherwise it is null.
366      * @return either (a) a SequenceIterator over the sequence of items that the supplied input
367      * item maps to, or (b) an Item if it maps to a single item, or (c) null if it maps to an empty
368      * sequence.
369      */

370
371     public Object JavaDoc map(Item item, XPathContext context) throws XPathException {
372         return action.iterate(context);
373     }
374
375     /**
376      * Diagnostic print of expression structure. The expression is written to the System.err
377      * output stream
378      *
379      * @param level indentation level for this expression
380      * @param out
381      */

382
383     public void display(int level, NamePool pool, PrintStream JavaDoc out) {
384         out.println(ExpressionTool.indent(level) + "for-each-group");
385         out.println(ExpressionTool.indent(level) + "select");
386         select.display(level + 1, pool, out);
387         out.println(ExpressionTool.indent(level) + "return");
388         action.display(level + 1, pool, out);
389     }
390 }
391
392 //
393
// The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
394
// you may not use this file except in compliance with the License. You may obtain a copy of the
395
// License at http://www.mozilla.org/MPL/
396
//
397
// Software distributed under the License is distributed on an "AS IS" basis,
398
// WITHOUT WARRANTY OF ANY KIND, either express or implied.
399
// See the License for the specific language governing rights and limitations under the License.
400
//
401
// The Original Code is: all this file.
402
//
403
// The Initial Developer of the Original Code is Michael H. Kay.
404
//
405
// Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
406
//
407
// Contributor(s): none.
408
//
409
Popular Tags