KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > net > sf > saxon > Controller


1 package net.sf.saxon;
2 import net.sf.saxon.event.*;
3 import net.sf.saxon.expr.XPathContext;
4 import net.sf.saxon.expr.XPathContextMajor;
5 import net.sf.saxon.functions.Component;
6 import net.sf.saxon.instruct.*;
7 import net.sf.saxon.om.*;
8 import net.sf.saxon.tinytree.TinyBuilder;
9 import net.sf.saxon.trace.*;
10 import net.sf.saxon.trans.*;
11 import net.sf.saxon.tree.TreeBuilder;
12 import net.sf.saxon.value.DateTimeValue;
13 import org.xml.sax.SAXParseException JavaDoc;
14
15 import javax.xml.transform.*;
16 import javax.xml.transform.dom.DOMSource JavaDoc;
17 import javax.xml.transform.stream.StreamResult JavaDoc;
18 import java.io.OutputStream JavaDoc;
19 import java.io.PrintStream JavaDoc;
20 import java.util.*;
21
22 /**
23  * The Controller is Saxon's implementation of the JAXP Transformer class, and represents
24  * an executing instance of a transformation or query. Multiple concurrent executions of
25  * the same transformation or query will use different Controller instances. This class is
26  * therefore not thread-safe.
27  * <p>
28  * The Controller is serially reusable, as required by JAXP: when one transformation or query
29  * is finished, it can be used to run another. However, there is no advantage in doing this
30  * rather than allocating a new Controller each time.
31  * <p>
32  * The Controller can also be used when running Java applications that use neither XSLT nor
33  * XQuery. A dummy Controller is created when running free-standing XPath expressions.
34  * <p>
35  * The Controller holds those parts of the dynamic context that do not vary during the course
36  * of a transformation or query, or that do not change once their value has been computed.
37  * This also includes those parts of the static context that are required at run-time.
38  * <p>
39  * Wherever possible XSLT applications should use the JAXP Transformer class directly,
40  * rather than relying on Saxon-specific methods in the Controller. However, some
41  * features are currently available only through this class. This applies especially
42  * to new features specific to XSLT 2.0, since the JAXP interface still supports
43  * only XSLT 1.0. Such methods may be superseded in the future by JAXP methods.
44  * <p>
45  * Many methods on the Controller are designed for internal use and should not be
46  * considered stable. From release 8.4 onwards, those methods that are considered sufficiently
47  * stable to constitute path of the Saxon public API are labelled with the JavaDoc tag "since":
48  * the value indicates the release at which the method was added to the public API.
49  *
50  * @author Michael H. Kay
51  * @since 8.4
52  */

