XSLT transformations from C#
You can perform a transformation using the C#
Saxon.Api interface as follows
(the same classes can also be used, of course, from other languages supported on .NET,
but the description here is oriented to C#):
Create a Processor and set any global configuration options on thevar processor = new Processor();
Processor. It is recommended to create a single
Processorfor the entire application.
Callvar compiler = processor.NewXsltCompiler();
NewXsltCompiler()to create an XsltCompiler object, and set any options that are local to a specific compilation (for example, the destination of error messages).
Decide how you want to handle compile-time errors. Some options are:
If your application will only be used to execute stylesheets that have been thoroughly tested elsewhere (for example, in a development environment such as Oxygen), then you can simply rely on the exception thrown by the compiler if an error occurs. However, the exception won't contain detailed diagnostics to say what is wrong.
If your application runs from the command line, then in normal circumstances any error messages will be written to the console, and no special action is needed.
If however the application runs in a web server, or within a GUI framework, then you will need to think about where to direct the error messages. For example, you could send them to a log file, or you could display them on screen. Either way, you will want to register an ErrorReporter that deals with the messages. For example, you could capture the messages in a list (for later analysis) like this:compiler.ErrorReporter = err => errorList.Add(err)
Or you could send them to a log file like this:compiler.ErrorReporter = err => Console.Error.WriteLine(err.Message)
The error object that is passed to the
ErrorReporterdelegate is not an exception (it cannot be thrown). It is an object of class Error, and its main properties are:
Message: an error message
ErrorCode: the error code
Location: the location in the stylesheet where the error was detected
IsWarning: distinguishes warnings from fatal error conditions
Call thevar executable = compiler.Compile(...)
Compile()method to compile a stylesheet. The result is an XsltExecutable, which can be used as often as you like, in the same thread or in different threads.
This method has a number of overloads, allowing the stylesheet to be supplied in different ways. It can be supplied as a URI, as a
Stream, as a
TextReader, or as an
Except for trivial stylesheets containing a single module, it's important that the stylesheet should have a known base URI. The base URI is used at compile time for resolving any relative URI reference appearing in an
xsl:importdeclaration; it's also used at run-time when calling functions such as
json-doc(). You can supply a base URI either by setting the
BaseUriproperty on the
XsltCompiler, or as an (implicit or explicit) parameter on the call to the
Compiling a stylesheet can often be an expensive process in comparison with the actual execution (especially when the stylesheet is large and the source document is small). It's therefore desirable to reuse the
XsltExecutablefor multiple transformations where possible. Once created, the
XsltExecutableis read-only and thread-safe.
Either of these can be used to run the transformation (regardless of which XSLT version you are using), but they have different capabilities:
The XsltTransformer is geared towards the traditional way of running an XSLT transformation, by supplying a principal source document as input. When you call the
Run()method, the template rule that best matches this source document is located and executed.
The input document is supplied as a
Stream(containing lexical XML), using the method
SetInputStream. This method also expects a URI, which is used as the base URI of the source document in case it contains relative references to other documents.
The destination for the result is supplied as the argument to the
Run()method. This can be any implementation of the interface IDestination; the most common destinations are Serializer (which causes the transformation output to be serialized, typically as XML or HTML), and XdmDestination which delivers the result as an XDM node tree. (Read the
xdmDestination.XdmNodeproperty on completion to access the root of the tree.)
Options for serializing the result can be set either on the
Serializerobject, or using
<xsl:output>declarations in the stylesheet. Options set via the API take precedence.
Another option is to send the result of a transformation to another
XsltTransformer. The class
IDestinationinterface, so the output of one transformation can form the input to another, making it easy to construct a pipeline of transformations.
XsltTransformeralso allows you to start executing the stylesheet with a named template as the entry point. In this case there will not necessarily be a source document, though you can still supply one, and it will be used as the context item for global variables.
You can use methods on the
XsltTransformerto set values for global stylesheet parameters, but not for parameters declared at the level of a particular
Typical usage:var transformer = executable.Load(); transformer.SetInputStream(...); transformer.SetParameter(new QName("debug"), new XdmAtomicValue(true)); var writer = new StringWriter(); var serializer = processor.NewSerializer(writer); serializer.SetOutputProperty(Serializer.INDENT, "yes"); transformer.Run(serializer); Console.WriteLine(writer.ToString());
The Xslt30Transformer class was a later introduction, and as its name suggests, it provides new ways of executing stylesheet code that are defined in the XSLT 3.0 specification, though Saxon also allows you to use the same entry points with 1.0 or 2.0 stylesheets. Among the new capabilities are:
- You can invoke a specific stylesheet function, with parameters, rather than invoking a named template or template rule.
- If you start execution with a named template or template rule, you can supply values for the parameters defined on that template, as well as the global stylesheet parameters.
- Whether you execute a template or a function, you can return the results in raw form rather than wrapping them in a result tree. For example, a function (or template) might return a sequence of strings, or a single boolean, or a map, or even a function.
- There is no longer any necessary relationship between the "principal source document" (if it still exists) and the context item for evaluating global variables. The two things are quite independent of each other.
Xslt30Transformerdoes not implement the
IDestinationinterface so it is not quite as convenient as
XsltTransformerwhen constructing a pipeline.
Xslt30Transformercan be serially reused, but they must not be shared across multiple threads. Both allow you to set any options required for the specific transformation: for example, the global context item, the stylesheet parameters, and callbacks for resolving URIs used in functions such as
Examples of Saxon.Api transformations are included in the
download file, see the sample application Examples.cs, and API examples for .NET for more information.
Examples.cs runs as follows: