KickJava   Java API By Example, From Geeks To Geeks.

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


1 package net.sf.saxon.instruct;
2 import net.sf.saxon.Controller;
3 import net.sf.saxon.expr.*;
4 import net.sf.saxon.om.*;
5 import net.sf.saxon.style.StandardNames;
6 import net.sf.saxon.trace.InstructionInfo;
7 import net.sf.saxon.trace.Location;
8 import net.sf.saxon.trace.TraceListener;
9 import net.sf.saxon.trans.DynamicError;
10 import net.sf.saxon.trans.Mode;
11 import net.sf.saxon.trans.XPathException;
12 import net.sf.saxon.trans.SaxonErrorCode;
13 import net.sf.saxon.type.ItemType;
14 import net.sf.saxon.type.Type;
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.Iterator JavaDoc;
21
22 /**
23 * An instruction representing an xsl:apply-templates element in the stylesheet
24 */

25
26 public class ApplyTemplates extends Instruction {
27
28     private Expression select;
29     private WithParam[] actualParams = null;
30     private WithParam[] tunnelParams = null;
31     private boolean useCurrentMode = false;
32     private boolean useTailRecursion = false;
33     private Mode mode;
34     private boolean backwardsCompatible;
35
36     public ApplyTemplates( Expression select,
37                             boolean useCurrentMode,
38                             boolean useTailRecursion,
39                             Mode mode,
40                             boolean backwardsCompatible) {
41         this.select = select;
42         this.useCurrentMode = useCurrentMode;
43         this.useTailRecursion = useTailRecursion;
44         this.mode = mode;
45         this.backwardsCompatible = backwardsCompatible;
46         adoptChildExpression(select);
47     }
48
49    /**
50      * Set the actual parameters on the call
51      */

52
53     public void setActualParameters(
54                         WithParam[] actualParams,
55                         WithParam[] tunnelParams ) {
56         this.actualParams = actualParams;
57         this.tunnelParams = tunnelParams;
58     }
59
60     /**
61     * Get the name of this instruction for diagnostic and tracing purposes
62     */

63
64     public int getInstructionNameCode() {
65         return StandardNames.XSL_APPLY_TEMPLATES;
66     }
67
68     /**
69      * Set additional trace properties appropriate to the kind of instruction. This
70      * implementation adds the mode attribute
71      */

72
73     public InstructionInfo getInstructionInfo() {
74         InstructionDetails details = (InstructionDetails)super.getInstructionInfo();
75         details.setProperty("mode", mode);
76         return details;
77     }
78
79     /**
80      * Simplify an expression. This performs any static optimization (by rewriting the expression
81      * as a different expression).
82      *
83      * @exception XPathException if an error is discovered during expression
84      * rewriting
85      * @return the simplified expression
86      */

87
88     public Expression simplify(StaticContext env) throws XPathException {
89         WithParam.simplify(actualParams, env);
90         WithParam.simplify(tunnelParams, env);
91         select = select.simplify(env);
92         return this;
93     }
94
95     public Expression typeCheck(StaticContext env, ItemType contextItemType) throws XPathException {
96         WithParam.typeCheck(actualParams, env, contextItemType);
97         WithParam.typeCheck(tunnelParams, env, contextItemType);
98         select = select.typeCheck(env, contextItemType);
99         adoptChildExpression(select);
100         if (select instanceof EmptySequence) {
101             return EmptySequence.getInstance();
102         }
103         return this;
104     }
105
106     public Expression optimize(Optimizer opt, StaticContext env, ItemType contextItemType) throws XPathException {
107         WithParam.optimize(opt, actualParams, env, contextItemType);
108         WithParam.optimize(opt, tunnelParams, env, contextItemType);
109         select = select.typeCheck(env, contextItemType); // More info available second time around
110
select = select.optimize(opt, env, contextItemType);
111         adoptChildExpression(select);
112         if (select instanceof EmptySequence) {
113             return EmptySequence.getInstance();
114         }
115         return this;
116     }
117
118     /**
119      * Determine whether this instruction creates new nodes.
120      * This implementation returns true (which is almost invariably the case, so it's not worth
121      * doing any further analysis to find out more precisely).
122      */

123
124     public final boolean createsNewNodes() {
125         return true;
126     }
127
128     public void process(XPathContext context) throws XPathException {
129         apply(context, false);
130     }
131
132     public TailCall processLeavingTail(XPathContext context) throws XPathException {
133         return apply(context, useTailRecursion);
134     }
135
136     private TailCall apply(XPathContext context, boolean returnTailCall) throws XPathException {
137         Mode thisMode = mode;
138         if (useCurrentMode) {
139             thisMode = context.getCurrentMode();
140         }
141
142         // handle parameters if any
143

144         ParameterSet params = assembleParams(context, actualParams);
145         ParameterSet tunnels = assembleTunnelParams(context, tunnelParams);
146
147         if (returnTailCall) {
148             XPathContextMajor c2 = context.newContext();
149             c2.setOrigin(this);
150             return new ApplyTemplatesPackage(
151                     ExpressionTool.lazyEvaluate(select, context, 1),
152                     thisMode, params, tunnels, c2, getLocationId());
153         }
154
155         // Get an iterator to iterate through the selected nodes in original order
156

157         SequenceIterator iter = select.iterate(context);
158
159         // Quick exit if the iterator is empty
160

161         if (iter instanceof EmptyIterator) {
162             return null;
163         }
164
165         // process the selected nodes now
166
XPathContextMajor c2 = context.newContext();
167         c2.setOrigin(this);
168         try {
169             TailCall tc = applyTemplates(iter, thisMode, params, tunnels, c2, backwardsCompatible, getLocationId());
170             while (tc != null) {
171                 tc = tc.processLeavingTail(c2);
172             }
173         } catch (StackOverflowError JavaDoc e) {
174             DynamicError err = new DynamicError(
175                     "Too many nested apply-templates calls. The stylesheet is probably looping.");
176             err.setErrorCode(SaxonErrorCode.SXLM0001);
177             err.setLocator(this);
178             err.setXPathContext(context);
179             throw err;
180         }
181         return null;
182
183     }
184
185     /**
186      * Process selected nodes using the handlers registered for a particular
187      * mode.
188      *
189      * @exception XPathException if any dynamic error occurs
190      * @param iterator an Iterator over the nodes to be processed, in the
191      * correct (sorted) order
192      * @param mode Identifies the processing mode. It should match the
193      * mode defined when the element handler was registered using
194      * setHandler with a mode parameter. Set this parameter to null to
195      * invoke the default mode.
196      * @param parameters A ParameterSet containing the parameters to
197      * the handler/template being invoked. Specify null if there are no
198      * parameters.
199      * @param tunnelParameters A ParameterSet containing the parameters to
200      * the handler/template being invoked. Specify null if there are no
201      * parameters.
202      * @param context A newly-created context object
203      * @param locationId
204      * @return a TailCall returned by the last template to be invoked, or null,
205      * indicating that there are no outstanding tail calls.
206      */

207
208     public static TailCall applyTemplates(SequenceIterator iterator,
209                                           Mode mode,
210                                           ParameterSet parameters,
211                                           ParameterSet tunnelParameters,
212                                           XPathContextMajor context,
213                                           boolean backwardsCompatible,
214                                           int locationId)
215                                 throws XPathException {
216         Controller controller = context.getController();
217         TailCall tc = null;
218
219         XPathContextMajor c2 = context;
220
221         // Iterate over this sequence
222

223         if (controller.isTracing()) {
224
225             c2.setCurrentIterator(iterator);
226             c2.setCurrentMode(mode);
227             while(true) {
228                 // process any tail calls returned from previous nodes
229
while (tc != null) {
230                     tc = tc.processLeavingTail(c2);
231                 }
232
233                 NodeInfo node = (NodeInfo)iterator.next();
234                         // We can assume it's a node - we did static type checking
235
if (node == null) break;
236
237                 // find the template rule for this node
238
Template eh = controller.getRuleManager().getTemplateRule(node, mode, c2);
239
240                 if (eh==null) { // Use the default action for the node
241
// No need to open a new stack frame!
242
defaultAction(node, parameters, tunnelParameters, c2, backwardsCompatible, locationId);
243
244                 } else {
245                     //if (tunnelParameters != null || eh.needsStackFrame()) {
246
TraceListener traceListener = controller.getTraceListener();
247                         c2.setLocalParameters(parameters);
248                         c2.setTunnelParameters(tunnelParameters);
249                         c2.openStackFrame(eh.getStackFrameMap());
250                         traceListener.startCurrentItem(node);
251                         tc = eh.processLeavingTail(c2);
252                         traceListener.endCurrentItem(node);
253                     //} else {
254
// TraceListener traceListener = controller.getTraceListener();
255
// traceListener.startCurrentItem(node);
256
// tc = eh.processLeavingTail(c2);
257
// traceListener.endCurrentItem(node);
258
//}
259
}
260             }
261
262         } else { // not tracing
263

264             c2.setCurrentIterator(iterator);
265             c2.setCurrentMode(mode);
266             while(true) {
267
268                 // process any tail calls returned from previous nodes
269
while (tc != null) {
270                     tc = tc.processLeavingTail(c2);
271                 }
272
273                 NodeInfo node = (NodeInfo)iterator.next();
274                         // We can assume it's a node - we did static type checking
275
if (node == null) break;
276
277                 // find the template rule for this node
278

279                 Template eh = controller.getRuleManager().getTemplateRule(node, mode, c2);
280
281                 if (eh==null) { // Use the default action for the node
282
// No need to open a new stack frame!
283
defaultAction(node, parameters, tunnelParameters, c2, backwardsCompatible, locationId);
284
285                 } else {
286                     //if (tunnelParameters != null || eh.needsStackFrame()) {
287
c2.openStackFrame(eh.getStackFrameMap());
288                         c2.setLocalParameters(parameters);
289                         c2.setTunnelParameters(tunnelParameters);
290                         tc = eh.processLeavingTail(c2);
291                     //} else {
292
// tc = eh.processLeavingTail(c2);
293
//}
294
}
295             }
296         }
297         // return the TailCall returned from the last node processed
298
return tc;
299     }
300
301     /**
302      * Perform the built-in template action for a given node.
303      *
304      * @param node the node to be processed
305      * @param parameters the parameters supplied to apply-templates
306      * @param tunnelParams the tunnel parameters to be passed through
307      * @param backwardsCompatible true if in 1.0 mode (currently makes no difference)
308      * @param locationId location of the instruction (apply-templates, apply-imports etc) that caused
309      * the built-in template to be invoked
310      * @exception XPathException if any dynamic error occurs
311      */

312
313     public static void defaultAction(NodeInfo node,
314                                      ParameterSet parameters,
315                                      ParameterSet tunnelParams,
316                                      XPathContext context,
317                                      boolean backwardsCompatible,
318                                      int locationId) throws XPathException {
319         switch(node.getNodeKind()) {
320             case Type.DOCUMENT:
321             case Type.ELEMENT:
322                 SequenceIterator iter = node.iterateAxis(Axis.CHILD);
323                 XPathContextMajor c2 = context.newContext();
324                 c2.setOrigin(builtInDetails);
325                 TailCall tc = applyTemplates(
326                         iter, context.getCurrentMode(), parameters, tunnelParams, c2, backwardsCompatible, locationId);
327                 while (tc != null) {
328                     tc = tc.processLeavingTail(c2);
329                 }
330                 return;
331             case Type.TEXT:
332                 // NOTE: I tried changing this to use the text node's copy() method, but
333
// performance was worse
334
case Type.ATTRIBUTE:
335                 context.getReceiver().characters(node.getStringValueCS(), locationId, 0);
336                 return;
337             case Type.COMMENT:
338             case Type.PROCESSING_INSTRUCTION:
339             case Type.NAMESPACE:
340                 // no action
341
return;
342         }
343     }
344
345     /**
346      * Instruction details for the built-in template
347      */

348
349     private static InstructionDetails builtInDetails = new InstructionDetails();
350     static {
351         builtInDetails.setConstructType(Location.BUILT_IN_TEMPLATE);
352     }
353
354     /**
355      * Get all the XPath expressions associated with this instruction
356      * (in XSLT terms, the expression present on attributes of the instruction,
357      * as distinct from the child instructions in a sequence construction)
358      */

359
360     public Iterator JavaDoc iterateSubExpressions() {
361         ArrayList JavaDoc list = new ArrayList JavaDoc(10);
362         list.add(select);
363         WithParam.getXPathExpressions(actualParams, list);
364         WithParam.getXPathExpressions(tunnelParams, list);
365         return list.iterator();
366     }
367
368     /**
369      * Handle promotion offers, that is, non-local tree rewrites.
370      * @param offer The type of rewrite being offered
371      * @throws XPathException
372      */

373
374     protected void promoteInst(PromotionOffer offer) throws XPathException {
375         select = doPromotion(select, offer);
376         WithParam.promoteParams(actualParams, offer);
377         WithParam.promoteParams(tunnelParams, offer);
378     }
379
380     /**
381      * Diagnostic print of expression structure. The expression is written to the System.err
382      * output stream
383      *
384      * @param level indentation level for this expression
385      * @param out
386      */

387
388     public void display(int level, NamePool pool, PrintStream JavaDoc out) {
389         out.println(ExpressionTool.indent(level) + "apply-templates " + "select=");
390         select.display(level+1, pool, out);
391     }
392
393     /**
394     * An ApplyTemplatesPackage is an object that encapsulates the sequence of nodes to be processed,
395     * the mode, the parameters to be supplied, and the execution context. This object can be returned as a tail
396     * call, so that the actual call is made from a lower point on the stack, allowing a tail-recursive
397     * template to execute in a finite stack size
398     */

399
400     private static class ApplyTemplatesPackage implements TailCall {
401
402         private ValueRepresentation selectedNodes;
403         private Mode mode;
404         private ParameterSet params;
405         private ParameterSet tunnelParams;
406         private XPathContextMajor evaluationContext;
407         private int locationId;
408
409         ApplyTemplatesPackage(ValueRepresentation selectedNodes,
410                                      Mode mode,
411                                      ParameterSet params,
412                                      ParameterSet tunnelParams,
413                                      XPathContextMajor context,
414                                      int locationId
415                                      ) {
416             this.selectedNodes = selectedNodes;
417             this.mode = mode;
418             this.params = params;
419             this.tunnelParams = tunnelParams;
420             this.evaluationContext = context;
421             this.locationId = locationId;
422         }
423
424         public TailCall processLeavingTail(XPathContext context) throws XPathException {
425             TailCall tc = applyTemplates(
426                     Value.getIterator(selectedNodes), mode, params, tunnelParams, evaluationContext, false, locationId);
427             return tc;
428         }
429     }
430
431 }
432
433 //
434
// The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
435
// you may not use this file except in compliance with the License. You may obtain a copy of the
436
// License at http://www.mozilla.org/MPL/
437
//
438
// Software distributed under the License is distributed on an "AS IS" basis,
439
// WITHOUT WARRANTY OF ANY KIND, either express or implied.
440
// See the License for the specific language governing rights and limitations under the License.
441
//
442
// The Original Code is: all this file.
443
//
444
// The Initial Developer of the Original Code is Michael H. Kay.
445
//
446
// Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
447
//
448
// Contributor(s): none.
449
//
450
Popular Tags