53
54 public class Controller extends Transformer implements InstructionInfoProvider {
55
56     private Configuration config;
57     private DocumentInfo principalSourceDocument;
58     private Bindery bindery; // holds values of global and local variables
59
private NamePool namePool;
60     private Emitter messageEmitter;
61     private RuleManager ruleManager;
62     private Properties outputProperties;
63     private GlobalParameterSet parameters;
64     private PreparedStylesheet preparedStylesheet;
65     private TraceListener traceListener;
66     private boolean tracingPaused;
67     private URIResolver standardURIResolver;
68     private URIResolver userURIResolver;
69     private Result JavaDoc principalResult;
70     private String JavaDoc principalResultURI;
71     private OutputURIResolver outputURIResolver;
72     private ErrorListener errorListener;
73     private Executable executable;
74     private int treeModel = Builder.TINY_TREE;
75     private Template initialTemplate = null;
76     private HashSet allOutputDestinations;
77     private DocumentPool sourceDocumentPool;
78     private HashMap userDataTable;
79     private DateTimeValue currentDateTime;
80     private boolean dateTimePreset = false;
81     private int initialMode = -1;
82     private NodeInfo lastRememberedNode = null;
83     private int lastRememberedNumber = -1;
84     private ClassLoader JavaDoc classLoader;
85 // private int nextLocalDocumentNumber = -1;
86

87     /**
88      * Create a Controller and initialise variables. Constructor is protected,
89      * the Controller should be created using newTransformer() in the PreparedStylesheet
90      * class.
91      *
92      * @param config The Configuration used by this Controller
93      */

94
95     public Controller(Configuration config) {
96         this.config = config;
97         // create a dummy executable
98
executable = new Executable();
99         executable.setConfiguration(config);
100         executable.setHostLanguage(config.getHostLanguage());
101         sourceDocumentPool = new DocumentPool();
102         reset();
103     }
104
105     /**
106      * Create a Controller and initialise variables. Constructor is protected,
107      * the Controller should be created using newTransformer() in the PreparedStylesheet
108      * class.
109      *
110      * @param config The Configuration used by this Controller
111      * @param executable The executable used by this Controller
112      */

113
114     public Controller(Configuration config, Executable executable) {
115         this.config = config;
116         this.executable = executable;
117         sourceDocumentPool = new DocumentPool();
118         reset();
119     }
120
121     /**
122      * <p>Reset this <code>Transformer</code> to its original configuration.</p>
123      * <p/>
124      * <p><code>Transformer</code> is reset to the same state as when it was created with
125      * {@link javax.xml.transform.TransformerFactory#newTransformer()},
126      * {@link javax.xml.transform.TransformerFactory#newTransformer(javax.xml.transform.Source source)} or
127      * {@link javax.xml.transform.Templates#newTransformer()}.
128      * <code>reset()</code> is designed to allow the reuse of existing <code>Transformer</code>s
129      * thus saving resources associated with the creation of new <code>Transformer</code>s.</p>
130      * <p>
131      * <i>The above is from the JAXP specification. With Saxon, it's unlikely that reusing a Transformer will
132      * give any performance benefits over creating a new one. The one case where it might be beneficial is
133      * to reuse the document pool (the set of documents that have been loaded using the doc() or document()
134      * functions). Therefore, this method does not clear the document pool. If you want to clear the document
135      * pool, call the method {@link #clearDocumentPool} as well.</i>
136      * <p/>
137      * <p>The reset <code>Transformer</code> is not guaranteed to have the same {@link javax.xml.transform.URIResolver}
138      * or {@link javax.xml.transform.ErrorListener} <code>Object</code>s, e.g. {@link Object#equals(Object obj)}.
139      * It is guaranteed to have a functionally equal <code>URIResolver</code>
140      * and <code>ErrorListener</code>.</p>
141      *
142      * @since 1.5
143      */

144
145     public void reset() {
146         bindery = new Bindery();
147         namePool = NamePool.getDefaultNamePool();
148         standardURIResolver = config.getSystemURIResolver();
149         userURIResolver = config.getURIResolver();
150
151         outputURIResolver = config.getOutputURIResolver();
152         errorListener = config.getErrorListener();
153         if (errorListener instanceof StandardErrorListener) {
154             // if using a standard error listener, make a fresh one
155
// for each transformation, because it is stateful - and also because the
156
// host language is now known (a Configuration can serve multiple host languages)
157
PrintStream JavaDoc ps = ((StandardErrorListener)errorListener).getErrorOutput();
158             errorListener = ((StandardErrorListener)errorListener).makeAnother(executable.getHostLanguage());
159             ((StandardErrorListener)errorListener).setErrorOutput(ps);
160             ((StandardErrorListener)errorListener).setRecoveryPolicy(
161                     config.getRecoveryPolicy());
162         }
163
164         userDataTable = new HashMap(20);
165
166         traceListener = null;
167         tracingPaused = false;
168         TraceListener tracer = config.getTraceListener();
169         if (tracer!=null) {
170             addTraceListener(tracer);
171         }
172
173         setTreeModel(config.getTreeModel());
174         principalSourceDocument = null;
175         messageEmitter = null;
176         outputProperties = null;
177         parameters = null;
178
179         principalResult = null;
180         principalResultURI = null;
181         initialTemplate = null;
182         allOutputDestinations = null;
183         currentDateTime = null;
184         dateTimePreset = false;
185         initialMode = -1;
186         lastRememberedNode = null;
187         lastRememberedNumber = -1;
188         classLoader = null;
189
190     }
191
192     /**
193      * Get the Configuration associated with this Controller. The Configuration holds
194      * settings that potentially apply globally to many different queries and transformations.
195      * @return the Configuration object
196      * @since 8.4
197      */

198     public Configuration getConfiguration() {
199         return config;
200     }
201
202     /**
203      * Set the initial mode for the transformation.
204      * <p>
205      * XSLT 2.0 allows a transformation to be started in a mode other than the default mode.
206      * The transformation then starts by looking for the template rule in this mode that best
207      * matches the initial context node.
208      * <p>
209      * This method may eventually be superseded by a standard JAXP method.
210      *
211      * @param expandedModeName the name of the initial mode. The mode is
212      * supplied as an expanded QName, that is "localname" if there is no
213      * namespace, or "{uri}localname" otherwise
214      * @since 8.4
215      */

216
217     public void setInitialMode(String JavaDoc expandedModeName) {
218         if (expandedModeName==null) return;
219         if (expandedModeName.equals("")) return;
220         initialMode = namePool.allocateClarkName(expandedModeName);
221     }
222
223     ////////////////////////////////////////////////////////////////////////////////
224
// Methods for managing output destinations and formatting
225
////////////////////////////////////////////////////////////////////////////////
226

227     /**
228      * Set the output properties for the transformation. These
229      * properties will override properties set in the templates
230      * with xsl:output.
231      * <p>
232      * As well as the properties defined in the JAXP OutputKeys class,
233      * Saxon defines an additional set of properties in {@link SaxonOutputKeys}.
234      * These fall into two categories: Constants representing serialization
235      * properties defined in XSLT 2.0 (which are not yet supported by JAXP),
236      * and constants supporting Saxon extensions to the set of serialization
237      * properties.
238      *
239      * @param properties the output properties to be used for the
240      * transformation. If the value is null, the properties are reset to
241      * be the properties of the Templates object (that is, for XSLT 2.0,
242      * the properties set in the unnamed xsl:output object).
243      * @see SaxonOutputKeys
244      * @since 8.4
245      */

246
247     public void setOutputProperties(Properties properties) {
248         if (properties == null) {
249             outputProperties = null;
250         } else {
251             Enumeration keys = properties.propertyNames();
252             while(keys.hasMoreElements()) {
253                 String JavaDoc key = (String JavaDoc)keys.nextElement();
254                 setOutputProperty(key, properties.getProperty(key));
255             }
256         }
257     }
258
259     /**
260      * Get the output properties for the transformation.
261      * <p>
262      * As well as the properties defined in the JAXP OutputKeys class,
263      * Saxon defines an additional set of properties in {@link SaxonOutputKeys}.
264      * These fall into two categories: Constants representing serialization
265      * properties defined in XSLT 2.0 (which are not yet supported by JAXP),
266      * and constants supporting Saxon extensions to the set of serialization
267      * properties.
268      *
269      * @return the output properties being used for the transformation,
270      * including properties defined in the stylesheet for the unnamed
271      * output format
272      * @see SaxonOutputKeys
273      * @since 8.4
274      */

275
276     public Properties getOutputProperties() {
277         if (outputProperties == null) {
278             if (executable==null) {
279                 return new Properties();
280             } else {
281                 outputProperties = executable.getDefaultOutputProperties();
282             }
283         }
284
285         // Make a copy, so that modifications to the returned properties have no effect
286

287         Properties newProps = new Properties();
288         Enumeration keys = outputProperties.propertyNames();
289         while(keys.hasMoreElements()) {
290             String JavaDoc key = (String JavaDoc)keys.nextElement();
291             newProps.put(key, outputProperties.getProperty(key));
292         }
293         return newProps;
294     }
295
296     /**
297      * Set an output property for the transformation.
298      * <p>
299      * As well as the properties defined in the JAXP OutputKeys class,
300      * Saxon defines an additional set of properties in {@link SaxonOutputKeys}.
301      * These fall into two categories: Constants representing serialization
302      * properties defined in XSLT 2.0 (which are not yet supported by JAXP),
303      * and constants supporting Saxon extensions to the set of serialization
304      * properties.
305      *
306      * @param name the name of the property
307      * @param value the value of the property
308      * @see SaxonOutputKeys
309      * @since 8.4
310      */

311
312     public void setOutputProperty(String JavaDoc name, String JavaDoc value) {
313         if (outputProperties == null) {
314             outputProperties = getOutputProperties();
315         }
316         try {
317             SaxonOutputKeys.checkOutputProperty(name, value);
318         } catch (DynamicError err) {
319             throw new IllegalArgumentException JavaDoc(err.getMessage());
320         }
321         outputProperties.put(name, value);
322     }
323
324     /**
325      * Get the value of an output property.
326      * <p>
327      * As well as the properties defined in the JAXP OutputKeys class,
328      * Saxon defines an additional set of properties in {@link SaxonOutputKeys}.
329      * These fall into two categories: Constants representing serialization
330      * properties defined in XSLT 2.0 (which are not yet supported by JAXP),
331      * and constants supporting Saxon extensions to the set of serialization
332      * properties.
333      *
334      * @param name the name of the requested property
335      * @return the value of the requested property
336      * @see SaxonOutputKeys
337      * @since 8.4
338      */

339
340     public String JavaDoc getOutputProperty(String JavaDoc name) {
341          try {
342             SaxonOutputKeys.checkOutputProperty(name, null);
343         } catch (DynamicError err) {
344             throw new IllegalArgumentException JavaDoc(err.getMessage());
345         }
346         if (outputProperties == null) {
347             if (executable==null) {
348                 return null;
349             } else {
350                 outputProperties = executable.getDefaultOutputProperties();
351             }
352         }
353         return outputProperties.getProperty(name);
354     }
355
356     /**
357      * Set the base output URI.
358      * This defaults to the system ID of the principal Result object, but
359      * a different value can be set for use where there is no principal result.
360      * The command line interface sets this to the current working directory.
361      * <p>
362      * The concept of the base output URI is new in XSLT 2.0: it defines the
363      * base URI for resolving relative URIs in the <code>href</code> attribute
364      * of the <code>xsl:result-document</code> instruction. This method may be
365      * superseded by a standard JAXP method when JAXP is updated to support XSLT 2.0.
366      *
367      * @param uri the base output URI
368      * @since 8.4
369      */

370
371     public void setBaseOutputURI(String JavaDoc uri) {
372         principalResultURI = uri;
373     }
374
375     /**
376      * Get the base output URI.
377      * This defaults to the system ID of the principal Result object, but
378      * a different value can be set for use where there is no principal result.
379      * The command line interface sets this to the current working directory.
380      * <p>
381      * The concept of the base output URI is new in XSLT 2.0: it defines the
382      * base URI for resolving relative URIs in the <code>href</code> attribute
383      * of the <code>xsl:result-document</code> instruction. This method may be
384      * superseded by a standard JAXP method when JAXP is updated to support XSLT 2.0.
385      *
386      * @return the base output URI
387      * @since 8.4
388      */

389
390     public String JavaDoc getBaseOutputURI() {
391         return principalResultURI;
392     }
393
394     /**
395      * Get the principal result destination.
396      * <p>
397      * This method is intended for internal use only.
398      */

399
400     public Result JavaDoc getPrincipalResult() {
401         return principalResult;
402     }
403
404     /**
405      * Check that an output destination has not been used before.
406      * <p>
407      * This method is intended for internal use only.
408      */

409
410     public boolean checkUniqueOutputDestination(String JavaDoc uri) {
411         if (allOutputDestinations == null) {
412             allOutputDestinations = new HashSet(20);
413         }
414         if (allOutputDestinations.contains(uri)) {
415             return false;
416         }
417         allOutputDestinations.add(uri);
418         return true;
419     }
420
421     ///////////////////////////////////////////////////////////////////////////////
422

423     /**
424      * Set the initial named template to be used as the entry point.
425      * <p>
426      * XSLT 2.0 allows a transformation to start by executing a named template, rather than
427      * by matching an initial context node in a source document. This method may eventually
428      * be superseded by a standard JAXP method once JAXP supports XSLT 2.0.
429      * <p>
430      * Although the Saxon command line interface does not allow both a source document and
431      * an initial template to be specified, this API has no such restriction.
432      * <p>
433      * Note that any parameters supplied using {@link #setParameter} are used as the values
434      * of global stylesheet parameters. There is no way to supply values for local parameters
435      * of the initial template.
436      *
437      * @param expandedName The expanded name of the template in {uri}local format
438      * @throws XPathException if there is no named template with this name
439      * @since 8.4
440      */

441
442     public void setInitialTemplate(String JavaDoc expandedName) throws XPathException {
443         int fingerprint = namePool.allocateClarkName(expandedName);
444         Template t = getExecutable().getNamedTemplate(fingerprint);
445         if (t == null) {
446             DynamicError err = new DynamicError("There is no named template with expanded name "
447                                            + expandedName);
448             err.setErrorCode("XTDE0040");
449             throw err;
450         } else {
451             initialTemplate = t;
452         }
453     }
454
455     ///////////////////////////////////////////////////////////////////////////////
456

457     /**
458      * Make a PipelineConfiguration based on the properties of this Controller.
459      * <p>
460      * This interface is intended primarily for internal use, although it may be necessary
461      * for applications to call it directly for use in conjunction with the experimental pull
462      * API.
463      */

464
465     public PipelineConfiguration makePipelineConfiguration() {
466         PipelineConfiguration pipe = new PipelineConfiguration();
467         pipe.setConfiguration(getConfiguration());
468         pipe.setErrorListener(getErrorListener());
469         pipe.setURIResolver(userURIResolver==null ? standardURIResolver : userURIResolver);
470         pipe.setController(this);
471         if (getExecutable() != null) {
472             // can be null for an IdentityTransformer
473
pipe.setLocationProvider(getExecutable().getLocationMap());
474         }
475         return pipe;
476     }
477
478     /**
479      * Make an Emitter to be used for xsl:message output.
480      * <p>
481      * This method is intended for internal use only.
482      *
483      * @exception XPathException if any dynamic error occurs; in
484      * particular, if the registered MessageEmitter class is not an
485      * Emitter
486      * @return The newly constructed message Emitter
487      */

488
489     public Emitter makeMessageEmitter() throws XPathException {
490         String JavaDoc emitterClass = config.getMessageEmitterClass();
491
492         Object JavaDoc emitter = config.getInstance(emitterClass, getClassLoader());
493         if (!(emitter instanceof Emitter)) {
494             throw new DynamicError(emitterClass + " is not an Emitter");
495         }
496         setMessageEmitter((Emitter)emitter);
497         return messageEmitter;
498     }
499
500     /**
501      * Set the Emitter to be used for xsl:message output.
502      * <p>
503      * Recent versions of the JAXP interface specify that by default the
504      * output of xsl:message is sent to the registered ErrorListener. Saxon
505      * does not yet implement this convention. Instead, the output is sent
506      * to a default message emitter, which is a slightly customised implementation
507      * of the standard Saxon Emitter interface.
508      * <p>
509      * This interface can be used to change the way in which Saxon outputs
510      * xsl:message output.
511      * <p>
512      * It is not necessary to use this interface in order to change the destination
513      * to which messages are written: that can be achieved by obtaining the standard
514      * message emitter and calling its {@link Emitter#setWriter} method.
515      * <p>
516      * This method is intended for use by advanced applications. The Emitter interface
517      * itself is not part of the stable Saxon public API.
518      *
519      * @param emitter The emitter to receive xsl:message output.
520      */

521
522     public void setMessageEmitter(Emitter emitter) {
523         messageEmitter = emitter;
524         messageEmitter.setPipelineConfiguration(makePipelineConfiguration());
525     }
526
527     /**
528      * Get the Emitter used for xsl:message output. This returns the emitter
529      * previously supplied to the {@link #setMessageEmitter} method, or the
530      * default message emitter otherwise.
531      *
532      * @return the Emitter being used for xsl:message output
533      */

534
535     public Emitter getMessageEmitter() {
536        return messageEmitter;
537     }
538
539     /**
540      * Make a CharacterMapExpander to handle the character map definitions in the serialization
541      * properties.
542      * <p>
543      * This method is intended for internal use only.
544      *
545      * @param useMaps the expanded use-character-maps property: a space-separated list of names
546      * of character maps to be used, each one expressed as an expanded-QName in Clark notation
547      * (that is, {uri}local-name).
548      * @return a CharacterMapExpander if one is required, or null if not (for example, if the
549      * useMaps argument is an empty string).
550      * @throws XPathException if a name in the useMaps property cannot be resolved to a declared
551      * character map.
552      */

553
554     public CharacterMapExpander makeCharacterMapExpander(String JavaDoc useMaps) throws XPathException {
555         CharacterMapExpander characterMapExpander = null;
556         HashMap characterMapIndex = getExecutable().getCharacterMapIndex();
557         if (useMaps != null && characterMapIndex != null) {
558             List characterMaps = new ArrayList(5);
559             StringTokenizer st = new StringTokenizer(useMaps);
560             while (st.hasMoreTokens()) {
561                 String JavaDoc expandedName = st.nextToken();
562                 int f = namePool.getFingerprintForExpandedName(expandedName);
563                 HashMap map = (HashMap)characterMapIndex.get(new Integer JavaDoc(f));
564                 if (map==null) {
565                     throw new DynamicError("Character map '" + expandedName + "' has not been defined");
566                 }
567                 characterMaps.add(map);
568             }
569             if (characterMaps.size() > 0) {
570                 characterMapExpander = new CharacterMapExpander();
571                 characterMapExpander.setCharacterMaps(characterMaps);
572             }
573         }
574         return characterMapExpander;
575     }
576
577     /**
578      * Get the policy for handling recoverable errors.
579      * <p>
580      * This method is intended for internal use
581      *
582      * @return the current policy. This is obtained from the error listener; if the error listener is
583      * not a StandardErrorListener, the value RECOVER_WITH_WARNINGS is returned.
584      */

585
586     public int getRecoveryPolicy() {
587         if (errorListener instanceof StandardErrorListener) {
588             return ((StandardErrorListener)errorListener).getRecoveryPolicy();
589         } else {
590             return Configuration.RECOVER_WITH_WARNINGS;
591         }
592     }
593
594     /**
595      * Set the error listener.
596      *
597      * @param listener the ErrorListener to be used
598      */

599
600     public void setErrorListener(ErrorListener listener) {
601         errorListener = listener;
602     }
603
604     /**
605      * Get the error listener.
606      *
607      * @return the ErrorListener in use
608      */

609
610     public ErrorListener getErrorListener() {
611         return errorListener;
612     }
613
614     /**
615      * Report a recoverable error. This is an XSLT concept: by default, such an error results in a warning
616      * message, and processing continues. In XQuery, however, there are no recoverable errors so a fatal
617      * error is reported.
618      * <p>
619      * This method is intended for internal use only.
620      *
621      * @param err An exception holding information about the error
622      * @exception DynamicError if the error listener decides not to
623      * recover from the error
624      */

625
626     public void recoverableError(XPathException err) throws DynamicError {
627         try {
628             if (executable.getHostLanguage() == Configuration.XQUERY) {
629                 errorListener.fatalError(err);
630                 throw err;
631             } else {
632                 errorListener.error(err);
633             }
634         } catch (TransformerException e) {
635             throw DynamicError.makeDynamicError(e);
636         }
637     }
638
639     /////////////////////////////////////////////////////////////////////////////////////////
640
// Methods for managing the various runtime control objects
641
/////////////////////////////////////////////////////////////////////////////////////////
642

643
644     /**
645      * Get the Executable object.
646      * <p>
647      * This method is intended for internal use only.
648      *
649      * @return the Executable (which represents the compiled stylesheet)
650      */

651
652     public Executable getExecutable() {
653         return executable;
654     }
655
656     /**
657      * Get the document pool. This is used only for source documents, not for stylesheet modules.
658      * <p>
659      * This method is intended for internal use only.
660      *
661      * @return the source document pool
662      */

663
664     public DocumentPool getDocumentPool() {
665         return sourceDocumentPool;
666     }
667
668     /**
669      * Clear the document pool.
670      * This is sometimes useful when re-using the same Transformer
671      * for a sequence of transformations, but it isn't done automatically, because when
672      * the transformations use common look-up documents, the caching is beneficial.
673      */

674
675     public void clearDocumentPool() {
676         sourceDocumentPool = new DocumentPool();
677     }
678
679     /**
680      * Set the principal source document (used for evaluating global variables).
681      * When a transformation is invoked using the {@link #transform} method, the
682      * principal source document is set automatically. This method is useful in XQuery,
683      * to define an initial context node for evaluating global variables, and also
684      * in XSLT 2.0, when the transformation is started by invoking a named template.
685      *
686      * @param doc The principal source document
687      * @since 8.4
688      */

689
690     public void setPrincipalSourceDocument(DocumentInfo doc) {
691         principalSourceDocument = doc;
692     }
693
694     /**
695      * Get the current bindery.
696      * <p>
697      * This method is intended for internal use only.
698      *
699      * @return the Bindery (in which values of all variables are held)
700      */

701
702     public Bindery getBindery() {
703         return bindery;
704     }
705
706     /**
707      * Get the principal source document. This returns the document
708      * previously supplied to the {@link #setPrincipalSourceDocument} method, or the
709      * principal source document set implicitly using methods such as {@link #transform}.
710      * @return the principal source document
711      * @since 8.4
712      */

713
714     public DocumentInfo getPrincipalSourceDocument() {
715         return principalSourceDocument;
716     }
717
718     /**
719      * Set an object that will be used to resolve URIs used in
720      * document(), etc.
721      *
722      * @param resolver An object that implements the URIResolver interface, or
723      * null.
724      */

725
726     public void setURIResolver(URIResolver resolver) {
727         userURIResolver = resolver;
728     }
729
730     /**
731      * Get the URI resolver.
732      *
733      * <p><i>This method changed in Saxon 8.5, to conform to the JAXP specification. If there
734      * is no user-specified URIResolver, it now returns null; previously it returned the system
735      * default URIResolver.</i></p>
736      *
737      * @return the user-supplied URI resolver if there is one, or null otherwise.
738      */

739
740     public URIResolver getURIResolver() {
741         return userURIResolver;
742     }
743
744     /**
745      * Get the fallback URI resolver. This is the URIResolver that Saxon uses when
746      * the user-supplied URI resolver returns null.
747      * <p>
748      * This method is intended for internal use only.
749      *
750      * @return the the system-defined URIResolver
751      */

752
753     public URIResolver getStandardURIResolver() {
754         return standardURIResolver;
755     }
756
757      /**
758      * Set the URI resolver for secondary output documents.
759       * <p>
760       * XSLT 2.0 introduces the <code>xsl:result-document</code instruction,
761       * allowing a transformation to have multiple result documents. JAXP does
762       * not yet support this capability. This method allows an OutputURIResolver
763       * to be specified that takes responsibility for deciding the destination
764       * (and, if it wishes, the serialization properties) of secondary output files.
765       * <p>
766       * This method may eventually be superseded by a standard JAXP method.
767      *
768      * @param resolver An object that implements the OutputURIResolver
769      * interface, or null.
770       * @since 8.4
771      */

772
773     public void setOutputURIResolver(OutputURIResolver resolver) {
774         if (resolver==null) {
775             outputURIResolver = StandardOutputResolver.getInstance();
776         } else {
777             outputURIResolver = resolver;
778         }
779     }
780
781     /**
782      * Get the output URI resolver.
783      *
784      * @return the user-supplied URI resolver if there is one, or the
785      * system-defined one otherwise.
786      * @see #setOutputURIResolver
787      * @since 8.4
788      */

789
790     public OutputURIResolver getOutputURIResolver() {
791         return outputURIResolver;
792     }
793
794     /**
795      * Get the KeyManager.
796      * <p>
797      * This method is intended for internal use only.
798      *
799      * @return the KeyManager, which holds details of all key declarations
800      */

801
802     public KeyManager getKeyManager() {
803         return executable.getKeyManager();
804     }
805
806     /**
807      * Get the name pool in use. The name pool is responsible for mapping QNames used in source
808      * documents and compiled stylesheets and queries into numeric codes. All source documents
809      * used by a given transformation or query must use the same name pool as the compiled stylesheet
810      * or query.
811      *
812      * @return the name pool in use
813      * @since 8.4
814      */

815
816     public NamePool getNamePool() {
817         return namePool;
818     }
819
820     /**
821      * Set the tree data model to use. This affects all source documents subsequently constructed using a
822      * Builder obtained from this Controller. This includes a document built from a StreamSource or
823      * SAXSource supplied as a parameter to the {@link #transform} method.
824      *
825      * @param model the required tree model: {@link Builder#STANDARD_TREE} or
826      * {@link Builder#TINY_TREE}
827      * @see net.sf.saxon.event.Builder
828      * @since 8.4
829      */

830
831     public void setTreeModel(int model) {
832         treeModel = model;
833     }
834
835     /**
836      * Make a builder for the selected tree model.
837      *
838      * @return an instance of the Builder for the chosen tree model
839      * @since 8.4
840      */

841
842     public Builder makeBuilder() {
843         Builder b;
844         if (treeModel==Builder.TINY_TREE) {
845             b = new TinyBuilder();
846         } else {
847             b = new TreeBuilder();
848         }
849         b.setTiming(config.isTiming());
850         b.setLineNumbering(config.isLineNumbering());
851         b.setPipelineConfiguration(makePipelineConfiguration());
852         return b;
853     }
854
855     /**
856      * Make a Stripper configured to implement the whitespace stripping rules.
857      * In the case of XSLT the whitespace stripping rules are normally defined
858      * by <code>xsl:strip-space</code> and <code>xsl:preserve-space</code elements
859      * in the stylesheet. Alternatively, stripping of all whitespace text nodes
860      * may be defined at the level of the Configuration, using the method
861      * {@link Configuration#setStripsAllWhiteSpace(boolean)}.
862      *
863      * @param b the Receiver to which the events filtered by this stripper are
864      * to be sent (often a Builder). May be null if the stripper is not being used for filtering
865      * into a Builder or other Receiver.
866      * @return the required Stripper. A Stripper may be used in two ways. It acts as
867      * a filter applied to an event stream, that can be used to remove the events
868      * representing whitespace text nodes before they reach a Builder. Alternatively,
869      * it can be used to define a view of an existing tree in which the whitespace
870      * text nodes are dynamically skipped while navigating the XPath axes.
871      * @since 8.4 - Generalized in 8.5 to accept any Receiver as an argument
872      */

873
874     public Stripper makeStripper(Receiver b) {
875         if (config.isStripsAllWhiteSpace()) {
876             if (b==null) {
877                 return AllElementStripper.getInstance();
878             } else {
879                 Stripper s = new AllElementStripper();
880                 s.setUnderlyingReceiver(b);
881                 return s;
882             }
883         }
884         Stripper stripper;
885         if (executable==null) {
886             stripper = new Stripper(new Mode(Mode.STRIPPER_MODE));
887         } else {
888             stripper = executable.newStripper();
889         }
890         stripper.setPipelineConfiguration(makePipelineConfiguration());
891         //stripper.setController(this);
892
if (b != null) {
893             stripper.setUnderlyingReceiver(b);
894         }
895
896         return stripper;
897     }
898
899     /**
900      * Add a document to the document pool.
901      * <p>
902      * This method is intended for internal use only.
903      *
904      * @param doc the root node of the document to be added
905      * @param systemId thesystem ID of this document
906      */

907     public void registerDocument(DocumentInfo doc, String JavaDoc systemId) {
908         sourceDocumentPool.add(doc, systemId);
909         //int nr = config.getDocumentNumberAllocator().allocateDocumentNumber();
910
}
911
912     ////////////////////////////////////////////////////////////////////////////////
913
// Methods for registering and retrieving handlers for template rules
914
////////////////////////////////////////////////////////////////////////////////
915

916     /**
917      * Set the RuleManager, used to manage template rules for each mode.
918      * <p>
919      * This method is intended for internal use only.
920      *
921      * @param r the Rule Manager
922      */

923     public void setRuleManager(RuleManager r) {
924         ruleManager = r;
925     }
926
927     /**
928      * Get the Rule Manager.
929      * <p>
930      * This method is intended for internal use only.
931      *
932      * @return the Rule Manager, used to hold details of template rules for
933      * all modes
934      */

935     public RuleManager getRuleManager() {
936         return ruleManager;
937     }
938
939     /////////////////////////////////////////////////////////////////////////
940
// Methods for tracing
941
/////////////////////////////////////////////////////////////////////////
942

943     /**
944      * Get the TraceListener. By default, there is no TraceListener, and this
945      * method returns null. A TraceListener may be added using the method
946      * {@link #addTraceListener}. If more than one TraceListener has been added,
947      * this method will return a composite TraceListener. Because this form
948      * this takes is implementation-dependent, this method is not part of the
949      * stable Saxon public API.
950      *
951      * @return the TraceListener used for XSLT or XQuery instruction tracing
952      */

953     public TraceListener getTraceListener() { // e.g.
954
return traceListener;
955     }
956
957     /**
958      * Test whether instruction execution is being traced. This will be true
959      * if (a) at least one TraceListener has been registered using the
960      * {@link #addTraceListener} method, and (b) tracing has not been temporarily
961      * paused using the {@link #pauseTracing} method.
962      *
963      * @return true if tracing is active, false otherwise
964      * @since 8.4
965      */

966
967     public final boolean isTracing() { // e.g.
968
return traceListener != null && !tracingPaused;
969     }
970
971     /**
972      * Pause or resume tracing. While tracing is paused, trace events are not sent to any
973      * of the registered TraceListeners.
974      *
975      * @param pause true if tracing is to pause; false if it is to resume
976      * @since 8.4
977      */

978     public final void pauseTracing(boolean pause) {
979         tracingPaused = pause;
980     }
981
982     /**
983      * Adds the specified trace listener to receive trace events from
984      * this instance. Note that although TraceListeners can be added
985      * or removed dynamically, this has no effect unless the stylesheet
986      * or query has been compiled with tracing enabled. This is achieved
987      * by calling {@link Configuration#setTraceListener} or by setting
988      * the attribute {@link FeatureKeys#TRACE_LISTENER} on the
989      * TransformerFactory. Conversely, if this property has been set in the
990      * Configuration or TransformerFactory, the TraceListener will automatically
991      * be added to every Controller that uses that Configuration.
992      *
993      * @param trace the trace listener.
994      * @since 8.4
995      */

996
997     public void addTraceListener(TraceListener trace) { // e.g.
998
traceListener = TraceEventMulticaster.add(traceListener, trace);
999     }
1000
1001    /**
1002     * Removes the specified trace listener so that the listener will no longer
1003     * receive trace events.
1004     *
1005     * @param trace the trace listener.
1006     * @since 8.4
1007     */

1008
1009    public void removeTraceListener(TraceListener trace) { // e.g.
1010
traceListener = TraceEventMulticaster.remove(traceListener, trace);
1011    }
1012
1013    /**
1014     * Associate this Controller with a compiled stylesheet.
1015     * <p>
1016     * This method is intended for internal use only.
1017     *
1018     * @param sheet the compiled stylesheet
1019     */

1020
1021    public void setPreparedStylesheet(PreparedStylesheet sheet) {
1022        preparedStylesheet = sheet;
1023        executable = sheet.getExecutable();
1024        //setOutputProperties(sheet.getOutputProperties());
1025
// above line deleted for bug 490964 - may have side-effects
1026
}
1027
1028    /**
1029     * Associate this Controller with an Executable. This method is used by the XQuery
1030     * processor. The Executable object is overkill in this case - the only thing it
1031     * currently holds are copies of the collation table.
1032     * <p>
1033     * This method is intended for internal use only
1034     * @param exec the Executable
1035     */

1036
1037    public void setExecutable(Executable exec) {
1038        executable = exec;
1039    }
1040
1041    /**
1042     * Initialize the controller ready for a new transformation. This method should not normally be called by
1043     * users (it is done automatically when transform() is invoked). However, it is available as a low-level API
1044     * especially for use with XQuery.
1045     */

1046
1047    public void initializeController() throws XPathException {
1048        setRuleManager(executable.getRuleManager());
1049        //setDecimalFormatManager(executable.getDecimalFormatManager());
1050

1051        if (traceListener!=null) {
1052            traceListener.open();
1053        }
1054
1055        // get a new bindery, to clear out any variables from previous runs
1056

1057        bindery = new Bindery();
1058        executable.initialiseBindery(bindery);
1059
1060        // create an initial stack frame, used for evaluating standalone expressions,
1061
// e.g. expressions within the filter of a match pattern. This stack frame
1062
// never gets closed, but no one will notice.
1063

1064        //bindery.openStackFrame();
1065

1066        // if parameters were supplied, set them up
1067

1068        defineGlobalParameters(bindery);
1069    }
1070
1071    /**
1072     * Define the global parameters of the transformation or query.
1073     * <p>
1074     * This method is intended for internal use only
1075     * @param bindery The Bindery, which holds values of global variables and parameters
1076     */

1077
1078    public void defineGlobalParameters(Bindery bindery) throws XPathException {
1079        executable.checkAllRequiredParamsArePresent(parameters);
1080        bindery.defineGlobalParameters(parameters);
1081    }
1082
1083
1084
1085    /////////////////////////////////////////////////////////////////////////
1086
// Allow user data to be associated with nodes on a tree
1087
/////////////////////////////////////////////////////////////////////////
1088

1089    /**
1090     * Get user data associated with a key. To retrieve user data, two objects are required:
1091     * an arbitrary object that may be regarded as the container of the data (originally, and
1092     * typically still, a node in a tree), and a name. The name serves to distingush data objects
1093     * associated with the same node by different client applications.
1094     * <p>
1095     * This method is intended primarily for internal use, though it may also be
1096     * used by advanced applications.
1097     *
1098     * @param key an object acting as a key for this user data value. This must be equal
1099     * (in the sense of the equals() method) to the key supplied when the data value was
1100     * registered using {@link #setUserData}.
1101     * @param name the name of the required property
1102     * @return the value of the required property
1103     */

1104
1105    public Object JavaDoc getUserData(Object JavaDoc key, String JavaDoc name) {
1106        String JavaDoc keyValue = key.hashCode() + " " + name;
1107        // System.err.println("getUserData " + name + " on object returning " + userDataTable.get(key));
1108
return userDataTable.get(keyValue);
1109    }
1110
1111    /**
1112     * Set user data associated with a key. To store user data, two objects are required:
1113     * an arbitrary object that may be regarded as the container of the data (originally, and
1114     * typically still, a node in a tree), and a name. The name serves to distingush data objects
1115     * associated with the same node by different client applications.
1116     * <p>
1117     * This method is intended primarily for internal use, though it may also be
1118     * used by advanced applications.
1119     *
1120     * @param key an object acting as a key for this user data value. This must be equal
1121     * (in the sense of the equals() method) to the key supplied when the data value was
1122     * registered using {@link #setUserData}. If data for the given object and name already
1123     * exists, it is overwritten.
1124     * @param name the name of the required property
1125     * @param data the value of the required property
1126     */

1127
1128    public void setUserData(Object JavaDoc key, String JavaDoc name, Object JavaDoc data) {
1129        // System.err.println("setUserData " + name + " on object to " + data);
1130
String JavaDoc keyVal = key.hashCode() + " " + name;
1131        if (data==null) {
1132            userDataTable.remove(keyVal);
1133        } else {
1134            userDataTable.put(keyVal, data);
1135        }
1136    }
1137
1138
1139    /////////////////////////////////////////////////////////////////////////
1140
// implement the javax.xml.transform.Transformer methods
1141
/////////////////////////////////////////////////////////////////////////
1142

1143    /**
1144     * Perform a transformation from a Source document to a Result document.
1145     *
1146     * @exception XPathException if the transformation fails. As a
1147     * special case, the method throws a TerminationException (a subclass
1148     * of XPathException) if the transformation was terminated using
1149     * xsl:message terminate="yes".
1150     * @param source The input for the source tree. May be null if and only if an
1151     * initial template has been supplied.
1152     * @param result The destination for the result tree.
1153     */

1154
1155    public void transform(Source JavaDoc source, Result JavaDoc result) throws TransformerException {
1156        if (preparedStylesheet==null) {
1157            throw new DynamicError("Stylesheet has not been prepared");
1158        }
1159
1160        if (!dateTimePreset) {
1161            currentDateTime = null; // reset at start of each transformation
1162
}
1163
1164        try {
1165            NodeInfo startNode = null;
1166            boolean wrap = true;
1167            int validationMode = config.getSchemaValidationMode();
1168            Source JavaDoc underSource = source;
1169            if (source instanceof AugmentedSource) {
1170                Boolean JavaDoc localWrap = ((AugmentedSource)source).getWrapDocument();
1171                if (localWrap != null) {
1172                    wrap = localWrap.booleanValue();
1173                }
1174                int localValidate = ((AugmentedSource)source).getSchemaValidation();
1175                if (localValidate != Validation.DEFAULT) {
1176                    validationMode = localValidate;
1177                }
1178                if (validationMode == Validation.STRICT || validationMode == Validation.LAX) {
1179                    // If validation of a DOMSource or NodeInfo is requested, we must copy it, we can't wrap it
1180
wrap = false;
1181                }
1182                underSource = ((AugmentedSource)source).getContainedSource();
1183            }
1184            Source JavaDoc s2 = config.getSourceResolver().resolveSource(underSource, config);
1185            if (s2 != null) {
1186                underSource = s2;
1187            }
1188            if (wrap && (underSource instanceof NodeInfo || underSource instanceof DOMSource JavaDoc)) {
1189                startNode = prepareInputTree(underSource);
1190                registerDocument(startNode.getDocumentRoot(), underSource.getSystemId());
1191
1192            } else if (source == null) {
1193                if (initialTemplate == null) {
1194                    throw new DynamicError("Either a source document or an initial template must be specified");
1195                }
1196
1197            } else {
1198                // The input is a SAXSource or StreamSource, or
1199
// a DOMSource with wrap=no: build the document tree
1200

1201                Builder sourceBuilder = makeBuilder();
1202                Sender sender = new Sender(makePipelineConfiguration());
1203                Receiver r = sourceBuilder;
1204                if (executable.stripsWhitespace()) {
1205                    r = makeStripper(sourceBuilder);
1206                }
1207                if (executable.stripsInputTypeAnnotations()) {
1208                    r = config.getAnnotationStripper(r);
1209                }
1210                sender.send(source, r);
1211                DocumentInfo doc = (DocumentInfo)sourceBuilder.getCurrentRoot();
1212                registerDocument(doc, source.getSystemId());
1213                startNode = doc;
1214            }
1215
1216            transformDocument(startNode, result);
1217
1218        } catch (TerminationException err) {
1219            //System.err.println("Processing terminated using xsl:message");
1220
throw err;
1221        } catch (XPathException err) {
1222            Throwable JavaDoc cause = err.getException();
1223            if (cause != null && cause instanceof SAXParseException JavaDoc) {
1224                // This generally means the error was already reported.
1225
// But if a RuntimeException occurs in Saxon during a callback from
1226
// the Crimson parser, Crimson wraps this in a SAXParseException without
1227
// reporting it further.
1228
SAXParseException JavaDoc spe = (SAXParseException JavaDoc)cause;
1229                cause = spe.getException();
1230                if (cause instanceof RuntimeException JavaDoc) {
1231                    errorListener.fatalError(err);
1232                }
1233            } else {
1234                errorListener.fatalError(err);
1235            }
1236            throw err;
1237        }
1238    }
1239
1240    /**
1241     * Prepare an input tree for processing. This is used when either the initial
1242     * input, or a Source returned by the document() function, is a NodeInfo or a
1243     * DOMSource. The preparation consists of wrapping a DOM document inside a wrapper
1244     * that implements the NodeInfo interface, and/or adding a space-stripping wrapper
1245     * if the stylesheet strips whitespace nodes.
1246     * <p>
1247     * This method is intended for internal use.
1248     *
1249     * @param source the input tree. Must be either a DOMSource or a NodeInfo
1250     * @return the NodeInfo representing the input node, suitably wrapped.
1251     */

1252
1253    public NodeInfo prepareInputTree(Source JavaDoc source) {
1254        NodeInfo start = unravel(source, getConfiguration());
1255        if (executable.stripsWhitespace()) {
1256            DocumentInfo docInfo = start.getDocumentRoot();
1257            StrippedDocument strippedDoc = new StrippedDocument(docInfo, makeStripper(null));
1258            start = strippedDoc.wrap(start);
1259        }
1260        return start;
1261    }
1262
1263    /**
1264     * Get a NodeInfo corresponding to a DOM Node, either by wrapping or unwrapping the DOM Node.
1265     * <p>
1266     * This method is intended for internal use.
1267     */

1268
1269    public static NodeInfo unravel(Source JavaDoc source, Configuration config) {
1270        List externalObjectModels = config.getExternalObjectModels();
1271        for (int m=0; m<externalObjectModels.size(); m++) {
1272            ExternalObjectModel model = (ExternalObjectModel)externalObjectModels.get(m);
1273            NodeInfo node = model.unravel(source, config);
1274            if (node != null) {
1275                return node;
1276            }
1277        }
1278        if (source instanceof NodeInfo) {
1279            return (NodeInfo)source;
1280        }
1281        return null;
1282    }
1283
1284    /**
1285     * Transform a source XML document supplied as a tree. <br>
1286     * A new output destination should be created for each source document,
1287     * by using setOutputDetails().
1288     * <p>
1289     * This method is intended for internal use. External applications should use
1290     * the {@link #transform} method, which is part of the JAXP interface. Note that
1291     * <code>NodeInfo</code> implements the JAXP <code>Source</code> interface, so
1292     * it may be supplied directly to the transform() method.
1293     *
1294     * @exception XPathException if any dynamic error occurs
1295     * @param startNode A Node that identifies the source document to be
1296     * transformed and the node where the transformation should start.
1297     * May be null if the transformation is to start using an initial template.
1298     * @param result The output destination
1299     */

1300
1301    public void transformDocument(NodeInfo startNode, Result JavaDoc result)
1302    throws TransformerException {
1303
1304        if (executable==null) {
1305            throw new DynamicError("Stylesheet has not been compiled");
1306        }
1307
1308        // Determine whether we need to close the output stream at the end. We
1309
// do this if the Result object is a StreamResult and is supplied as a
1310
// system ID, not as a Writer or OutputStream
1311

1312        boolean mustClose = (result instanceof StreamResult JavaDoc &&
1313                ((StreamResult JavaDoc)result).getOutputStream() == null);
1314
1315        principalResult = result;
1316        if (principalResultURI == null) {
1317            principalResultURI = result.getSystemId();
1318        }
1319
1320        XPathContextMajor initialContext = newXPathContext();
1321        initialContext.setOrigin(this);
1322
1323        if (startNode != null) {
1324            DocumentInfo sourceDoc;
1325            if (startNode instanceof DocumentInfo) {
1326                sourceDoc = (DocumentInfo)startNode;
1327            } else {
1328                sourceDoc = startNode.getDocumentRoot();
1329                if (sourceDoc == null) {
1330                    throw new DynamicError("Source tree must have a document node as its root");
1331                }
1332            }
1333
1334            principalSourceDocument = sourceDoc;
1335
1336            if (sourceDoc.getConfiguration()==null) {
1337                // must be a non-standard document implementation
1338
throw new TransformerException("The supplied source document must be associated with a Configuration");
1339                //sourceDoc.setConfiguration(getConfiguration());
1340
}
1341
1342            if (sourceDoc.getNamePool() != preparedStylesheet.getTargetNamePool()) {
1343                throw new DynamicError("Source document and stylesheet must use the same name pool");
1344            }
1345            SequenceIterator currentIter = SingletonIterator.makeIterator(sourceDoc);
1346            currentIter.next();
1347            initialContext.setCurrentIterator(currentIter);
1348        }
1349
1350        initializeController();
1351
1352        // In tracing/debugging mode, evaluate all the global variables first
1353
if (getConfiguration().getTraceListener() != null) {
1354            preEvaluateGlobals(initialContext);
1355        }
1356
1357        Properties xslOutputProps = executable.getDefaultOutputProperties();
1358
1359        // overlay the output properties defined via the API
1360
if (outputProperties!=null) {
1361            Enumeration props = outputProperties.propertyNames();
1362            while (props.hasMoreElements()) {
1363                String JavaDoc p = (String JavaDoc)props.nextElement();
1364                String JavaDoc v = outputProperties.getProperty(p);
1365                xslOutputProps.put(p, v);
1366            }
1367        }
1368
1369        // deal with stylesheet chaining
1370
String JavaDoc nextInChain = xslOutputProps.getProperty(SaxonOutputKeys.NEXT_IN_CHAIN);
1371        if (nextInChain != null) {
1372            String JavaDoc baseURI = xslOutputProps.getProperty(SaxonOutputKeys.NEXT_IN_CHAIN_BASE_URI);
1373            result = prepareNextStylesheet(nextInChain, baseURI, result);
1374        }
1375
1376        initialContext.changeOutputDestination(xslOutputProps, result, true, Validation.PRESERVE, null);
1377        initialContext.getReceiver().startDocument(0);
1378
1379        // Process the source document using the handlers that have been set up
1380

1381        if (initialTemplate == null) {
1382            AxisIterator single = SingletonIterator.makeIterator(startNode);
1383            initialContext.setCurrentIterator(single);
1384            principalSourceDocument = (startNode==null ? null : startNode.getDocumentRoot());
1385            if (principalSourceDocument == null) {
1386                throw new DynamicError("Source tree must be rooted at a document node");
1387            }
1388            TailCall tc = ApplyTemplates.applyTemplates(
1389                                initialContext.getCurrentIterator(),
1390                                getRuleManager().getMode(initialMode),
1391                                null, null, initialContext, false, 0);
1392            while (tc != null) {
1393                tc = tc.processLeavingTail(initialContext);
1394            }
1395        } else {
1396            Template t = initialTemplate;
1397            XPathContextMajor c2 = initialContext.newContext();
1398            c2.setOrigin(this);
1399            c2.openStackFrame(t.getStackFrameMap());
1400            c2.setLocalParameters(new ParameterSet());
1401            c2.setTunnelParameters(new ParameterSet());
1402
1403            TailCall tc = t.expand(c2);
1404            while (tc != null) {
1405                tc = tc.processLeavingTail(c2);
1406            }
1407        }
1408
1409        if (traceListener!=null) {
1410            traceListener.close();
1411        }
1412
1413        initialContext.getReceiver().endDocument();
1414        initialContext.getReceiver().close();
1415
1416        if (mustClose && result instanceof StreamResult JavaDoc) {
1417            OutputStream JavaDoc os = ((StreamResult JavaDoc)result).getOutputStream();
1418            if (os != null) {
1419                try {
1420                    os.close();
1421                } catch (java.io.IOException JavaDoc err) {
1422                    throw new DynamicError(err);
1423                }
1424            }
1425        }
1426
1427    }
1428
1429    /**
1430     * Pre-evaluate global variables (when debugging/tracing).
1431     * <p>
1432     * This method is intended for internal use.
1433     */

1434
1435    public void preEvaluateGlobals(XPathContext context) throws XPathException {
1436        HashMap vars = getExecutable().getGlobalVariableIndex();
1437        Iterator iter = vars.values().iterator();
1438        while (iter.hasNext()) {
1439            GlobalVariable var = (GlobalVariable)iter.next();
1440            var.evaluateVariable(context);
1441        }
1442    }
1443
1444    /**
1445     * Prepare another stylesheet to handle the output of this one.
1446     * <p>
1447     * This method is intended for internal use, to support the
1448     * <code>saxon:next-in-chain</code> extension.
1449     *
1450     * @exception XPathException if any dynamic error occurs
1451     * @param href URI of the next stylesheet to be applied
1452     * @param baseURI base URI for resolving href if it's a relative
1453     * URI
1454     * @param result the output destination of the current stylesheet
1455     * @return a replacement destination for the current stylesheet
1456     */

1457
1458    public Result JavaDoc prepareNextStylesheet(String JavaDoc href, String JavaDoc baseURI, Result JavaDoc result)
1459    throws TransformerException {
1460
1461        // TODO: should cache the results, we are recompiling the referenced
1462
// stylesheet each time it's used
1463

1464        Source JavaDoc source = null;
1465        if (userURIResolver != null) {
1466            source = userURIResolver.resolve(href, baseURI);
1467        }
1468        if (source == null) {
1469            source = standardURIResolver.resolve(href, baseURI);
1470        }
1471        TransformerFactoryImpl factory = new TransformerFactoryImpl();
1472        factory.setConfiguration(config);
1473        Templates next = factory.newTemplates(source);
1474        TransformerReceiver nextTransformer =
1475                new TransformerReceiver((Controller) next.newTransformer());
1476
1477        nextTransformer.setSystemId(principalResultURI);
1478        nextTransformer.setPipelineConfiguration(makePipelineConfiguration());
1479        nextTransformer.setResult(result);
1480
1481        return nextTransformer;
1482    }
1483
1484    //////////////////////////////////////////////////////////////////////////
1485
// Handle parameters to the transformation
1486
//////////////////////////////////////////////////////////////////////////
1487

1488    /**
1489     * Set a parameter for the transformation.
1490     * <p>
1491     * The following table shows some of the classes that are supported
1492     * by this method. (Others may also be supported, but continued support is
1493     * not guaranteed.) Each entry in the table shows first the Java class of the
1494     * supplied object, and then the type of the resulting XPath value.
1495     * <p>
1496     * <table>
1497     * <thead>
1498     * <tr><th>Java Class</th><th>XPath 2.0 type</th></tr>
1499     * </thead>
1500     * <tbody>
1501     * <tr><td>String</td><td>xs:string</td></tr>
1502     * <tr><td>Boolean</td><td>xs:boolean</td></tr>
1503     * <tr><td>Integer</td><td>xs:integer</td></tr>
1504     * <tr><td>Long</td><td>xs:integer</td></tr>
1505     * <tr><td>Double</td><td>xs:double</td></tr>
1506     * <tr><td>Float</td><td>xs:float</td></tr>
1507     * <tr><td>BigDecimal</td><td>xs:decimal</td></tr>
1508     * <tr><td>BigInteger</td><td>xs:integer</td></tr>
1509     * <tr><td>Date</td><td>xs:dateTime</td></tr>
1510     * <tr><td>Array or List of any of the above</td><td>sequence of the above</td></tr>
1511     * <tr><td>null</td><td>empty sequence</td></tr>
1512     * </tbody></table>
1513     * <p>
1514     * A node may be supplied as a <code>NodeInfo</code> object, a sequence of nodes
1515     * as an array or List of <code>NodeInfo</code> objects.
1516     * <p>
1517     * In addition, any object that implements the Saxon {@link net.sf.saxon.value.Value} interface
1518     * may be supplied, and will be used without conversion.
1519     * <p>
1520     * A node belong to an external object model (such as DOM, JDOM, or XOM) may be supplied provided (a)
1521     * that the external object model is registered with the Configuration, and (b) that the node is part
1522     * of a document tree that has been registered in the document pool.
1523     *
1524     * @param expandedName The name of the parameter in {uri}local format
1525     * @param value The value object. This must follow the rules above.
1526     * Other formats in addition to those listed above may be accepted.
1527     * @since 8.4
1528     */

1529
1530    public void setParameter(String JavaDoc expandedName, Object JavaDoc value) {
1531
1532        if (parameters == null) {
1533            parameters = new GlobalParameterSet();
1534        }
1535
1536        int fingerprint = namePool.allocateClarkName(expandedName);
1537        parameters.put(fingerprint, value);
1538
1539    }
1540
1541    /**
1542     * Reset the parameters to a null list.
1543     */

1544
1545    public void clearParameters() {
1546        parameters = null;
1547    }
1548
1549    /**
1550     * Get a parameter to the transformation. This returns the value of a parameter
1551     * that has been previously set using the {@link #setParameter} method. The value
1552     * is returned exactly as supplied, that is, before any conversion to an XPath value.
1553     *
1554     * @param expandedName the name of the required parameter, in
1555     * "{uri}local-name" format
1556     * @return the value of the parameter, if it exists, or null otherwise
1557     */

1558
1559    public Object JavaDoc getParameter(String JavaDoc expandedName) {
1560        if (parameters==null) {
1561            return null;
1562        }
1563        int f = namePool.allocateClarkName(expandedName);
1564        return parameters.get(f);
1565    }
1566
1567    /**
1568     * Set the current date and time for this query or transformation.
1569     * This method is provided primarily for testing purposes, to allow tests to be run with
1570     * a fixed date and time. The supplied date/time must include a timezone, which is used
1571     * as the implicit timezone. Calls are ignored if a current date/time has already been
1572     * established by calling getCurrentDateTime().
1573     *
1574     * <p>Note that comparisons of date/time values currently use the implicit timezone
1575     * taken from the system clock, not from the value supplied here.</p>
1576     */

1577
1578    public void setCurrentDateTime(DateTimeValue dateTime) throws XPathException {
1579        if (currentDateTime==null) {
1580            if (dateTime.getComponent(Component.TIMEZONE) == null) {
1581                throw new DynamicError("No timezone is present in supplied value of current date/time");
1582            }
1583            currentDateTime = dateTime;
1584            dateTimePreset = true;
1585        }
1586    }
1587
1588    /**
1589     * Get the current date and time for this query or transformation.
1590     * All calls during one transformation return the same answer.
1591     * <p>
1592     * This method is intended for internal use.
1593     *
1594     * @return Get the current date and time. This will deliver the same value
1595     * for repeated calls within the same transformation
1596     */

1597
1598    public DateTimeValue getCurrentDateTime() {
1599        if (currentDateTime==null) {
1600            currentDateTime = new DateTimeValue(new GregorianCalendar(), true);
1601        }
1602        return currentDateTime;
1603    }
1604
1605    /////////////////////////////////////////
1606
// Methods for handling dynamic context
1607
/////////////////////////////////////////
1608

1609    /**
1610     * Make an XPathContext object for expression evaluation.
1611     * <p>
1612     * This method is intended for internal use.
1613     *
1614     * @return the new XPathContext
1615     */

1616
1617    public XPathContextMajor newXPathContext() {
1618        return new XPathContextMajor(this);
1619    }
1620
1621    /**
1622     * Set the last remembered node, for node numbering purposes.
1623     * <p>
1624     * This method is strictly for internal use only.
1625     *
1626     * @param node the node in question
1627     * @param number the number of this node
1628     */

1629
1630    public void setRememberedNumber(NodeInfo node, int number) {
1631        lastRememberedNode = node;
1632        lastRememberedNumber = number;
1633    }
1634
1635    /**
1636     * Get the number of a node if it is the last remembered one.
1637     * <p>
1638     * This method is strictly for internal use only.
1639     *
1640     * @param node the node for which remembered information is required
1641     * @return the number of this node if known, else -1.
1642     */

1643
1644    public int getRememberedNumber(NodeInfo node) {
1645        if (lastRememberedNode == node) {
1646            return lastRememberedNumber;
1647        }
1648        return -1;
1649    }
1650
1651    /**
1652     * Get diagnostic information about this context.
1653     * <p>
1654     * This method is intended for internal use.
1655     */

1656
1657    public InstructionInfo getInstructionInfo() {
1658        InstructionDetails details = new InstructionDetails();
1659        details.setConstructType(Location.CONTROLLER);
1660        return details;
1661    }
1662
1663    /**
1664     * Set a ClassLoader to be used when loading external classes. Examples of classes that are
1665     * loaded include SAX parsers, localization modules for formatting numbers and dates,
1666     * extension functions, external object models. In an environment such as Eclipse that uses
1667     * its own ClassLoader, this ClassLoader should be nominated to ensure that any class loaded
1668     * by Saxon is identical to a class of the same name loaded by the external environment.
1669     * <p>
1670     * This method is for application use, but is experimental and subject to change.
1671     *
1672     * @param loader the ClassLoader to be used.
1673     */

1674
1675    public void setClassLoader(ClassLoader JavaDoc loader) {
1676        this.classLoader = loader;
1677    }
1678
1679    /**
1680     * Get the ClassLoader supplied using the method {@link #setClassLoader}.
1681     * If none has been supplied, return null.
1682     * <p>
1683     * This method is for application use, but is experimental and subject to change.
1684     *
1685     * @return the ClassLoader in use.
1686     */

1687
1688    public ClassLoader JavaDoc getClassLoader() {
1689        return classLoader;
1690    }
1691
1692    /**
1693     * Allocate a local document number: that is, a document number for a document
1694     * that is used only locally within this query or transformation (a temporary tree).
1695     * Local document numbers are allocated by the controller to avoid the synchronization
1696     * overhead of allocating a global document number from the NamePool. Local document
1697     * numbers are always negative, global document numbers are positive.
1698     */

1699
1700// public int allocateLocalDocumentNumber() {
1701
// return nextLocalDocumentNumber--;
1702
// }
1703
}
1704
1705//
1706
// The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
1707
// you may not use this file except in compliance with the License. You may obtain a copy of the
1708
// License at http://www.mozilla.org/MPL/
1709
//
1710
// Software distributed under the License is distributed on an "AS IS" basis,
1711
// WITHOUT WARRANTY OF ANY KIND, either express or implied.
1712
// See the License for the specific language governing rights and limitations under the License.
1713
//
1714
// The Original Code is: all this file.
1715
//
1716
// The Initial Developer of the Original Code is Michael H. Kay.
1717
//
1718
// Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
1719
//
1720
// Contributor(s):
1721
// Portions marked "e.g." are from Edwin Glaser (edwin@pannenleiter.de)
1722
//
1723
Popular Tags