The Controller is Saxon's implementation of the JAXP Transformer class, and represents
an executing instance of a transformation or query. Multiple concurrent executions of
the same transformation or query will use different Controller instances. This class is
therefore not thread-safe.
The Controller is serially reusable, as required by JAXP: when one transformation or query
is finished, it can be used to run another. However, there is no advantage in doing this
rather than allocating a new Controller each time.
The Controller can also be used when running Java applications that use neither XSLT nor
XQuery. A dummy Controller is created when running free-standing XPath expressions.
The Controller holds those parts of the dynamic context that do not vary during the course
of a transformation or query, or that do not change once their value has been computed.
This also includes those parts of the static context that are required at run-time.
Wherever possible XSLT applications should use the JAXP Transformer class directly,
rather than relying on Saxon-specific methods in the Controller. However, some
features are currently available only through this class. This applies especially
to new features specific to XSLT 2.0, since the JAXP interface still supports
only XSLT 1.0. Such methods may be superseded in the future by JAXP methods.
Many methods on the Controller are designed for internal use and should not be
considered stable. From release 8.4 onwards, those methods that are considered sufficiently
stable to constitute path of the Saxon public API are labelled with the JavaDoc tag "since":
the value indicates the release at which the method was added to the public API.
Method from net.sf.saxon.Controller Detail: |
public void addTraceListener(TraceListener trace) {
// e.g.
if (trace != null) {
traceListener = TraceEventMulticaster.add(traceListener, trace);
}
}
Adds the specified trace listener to receive trace events from
this instance. Note that although TraceListeners can be added
or removed dynamically, this has no effect unless the stylesheet
or query has been compiled with tracing enabled. This is achieved
by calling Configuration#setTraceListener or by setting
the attribute FeatureKeys#TRACE_LISTENER on the
TransformerFactory. Conversely, if this property has been set in the
Configuration or TransformerFactory, the TraceListener will automatically
be added to every Controller that uses that Configuration. |
public void addUnavailableOutputDestination(String uri) {
if (allOutputDestinations == null) {
allOutputDestinations = new HashSet(20);
}
allOutputDestinations.add(uri);
}
Add a URI to the set of output destinations that cannot be written to, either because
they have already been written to, or because they have been read |
public void allocateGlobalVariables(int numberOfVariables) {
SlotManager map = executable.getGlobalVariableMap();
map.setNumberOfVariables(numberOfVariables);
bindery.allocateGlobals(map);
}
Allocate space in the bindery for global variables.
For internal use only. |
public SequenceOutputter allocateSequenceOutputter(int size) {
if (reusableSequenceOutputter != null) {
SequenceOutputter out = reusableSequenceOutputter;
reusableSequenceOutputter = null;
return out;
} else {
return new SequenceOutputter(this, size);
}
}
Allocate a SequenceOutputter for a new output destination. Reuse the existing one
if it is available for reuse (this is designed to ensure that the TinyTree structure
is also reused, creating a forest of trees all sharing the same data structure) |
public void checkImplicitResultTree() throws XPathException {
if (!checkUniqueOutputDestination(principalResultURI)) {
XPathException err = new XPathException("Cannot write an implicit result document if an explicit result document has been written to the same URI: " +
principalResultURI);
err.setErrorCode("XTDE1490");
throw err;
}
}
Check whether an XSLT implicit result tree can be written. This is allowed only if no xsl:result-document
has been written for the principal output URI |
public boolean checkUniqueOutputDestination(String uri) {
if (uri == null) {
return true; // happens when writing say to an anonymous StringWriter
}
if (allOutputDestinations == null) {
allOutputDestinations = new HashSet(20);
}
if (uri.startsWith("file:///")) {
uri = "file:/" + uri.substring(8);
}
return !allOutputDestinations.contains(uri);
}
Check that an output destination has not been used before, optionally adding
this URI to the set of URIs that have been used. |
public void clearDocumentPool() {
sourceDocumentPool = new DocumentPool();
}
Clear the document pool.
This is sometimes useful when re-using the same Transformer
for a sequence of transformations, but it isn't done automatically, because when
the transformations use common look-up documents, the caching is beneficial. |
public void clearParameters() {
parameters = null;
}
Reset the parameters to a null list. |
public void defineGlobalParameters() throws XPathException {
executable.checkAllRequiredParamsArePresent(parameters);
bindery.defineGlobalParameters(parameters);
}
|
public String getBaseOutputURI() {
return principalResultURI;
}
Get the base output URI.
This defaults to the system ID of the principal Result object, but
a different value can be set for use where there is no principal result.
The command line interface sets this to the current working directory.
The concept of the base output URI is new in XSLT 2.0: it defines the
base URI for resolving relative URIs in the href attribute
of the xsl:result-document instruction. This method may be
superseded by a standard JAXP method when JAXP is updated to support XSLT 2.0. |
public Bindery getBindery() {
return bindery;
}
|
public ClassLoader getClassLoader() {
return classLoader;
}
Get the ClassLoader supplied using the method #setClassLoader .
If none has been supplied, return null.
This method is for application use, but is experimental and subject to change. |
public Configuration getConfiguration() {
return config;
}
Get the Configuration associated with this Controller. The Configuration holds
settings that potentially apply globally to many different queries and transformations. |
public Item getContextForGlobalVariables() {
return contextForGlobalVariables;
// See bug 5224, which points out that the rules for XQuery 1.0 weren't clearly defined
}
Get the item used as the context for evaluating global variables. In XQuery this
is the same as the initial context item; in XSLT it is the root of the tree containing
the initial context node. |
public String getCookedBaseOutputURI() {
if (cookedPrincipalResultURI == null) {
String base = getBaseOutputURI();
if (base == null && config.isAllowExternalFunctions()) {
// if calling external functions is allowed, then the stylesheet is trusted, so
// we allow it to write to files relative to the current directory
base = new File(System.getProperty("user.dir")).toURI().toString();
}
if (base != null) {
base = EscapeURI.iriToUri(base).toString();
}
cookedPrincipalResultURI = base;
}
return cookedPrincipalResultURI;
}
Get the base output URI after processing. The processing consists of (a) defaulting
to the current user directory if no base URI is available and if the stylesheet is trusted,
and (b) applying IRI-to-URI escaping |
public DateTimeValue getCurrentDateTime() {
if (currentDateTime==null) {
currentDateTime = new DateTimeValue(new GregorianCalendar(), true);
}
return currentDateTime;
}
Get the current date and time for this query or transformation.
All calls during one transformation return the same answer. |
public DocumentPool getDocumentPool() {
return sourceDocumentPool;
}
|
public ErrorListener getErrorListener() {
return errorListener;
}
|
public Executable getExecutable() {
return executable;
}
|
public int getImplicitTimezone() {
return getCurrentDateTime().getTimezoneInMinutes();
}
Get the implicit timezone for this query or transformation |
public Item getInitialContextItem() {
return initialContextItem;
}
Get the initial context item. This returns the item (often a document node)
previously supplied to the #setInitialContextItem method, or the
initial context node set implicitly using methods such as #transform . |
public String getInitialMode() {
return initialMode.getClarkName();
}
Get the initial mode for the transformation |
public String getInitialTemplate() {
if (initialTemplate == null) {
return null;
} else {
return initialTemplate.getTemplateName().getClarkName();
}
}
|
public KeyManager getKeyManager() {
return executable.getKeyManager();
}
|
public Receiver getMessageEmitter() {
return messageEmitter;
}
Get the Emitter used for xsl:message output. This returns the emitter
previously supplied to the #setMessageEmitter method, or the
default message emitter otherwise. |
public NamePool getNamePool() {
return namePool;
}
Get the name pool in use. The name pool is responsible for mapping QNames used in source
documents and compiled stylesheets and queries into numeric codes. All source documents
used by a given transformation or query must use the same name pool as the compiled stylesheet
or query. |
public Properties getOutputProperties() {
if (localOutputProperties == null) {
if (executable==null) {
return new Properties();
} else {
localOutputProperties = new Properties(executable.getDefaultOutputProperties());
}
}
// Make a copy, so that modifications to the returned properties object have no effect (even on the
// local output properties)
Properties newProps = new Properties();
Enumeration keys = localOutputProperties.propertyNames();
while(keys.hasMoreElements()) {
String key = (String)keys.nextElement();
newProps.setProperty(key, localOutputProperties.getProperty(key));
}
return newProps;
}
Get the output properties for the transformation.
As well as the properties defined in the JAXP OutputKeys class,
Saxon defines an additional set of properties in SaxonOutputKeys .
These fall into two categories: Constants representing serialization
properties defined in XSLT 2.0 (which are not yet supported by JAXP),
and constants supporting Saxon extensions to the set of serialization
properties. |
public String getOutputProperty(String name) {
try {
SaxonOutputKeys.checkOutputProperty(name, null, getConfiguration().getNameChecker());
} catch (XPathException err) {
throw new IllegalArgumentException(err.getMessage());
}
if (localOutputProperties == null) {
if (executable==null) {
return null;
} else {
localOutputProperties = executable.getDefaultOutputProperties();
}
}
return localOutputProperties.getProperty(name);
}
Get the value of an output property.
As well as the properties defined in the JAXP OutputKeys class,
Saxon defines an additional set of properties in SaxonOutputKeys .
These fall into two categories: Constants representing serialization
properties defined in XSLT 2.0 (which are not yet supported by JAXP),
and constants supporting Saxon extensions to the set of serialization
properties. |
public OutputURIResolver getOutputURIResolver() {
return outputURIResolver;
}
Get the output URI resolver. |
public Object getParameter(String expandedName) {
if (parameters==null) {
return null;
}
return parameters.get(StructuredQName.fromClarkName(expandedName));
}
Get a parameter to the transformation. This returns the value of a parameter
that has been previously set using the #setParameter method. The value
is returned exactly as supplied, that is, before any conversion to an XPath value. |
public PathMap getPathMapForDocumentProjection() {
return pathMap;
}
Get the path map used for document projection, if any. |
public Result getPrincipalResult() {
return principalResult;
}
Get the principal result destination.
This method is intended for internal use only. It is typically called by Saxon during the course
of a transformation, to discover the result that was supplied in the transform() call. |
public int getRecoveryPolicy() {
return recoveryPolicy;
}
Get the policy for handling recoverable errors |
public int getRememberedNumber(NodeInfo node) {
if (lastRememberedNode == node) {
return lastRememberedNumber;
}
return -1;
}
|
public RuleManager getRuleManager() {
return ruleManager;
}
|
public SchemaURIResolver getSchemaURIResolver() {
return schemaURIResolver;
}
Get the SchemaURIResolver used for resolving references to schema
documents. If none has been set on the Controller, returns the
SchemaURIResolver registered with the Configuration |
public URIResolver getStandardURIResolver() {
return standardURIResolver;
}
|
public PrintStream getTraceFunctionDestination() {
return traceFunctionDestination;
}
Get the destination for output from the fn:trace() function. |
public TraceListener getTraceListener() {
// e.g.
return traceListener;
}
Get the TraceListener. By default, there is no TraceListener, and this
method returns null. A TraceListener may be added using the method
#addTraceListener . If more than one TraceListener has been added,
this method will return a composite TraceListener. Because this form
this takes is implementation-dependent, this method is not part of the
stable Saxon public API. |
public int getTreeModel() {
return treeModel;
}
Get the tree data model to use. This affects all source documents subsequently constructed using a
Builder obtained from this Controller. This includes a document built from a StreamSource or
SAXSource supplied as a parameter to the #transform method. |
public URIResolver getURIResolver() {
return userURIResolver;
}
Get the URI resolver.
This method changed in Saxon 8.5, to conform to the JAXP specification. If there
is no user-specified URIResolver, it now returns null; previously it returned the system
default URIResolver. |
public UnparsedTextURIResolver getUnparsedTextURIResolver() {
return unparsedTextResolver;
}
Get the URI resolver for the unparsed-text() function. This will
return the UnparsedTextURIResolver previously set using the #setUnparsedTextURIResolver
method. |
public Object getUserData(Object key,
String name) {
String keyValue = key.hashCode() + " " + name;
// System.err.println("getUserData " + name + " on object returning " + userDataTable.get(key));
return userDataTable.get(keyValue);
}
Get user data associated with a key. To retrieve user data, two objects are required:
an arbitrary object that may be regarded as the container of the data (originally, and
typically still, a node in a tree), and a name. The name serves to distingush data objects
associated with the same node by different client applications.
This method is intended primarily for internal use, though it may also be
used by advanced applications. |
public boolean hasThereBeenAnExplicitResultDocument() {
return thereHasBeenAnExplicitResultDocument;
}
Test whether an explicit result tree has been written using xsl:result-document |
public void initializeController() throws XPathException {
setRuleManager(executable.getRuleManager());
//setDecimalFormatManager(executable.getDecimalFormatManager());
if (traceListener!=null) {
traceListener.open();
}
// get a new bindery, to clear out any variables from previous runs
bindery = new Bindery();
executable.initializeBindery(bindery);
// if parameters were supplied, set them up
defineGlobalParameters();
}
Initialize the controller ready for a new transformation. This method should not normally be called by
users (it is done automatically when transform() is invoked). However, it is available as a low-level API
especially for use with XQuery. |
public final boolean isTracing() {
// e.g.
return traceListener != null && !tracingPaused;
}
Test whether instruction execution is being traced. This will be true
if (a) at least one TraceListener has been registered using the
#addTraceListener method, and (b) tracing has not been temporarily
paused using the #pauseTracing method. |
public boolean isUnusedOutputDestination(String uri) {
return allOutputDestinations == null || !allOutputDestinations.contains(uri);
}
Determine whether an output URI is available for use. This method is intended
for use by applications, via an extension function. |
public Iterator iterateParameters() {
if (parameters == null) {
return Collections.EMPTY_LIST.iterator();
}
int k = parameters.getNumberOfKeys();
List list = new ArrayList(k);
Collection keys = parameters.getKeys();
for (Iterator it = keys.iterator(); it.hasNext();) {
StructuredQName qName = (StructuredQName)it.next();
String clarkName = qName.getClarkName();
list.add(clarkName);
}
return list.iterator();
}
Get an iterator over the names of global parameters that have been defined |
public Builder makeBuilder() {
Builder b;
if (treeModel==Builder.TINY_TREE) {
b = new TinyBuilder();
} else {
b = new TreeBuilder();
}
b.setTiming(config.isTiming());
b.setLineNumbering(config.isLineNumbering());
b.setPipelineConfiguration(makePipelineConfiguration());
return b;
}
Make a builder for the selected tree model. |
public CharacterMapExpander makeCharacterMapExpander(String useMaps,
SerializerFactory sf) throws XPathException {
CharacterMapExpander characterMapExpander = null;
HashMap characterMapIndex = getExecutable().getCharacterMapIndex();
if (useMaps != null && characterMapIndex != null) {
List characterMaps = new ArrayList(5);
StringTokenizer st = new StringTokenizer(useMaps, " \t\n\r", false);
while (st.hasMoreTokens()) {
String expandedName = st.nextToken();
StructuredQName qName = StructuredQName.fromClarkName(expandedName);
IntHashMap map = (IntHashMap)characterMapIndex.get(qName);
if (map==null) {
throw new XPathException("Character map '" + expandedName + "' has not been defined");
}
characterMaps.add(map);
}
if (!characterMaps.isEmpty()) {
characterMapExpander = sf.newCharacterMapExpander();
characterMapExpander.setCharacterMaps(characterMaps);
}
}
return characterMapExpander;
}
|
public PipelineConfiguration makePipelineConfiguration() {
PipelineConfiguration pipe = new PipelineConfiguration();
pipe.setConfiguration(getConfiguration());
pipe.setErrorListener(getErrorListener());
pipe.setURIResolver(userURIResolver==null ? standardURIResolver : userURIResolver);
pipe.setSchemaURIResolver(schemaURIResolver);
pipe.setExpandAttributeDefaults(getConfiguration().isExpandAttributeDefaults());
pipe.setUseXsiSchemaLocation(((Boolean)getConfiguration().getConfigurationProperty(
FeatureKeys.USE_XSI_SCHEMA_LOCATION)).booleanValue());
pipe.setController(this);
final Executable executable = getExecutable();
if (executable != null) {
// can be null for an IdentityTransformer
pipe.setLocationProvider(executable.getLocationMap());
pipe.setHostLanguage(executable.getHostLanguage());
}
return pipe;
}
Make a PipelineConfiguration based on the properties of this Controller.
This interface is intended primarily for internal use, although it may be necessary
for applications to call it directly if they construct pull or push pipelines |
public Stripper makeStripper(Receiver b) {
if (config.isStripsAllWhiteSpace()) {
if (b==null) {
return AllElementStripper.getInstance();
} else {
Stripper s = new AllElementStripper();
s.setUnderlyingReceiver(b);
s.setPipelineConfiguration(b.getPipelineConfiguration());
return s;
}
}
Stripper stripper;
if (executable==null) {
stripper = new Stripper(new Mode(Mode.STRIPPER_MODE, Mode.DEFAULT_MODE_NAME));
} else {
stripper = executable.newStripper();
}
stripper.setXPathContext(newXPathContext());
if (b == null) {
stripper.setPipelineConfiguration(makePipelineConfiguration());
} else {
stripper.setPipelineConfiguration(b.getPipelineConfiguration());
stripper.setUnderlyingReceiver(b);
}
return stripper;
}
Make a Stripper configured to implement the whitespace stripping rules.
In the case of XSLT the whitespace stripping rules are normally defined
by xsl:strip-space and xsl:preserve-space Configuration#setStripsAllWhiteSpace(boolean) . |
public XPathContextMajor newXPathContext() {
return new XPathContextMajor(this);
}
|
public final void pauseTracing(boolean pause) {
tracingPaused = pause;
}
Pause or resume tracing. While tracing is paused, trace events are not sent to any
of the registered TraceListeners. |
public void preEvaluateGlobals(XPathContext context) throws XPathException {
HashMap vars = getExecutable().getCompiledGlobalVariables();
if (vars != null) {
Iterator iter = vars.values().iterator();
while (iter.hasNext()) {
GlobalVariable var = (GlobalVariable)iter.next();
var.evaluateVariable(context);
}
}
}
|
public NodeInfo prepareInputTree(Source source) {
NodeInfo start = getConfiguration().unravel(source);
if (executable.stripsWhitespace()) {
DocumentInfo docInfo = start.getDocumentRoot();
StrippedDocument strippedDoc = new StrippedDocument(docInfo, makeStripper(null));
start = strippedDoc.wrap(start);
}
return start;
}
|
public Result prepareNextStylesheet(String href,
String baseURI,
Result result) throws TransformerException {
PreparedStylesheet next = preparedStylesheet.getCachedStylesheet(href, baseURI);
if (next == null) {
Source source = null;
if (userURIResolver != null) {
source = userURIResolver.resolve(href, baseURI);
}
if (source == null) {
source = standardURIResolver.resolve(href, baseURI);
}
TransformerFactoryImpl factory = new TransformerFactoryImpl();
factory.setConfiguration(config);
next = (PreparedStylesheet)factory.newTemplates(source);
preparedStylesheet.putCachedStylesheet(href, baseURI, next);
}
TransformerReceiver nextTransformer =
new TransformerReceiver((Controller) next.newTransformer());
nextTransformer.setSystemId(principalResultURI);
nextTransformer.setPipelineConfiguration(makePipelineConfiguration());
nextTransformer.setResult(result);
nextTransformer.open();
return nextTransformer;
}
Prepare another stylesheet to handle the output of this one.
This method is intended for internal use, to support the
saxon:next-in-chain extension. |
public void recoverableError(XPathException err) throws XPathException {
try {
if (executable.getHostLanguage() == Configuration.XQUERY) {
reportFatalError(err);
throw err;
} else {
errorListener.error(err);
}
} catch (TransformerException e) {
XPathException de = XPathException.makeXPathException(e);
de.setHasBeenReported();
throw de;
}
}
|
public void registerDocument(DocumentInfo doc,
String systemId) {
sourceDocumentPool.add(doc, systemId);
}
|
public void removeTraceListener(TraceListener trace) {
// e.g.
traceListener = TraceEventMulticaster.remove(traceListener, trace);
}
Removes the specified trace listener so that the listener will no longer
receive trace events. |
public void removeUnavailableOutputDestination(String uri) {
if (allOutputDestinations != null) {
allOutputDestinations.remove(uri);
}
}
Remove a URI from the set of output destinations that cannot be written to or read from.
Used to support saxon:discard-document() |
public void reportFatalError(XPathException err) {
if (!err.hasBeenReported()) {
try {
getErrorListener().fatalError(err);
} catch (TransformerException e) {
//
}
err.setHasBeenReported();
}
}
|
public void reset() {
bindery = new Bindery();
namePool = config.getNamePool();
standardURIResolver = config.getSystemURIResolver();
userURIResolver = config.getURIResolver();
outputURIResolver = config.getOutputURIResolver();
schemaURIResolver = config.getSchemaURIResolver();
unparsedTextResolver = new StandardUnparsedTextResolver();
errorListener = config.getErrorListener();
recoveryPolicy = config.getRecoveryPolicy();
if (errorListener instanceof StandardErrorListener) {
// if using a standard error listener, make a fresh one
// for each transformation, because it is stateful - and also because the
// host language is now known (a Configuration can serve multiple host languages)
PrintStream ps = ((StandardErrorListener)errorListener).getErrorOutput();
errorListener = ((StandardErrorListener)errorListener).makeAnother(executable.getHostLanguage());
((StandardErrorListener)errorListener).setErrorOutput(ps);
((StandardErrorListener)errorListener).setRecoveryPolicy(recoveryPolicy);
}
userDataTable = new HashMap(20);
traceListener = null;
tracingPaused = false;
traceFunctionDestination = System.err;
TraceListener tracer;
try {
tracer = config.makeTraceListener();
} catch (XPathException err) {
throw new IllegalStateException(err.getMessage());
}
if (tracer!=null) {
addTraceListener(tracer);
}
setTreeModel(config.getTreeModel());
initialContextItem = null;
contextForGlobalVariables = null;
messageEmitter = null;
localOutputProperties = null;
parameters = null;
principalResult = null;
principalResultURI = null;
initialTemplate = null;
allOutputDestinations = null;
thereHasBeenAnExplicitResultDocument = false;
currentDateTime = null;
dateTimePreset = false;
initialMode = null;
lastRememberedNode = null;
lastRememberedNumber = -1;
classLoader = null;
}
|
public void reuseSequenceOutputter(SequenceOutputter out) {
reusableSequenceOutputter = out;
}
Accept a SequenceOutputter that is now available for reuse |
public void setBaseOutputURI(String uri) {
principalResultURI = uri;
}
Set the base output URI.
This defaults to the system ID of the principal Result object, but
a different value can be set for use where there is no principal result.
The command line interface sets this to the current working directory.
The concept of the base output URI is new in XSLT 2.0: it defines the
base URI for resolving relative URIs in the href attribute
of the xsl:result-document instruction. This method may be
superseded by a standard JAXP method when JAXP is updated to support XSLT 2.0. |
public void setClassLoader(ClassLoader loader) {
classLoader = loader;
}
Set a ClassLoader to be used when loading external classes. Examples of classes that are
loaded include SAX parsers, localization modules for formatting numbers and dates,
extension functions, external object models. In an environment such as Eclipse that uses
its own ClassLoader, this ClassLoader should be nominated to ensure that any class loaded
by Saxon is identical to a class of the same name loaded by the external environment.
This method is for application use, but is experimental and subject to change. |
public void setCurrentDateTime(DateTimeValue dateTime) throws XPathException {
if (currentDateTime==null) {
if (dateTime.getComponent(Component.TIMEZONE) == null) {
throw new XPathException("No timezone is present in supplied value of current date/time");
}
currentDateTime = dateTime;
dateTimePreset = true;
} else {
throw new IllegalStateException(
"Current date and time can only be set once, and cannot subsequently be changed");
}
}
Set the current date and time for this query or transformation.
This method is provided primarily for testing purposes, to allow tests to be run with
a fixed date and time. The supplied date/time must include a timezone, which is used
as the implicit timezone.
Note that comparisons of date/time values currently use the implicit timezone
taken from the system clock, not from the value supplied here. |
public void setErrorListener(ErrorListener listener) {
errorListener = listener;
}
|
public void setExecutable(Executable exec) {
executable = exec;
}
|
public void setInitialContextItem(Item item) {
initialContextItem = item;
contextForGlobalVariables = item;
// TODO: are we enforcing the rule that in XSLT the context for global variables is always the
// root of the tree?
}
Set the initial context item.
When a transformation is invoked using the #transform method, the
initial context node is set automatically. This method is useful in XQuery,
to define an initial context node for evaluating global variables, and also
in XSLT 2.0, when the transformation is started by invoking a named template.
When an initial context item is set, it also becomes the context item used for
evaluating global variables. The two context items can only be different when the
#transform method is used to transform a document starting at a node other
than the root.
In XQuery, the two context items are always
the same; in XSLT, the context node for evaluating global variables is the root of the
tree containing the initial context item. |
public void setInitialMode(String expandedModeName) {
if (expandedModeName==null) return;
if (expandedModeName.length() == 0) return;
initialMode = StructuredQName.fromClarkName(expandedModeName);
}
Set the initial mode for the transformation.
XSLT 2.0 allows a transformation to be started in a mode other than the default mode.
The transformation then starts by looking for the template rule in this mode that best
matches the initial context node.
This method may eventually be superseded by a standard JAXP method. |
public void setInitialTemplate(String expandedName) throws XPathException {
if (expandedName == null) {
initialTemplate = null;
return;
}
StructuredQName qName = StructuredQName.fromClarkName(expandedName);
Template t = getExecutable().getNamedTemplate(qName);
if (t == null) {
XPathException err = new XPathException("There is no named template with expanded name "
+ expandedName);
err.setErrorCode("XTDE0040");
reportFatalError(err);
throw err;
} else if (t.hasRequiredParams()) {
XPathException err = new XPathException("The named template "
+ expandedName
+ " has required parameters, so cannot be used as the entry point");
err.setErrorCode("XTDE0060");
reportFatalError(err);
throw err;
} else {
initialTemplate = t;
}
}
Set the initial named template to be used as the entry point.
XSLT 2.0 allows a transformation to start by executing a named template, rather than
by matching an initial context node in a source document. This method may eventually
be superseded by a standard JAXP method once JAXP supports XSLT 2.0.
Note that any parameters supplied using #setParameter are used as the values
of global stylesheet parameters. There is no way to supply values for local parameters
of the initial template. |
public void setMessageEmitter(Receiver receiver) {
messageEmitter = receiver;
if (receiver.getPipelineConfiguration() == null) {
messageEmitter.setPipelineConfiguration(makePipelineConfiguration());
}
if (messageEmitter instanceof Emitter && ((Emitter)messageEmitter).getOutputProperties() == null) {
try {
Properties props = new Properties();
props.setProperty(OutputKeys.METHOD, "xml");
props.setProperty(OutputKeys.INDENT, "yes");
props.setProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
((Emitter)messageEmitter).setOutputProperties(props);
} catch (XPathException e) {
// no action
}
}
}
Set the Receiver to be used for xsl:message output.
Recent versions of the JAXP interface specify that by default the
output of xsl:message is sent to the registered ErrorListener. Saxon
does not yet implement this convention. Instead, the output is sent
to a default message emitter, which is a slightly customised implementation
of the standard Saxon Emitter interface.
This interface can be used to change the way in which Saxon outputs
xsl:message output.
It is not necessary to use this interface in order to change the destination
to which messages are written: that can be achieved by obtaining the standard
message emitter and calling its Emitter#setWriter method.
Although any Receiver can be supplied as the destination for messages,
applications may find it convenient to implement a subclass of net.sf.saxon.event.SequenceWriter ,
in which only the abstract write() method is implemented. This will have the effect that the
write() method is called to output each message as it is generated, with the Item
that is passed to the write() method being the document node at the root of an XML document
containing the contents of the message.
This method is intended for use by advanced applications. The Receiver interface
itself is subject to change in new Saxon releases.
The supplied Receiver will have its open() method called once at the start of
the transformation, and its close() method will be called once at the end of the
transformation. Each individual call of an xsl:message instruction is wrapped by
calls of startDocument() and endDocument(). If terminate="yes" is specified on the
xsl:message call, the properties argument of the startDocument() call will be set
to the value ReceiverOptions#TERMINATE . |
public void setOutputProperties(Properties properties) {
if (properties == null) {
localOutputProperties = null;
} else {
Enumeration keys = properties.propertyNames();
while(keys.hasMoreElements()) {
String key = (String)keys.nextElement();
setOutputProperty(key, properties.getProperty(key));
}
}
}
Set the output properties for the transformation. These
properties will override properties set in the templates
with xsl:output.
As well as the properties defined in the JAXP OutputKeys class,
Saxon defines an additional set of properties in SaxonOutputKeys .
These fall into two categories: Constants representing serialization
properties defined in XSLT 2.0 (which are not yet supported by JAXP),
and constants supporting Saxon extensions to the set of serialization
properties. |
public void setOutputProperty(String name,
String value) {
if (localOutputProperties == null) {
localOutputProperties = getOutputProperties();
}
try {
SaxonOutputKeys.checkOutputProperty(name, value, getConfiguration().getNameChecker());
} catch (XPathException err) {
throw new IllegalArgumentException(err.getMessage());
}
localOutputProperties.setProperty(name, value);
}
Set an output property for the transformation.
As well as the properties defined in the JAXP OutputKeys class,
Saxon defines an additional set of properties in SaxonOutputKeys .
These fall into two categories: Constants representing serialization
properties defined in XSLT 2.0 (which are not yet supported by JAXP),
and constants supporting Saxon extensions to the set of serialization
properties. |
public void setOutputURIResolver(OutputURIResolver resolver) {
if (resolver==null) {
outputURIResolver = config.getOutputURIResolver();
} else {
outputURIResolver = resolver;
}
}
Set the URI resolver for secondary output documents.
XSLT 2.0 introduces the xsl:result-document
This method may eventually be superseded by a standard JAXP method. |
public void setParameter(String expandedName,
Object value) {
if (parameters == null) {
parameters = new GlobalParameterSet();
}
parameters.put(StructuredQName.fromClarkName(expandedName), value);
}
Set a parameter for the transformation.
The following table shows some of the classes that are supported
by this method. (Others may also be supported, but continued support is
not guaranteed.) Each entry in the table shows first the Java class of the
supplied object, and then the type of the resulting XPath value.
Java Class | XPath 2.0 type |
String | xs:string |
Boolean | xs:boolean |
Integer | xs:integer |
Long | xs:integer |
Double | xs:double |
Float | xs:float |
BigDecimal | xs:decimal |
BigInteger | xs:integer |
Date | xs:dateTime |
Array or List of any of the above | sequence of the above |
null | empty sequence |
A node may be supplied as a NodeInfo object, a sequence of nodes
as an array or List of NodeInfo objects.
In addition, any object that implements the Saxon net.sf.saxon.value.Value interface
may be supplied, and will be used without conversion.
A node belong to an external object model (such as DOM, JDOM, or XOM) may be supplied provided (a)
that the external object model is registered with the Configuration, and (b) that the node is part
of a document tree that has been registered in the document pool. |
public void setParameter(StructuredQName qName,
ValueRepresentation value) {
if (parameters == null) {
parameters = new GlobalParameterSet();
}
parameters.put(qName, value);
}
Supply a parameter using Saxon-specific representations of the name and value |
public void setPreparedStylesheet(PreparedStylesheet sheet) {
preparedStylesheet = sheet;
executable = sheet.getExecutable();
//setOutputProperties(sheet.getOutputProperties());
// above line deleted for bug 490964 - may have side-effects
}
|
public void setPrincipalSourceDocument(DocumentInfo doc) {
initialContextItem = doc;
} Deprecated! From - Saxon 8.7, replaced by #setInitialContextItem(Item)
Set the initial context node (used for evaluating global variables).
When a transformation is invoked using the #transform method, the
initial context node is set automatically. This method is useful in XQuery,
to define an initial context node for evaluating global variables, and also
in XSLT 2.0, when the transformation is started by invoking a named template. |
public void setRecoveryPolicy(int policy) {
recoveryPolicy = policy;
if (errorListener instanceof StandardErrorListener) {
((StandardErrorListener)errorListener).setRecoveryPolicy(policy);
}
}
Set the policy for handling recoverable errrors |
public void setRememberedNumber(NodeInfo node,
int number) {
lastRememberedNode = node;
lastRememberedNumber = number;
}
|
public void setRuleManager(RuleManager r) {
ruleManager = r;
}
|
public void setSchemaURIResolver(SchemaURIResolver resolver) {
schemaURIResolver = resolver;
}
Set the SchemaURIResolver used for resolving references to schema
documents. Defaults to the SchemaURIResolver registered with the
Configuration |
public void setThereHasBeenAnExplicitResultDocument() {
thereHasBeenAnExplicitResultDocument = true;
}
Set that an explicit result tree has been written using xsl:result-document |
public void setTraceFunctionDestination(PrintStream stream) {
traceFunctionDestination = stream;
}
Set the destination for output from the fn:trace() function.
By default, the destination is System.err. If a TraceListener is in use,
this is ignored, and the trace() output is sent to the TraceListener. |
public void setTreeModel(int model) {
treeModel = model;
}
Set the tree data model to use. This affects all source documents subsequently constructed using a
Builder obtained from this Controller. This includes a document built from a StreamSource or
SAXSource supplied as a parameter to the #transform method. |
public void setURIResolver(URIResolver resolver) {
userURIResolver = resolver;
if (resolver instanceof StandardURIResolver) {
((StandardURIResolver)resolver).setConfiguration(getConfiguration());
}
}
Set an object that will be used to resolve URIs used in
document(), etc. |
public void setUnparsedTextURIResolver(UnparsedTextURIResolver resolver) {
unparsedTextResolver = resolver;
}
Set an UnparsedTextURIResolver to be used to resolve URIs passed to the XSLT
unparsed-text() function. |
public void setUseDocumentProjection(PathMap pathMap) {
this.pathMap = pathMap;
}
Indicate whether document projection should be used, and supply the PathMap used to control it.
Note: this is available only under Saxon-SA. |
public void setUserData(Object key,
String name,
Object data) {
// System.err.println("setUserData " + name + " on object to " + data);
String keyVal = key.hashCode() + " " + name;
if (data==null) {
userDataTable.remove(keyVal);
} else {
userDataTable.put(keyVal, data);
}
}
Set user data associated with a key. To store user data, two objects are required:
an arbitrary object that may be regarded as the container of the data (originally, and
typically still, a node in a tree), and a name. The name serves to distingush data objects
associated with the same node by different client applications.
This method is intended primarily for internal use, though it may also be
used by advanced applications. |
public void transform(Source source,
Result result) throws TransformerException {
if (preparedStylesheet==null) {
throw new XPathException("Stylesheet has not been prepared");
}
if (!dateTimePreset) {
currentDateTime = null; // reset at start of each transformation
}
boolean close = false;
try {
NodeInfo startNode = null;
boolean wrap = true;
int validationMode = config.getSchemaValidationMode();
Source underSource = source;
if (source instanceof AugmentedSource) {
Boolean localWrap = ((AugmentedSource)source).getWrapDocument();
if (localWrap != null) {
wrap = localWrap.booleanValue();
}
close = ((AugmentedSource)source).isPleaseCloseAfterUse();
int localValidate = ((AugmentedSource)source).getSchemaValidation();
if (localValidate != Validation.DEFAULT) {
validationMode = localValidate;
}
if (validationMode == Validation.STRICT || validationMode == Validation.LAX) {
// If validation of a DOMSource or NodeInfo is requested, we must copy it, we can't wrap it
wrap = false;
}
underSource = ((AugmentedSource)source).getContainedSource();
}
Source s2 = config.getSourceResolver().resolveSource(underSource, config);
if (s2 != null) {
underSource = s2;
}
if (wrap && (underSource instanceof NodeInfo || underSource instanceof DOMSource)) {
startNode = prepareInputTree(underSource);
registerDocument(startNode.getDocumentRoot(), underSource.getSystemId());
} else if (source == null) {
if (initialTemplate == null) {
throw new XPathException("Either a source document or an initial template must be specified");
}
} else {
// The input is a SAXSource or StreamSource or AugmentedSource, or
// a DOMSource with wrap=no: build the document tree
Builder sourceBuilder = makeBuilder();
Sender sender = new Sender(sourceBuilder.getPipelineConfiguration());
Receiver r = sourceBuilder;
if (config.isStripsAllWhiteSpace() || executable.stripsWhitespace() ||
validationMode == Validation.STRICT || validationMode == Validation.LAX) {
r = makeStripper(sourceBuilder);
}
if (executable.stripsInputTypeAnnotations()) {
r = config.getAnnotationStripper(r);
}
sender.send(source, r);
if (close) {
((AugmentedSource)source).close();
}
DocumentInfo doc = (DocumentInfo)sourceBuilder.getCurrentRoot();
sourceBuilder.reset();
registerDocument(doc, source.getSystemId());
startNode = doc;
}
transformDocument(startNode, result);
} catch (TerminationException err) {
//System.err.println("Processing terminated using xsl:message");
throw err;
} catch (XPathException err) {
Throwable cause = err.getException();
if (cause != null && cause instanceof SAXParseException) {
// This generally means the error was already reported.
// But if a RuntimeException occurs in Saxon during a callback from
// the Crimson parser, Crimson wraps this in a SAXParseException without
// reporting it further.
SAXParseException spe = (SAXParseException)cause;
cause = spe.getException();
if (cause instanceof RuntimeException) {
reportFatalError(err);
}
} else {
reportFatalError(err);
}
throw err;
} finally {
if (close) {
((AugmentedSource)source).close();
}
principalResultURI = null;
}
}
Perform a transformation from a Source document to a Result document. |
public void transformDocument(NodeInfo startNode,
Result result) throws TransformerException {
// System.err.println("*** TransformDocument");
if (executable==null) {
throw new XPathException("Stylesheet has not been compiled");
}
if (getMessageEmitter() == null) {
Receiver me = makeMessageEmitter();
setMessageEmitter(me);
if (me instanceof Emitter && ((Emitter)me).getWriter()==null) {
try {
((Emitter)me).setWriter(new OutputStreamWriter(System.err));
} catch (Exception err) {
// This has been known to fail on .NET because the default encoding set for the
// .NET environment is not supported by the Java class library. So we'll try again
try {
((Emitter)me).setWriter(new OutputStreamWriter(System.err, "utf8"));
} catch (UnsupportedEncodingException e) {
throw new XPathException(e);
}
}
}
}
getMessageEmitter().open();
// Determine whether we need to close the output stream at the end. We
// do this if the Result object is a StreamResult and is supplied as a
// system ID, not as a Writer or OutputStream
boolean mustClose = (result instanceof StreamResult &&
((StreamResult)result).getOutputStream() == null);
principalResult = result;
if (principalResultURI == null) {
principalResultURI = result.getSystemId();
}
XPathContextMajor initialContext = newXPathContext();
initialContext.setOriginatingConstructType(Location.CONTROLLER);
if (startNode != null) {
initialContextItem = startNode;
contextForGlobalVariables = startNode.getRoot();
if (startNode.getConfiguration()==null) {
// must be a non-standard document implementation
throw new TransformerException("The supplied source document must be associated with a Configuration");
}
if (!startNode.getConfiguration().isCompatible(preparedStylesheet.getConfiguration())) {
throw new XPathException(
"Source document and stylesheet must use the same or compatible Configurations",
SaxonErrorCode.SXXP0004);
}
SequenceIterator currentIter = SingletonIterator.makeIterator(startNode);
if (initialTemplate != null) {
currentIter.next();
}
initialContext.setCurrentIterator(currentIter);
}
initializeController();
// In tracing/debugging mode, evaluate all the global variables first
if (traceListener != null) {
preEvaluateGlobals(initialContext);
}
Properties xslOutputProps;
if (localOutputProperties == null) {
xslOutputProps = executable.getDefaultOutputProperties();
} else {
xslOutputProps = localOutputProperties;
}
// deal with stylesheet chaining
String nextInChain = xslOutputProps.getProperty(SaxonOutputKeys.NEXT_IN_CHAIN);
if (nextInChain != null) {
String baseURI = xslOutputProps.getProperty(SaxonOutputKeys.NEXT_IN_CHAIN_BASE_URI);
result = prepareNextStylesheet(nextInChain, baseURI, result);
}
// add a property to indicate that this is the implicit result document, which
// should only be created if either it is non-empty, or no xsl:result-document has been executed
Properties props = new Properties(xslOutputProps);
props.setProperty(SaxonOutputKeys.IMPLICIT_RESULT_DOCUMENT, "yes");
initialContext.changeOutputDestination(props, result, true,
Configuration.XSLT, Validation.PRESERVE, null);
// Process the source document using the handlers that have been set up
if (initialTemplate == null) {
// SequenceIterator single = SingletonIterator.makeIterator(startNode);
// initialContext.setCurrentIterator(single);
initialContextItem = startNode;
final Mode mode = getRuleManager().getMode(initialMode, false);
if (mode == null || (initialMode != null && mode.isEmpty())) {
throw new XPathException("Requested initial mode " +
(initialMode == null ? "" : initialMode.getDisplayName()) +
" does not exist", "XTDE0045");
}
TailCall tc = ApplyTemplates.applyTemplates(
initialContext.getCurrentIterator(),
mode,
null, null, initialContext, false, 0);
while (tc != null) {
tc = tc.processLeavingTail();
}
} else {
Template t = initialTemplate;
XPathContextMajor c2 = initialContext.newContext();
initialContext.setOriginatingConstructType(Location.CONTROLLER);
c2.openStackFrame(t.getStackFrameMap());
c2.setLocalParameters(new ParameterSet());
c2.setTunnelParameters(new ParameterSet());
TailCall tc = t.expand(c2);
while (tc != null) {
tc = tc.processLeavingTail();
}
}
if (traceListener!=null) {
traceListener.close();
}
Receiver out = initialContext.getReceiver();
if (out instanceof ComplexContentOutputter && ((ComplexContentOutputter)out).contentHasBeenWritten()) {
if (principalResultURI != null) {
if (!checkUniqueOutputDestination(principalResultURI)) {
XPathException err = new XPathException(
"Cannot write more than one result document to the same URI, or write to a URI that has been read: " +
result.getSystemId());
err.setErrorCode("XTDE1490");
throw err;
} else {
addUnavailableOutputDestination(principalResultURI);
}
}
}
out.endDocument();
out.close();
getMessageEmitter().close();
if (mustClose && result instanceof StreamResult) {
OutputStream os = ((StreamResult)result).getOutputStream();
if (os != null) {
try {
os.close();
} catch (java.io.IOException err) {
throw new XPathException(err);
}
}
}
}
Transform a source XML document supplied as a tree.
This method is intended for internal use. External applications should use
the #transform method, which is part of the JAXP interface. Note that
NodeInfo implements the JAXP Source interface, so
it may be supplied directly to the transform() method. |
public static NodeInfo unravel(Source source,
Configuration config) {
return config.unravel(source);
} Deprecated! since - 9.0: use Configuration#unravel
|