Caching compiled stylesheets in memory

The JAXP interface represents a compiled stylesheet as a Templates object. The object contains the entire stylesheet; all modules must be compiled as a single unit. JAXP was designed before packages were added to the XSLT 3.0 language. The Templates object is thread-safe, so once created it can be used by many transformations running separately in parallel. To use the Templates object to run a transformation of a particular source document, a Transformer object is created. The Transformer is not thread-safe; its transform() method must not be called while a transformation is active. The Transformer can be serially reused, but with Saxon there is no benefit in doing so; better garbage collection generally occurs if a new Transformer is created for each transformation.

The s9api interface (Java) and Saxon.Api (C#) have a similar design: a compiled stylesheet is represented by an XsltExecutable object, and the instantiation of a stylesheet performing a single transformation by an XsltTransformer or Xslt30Transformer object. These APIs also add a third class to the design, namely the XsltCompiler, which holds compile-time options such as the base URI of the stylesheet, values of static parameters, and compile-time options such as whether to defer compilation of template rules until they are used, how to resolve references to modules (xsl:include/xsl:import), what schema definitions to use, and where to report compile-time errors. The XsltCompiler is also thread-safe, though the options in force should not be changed while the compiler is in use, and you may need to think carefully about how to capture compilation errors if several compilations are active at the same time. Different XsltCompiler instances with different option settings can run concurrently with each other.

In the SaxonC API (for C++, PHP and Python), a compiled stylesheet is also represented by an XsltExecutable object, but the API design differs to Java and C#. Methods to perform of a single transformation are provided directly on the XsltExecutable. A stylesheet is compiled to an XsltExecutable using methods on the Xslt30Processor object: compileFromString(), compileFromFile() and compileFromXdmNode() in C++; compileFromString(), compileFromFile() and compileFromValue() in PHP; and compile_stylesheet() in Python. The Xslt30Processor holds compile-time options such as the output base URI for the stylesheet, values of static parameters, etc. Compile-time errors are thrown as exceptions in C++, PHP and Python.

XSLT 3.0 packages have been supported since Saxon 9.6. A package may consist of a single module, or of a number of modules connected using xsl:include/xsl:import; a package is compiled as a unit, and may have references to other packages (via xsl:use-package) that are compiled independently. To allow independent compilation, there is much stronger control over the interfaces that a package exposes to the outside world, and over the ability of declarations in one package to override another. For example, if a function is declared to return an integer, then when compiling a call to that function, the compiler can be confident that any overriding declaration of the function will still return an integer result.

In the s9api interface (Java), a package is represented by an XsltPackage object. The XsltCompiler has a method compilePackage which returns an XsltPackage if successful. The package may be made available for use by other packages being compiled, in the same or in a different XsltCompiler, by the XsltCompiler's importPackage method. When an xsl:use-package declaration is found while compiling one package, the compiler searches for a matching package among those that have been imported by the XsltCompiler in this way. It is possible to import several different versions of the same package, and the package-version attribute of xsl:use-package determines which of them is loaded.

In the Saxon.Api interface (C#), a package is represented by an XsltPackage object. The XsltCompiler has a method CompilePackage which returns an XsltPackage if successful. The package may be made available for use by other packages being compiled, in the same or in a different XsltCompiler, by the XsltCompiler's ImportPackage method. When an xsl:use-package declaration is found while compiling one package, the compiler searches for a matching package among those that have been imported by the XsltCompiler in this way. It is possible to import several different versions of the same package, and the package-version attribute of xsl:use-package determines which of them is loaded.

The XsltPackage object, once created, is immutable and thread-safe. It is tied to a Saxon Processor, but it can be imported by multiple XsltCompiler instances. If a common library package is used by many different stylesheets, it makes sense to define it as a reusable package, since this avoids the cost of compiling the code repeatedly, and avoids the need to keep multiple copies in memory.

There is no object corresponding to XsltPackage in the SaxonC API. But a package can be exported as an stylesheet export file (SEF) which can then we imported again (see also Using packages). The Xslt30Processor has methods compileFromStringAndSave, compileFromFileAndSave and compileFromXdmNodeAndSave which exports the xsl:package to file store if successful. From 12.4, the package may be made available for use by other packages being compiled, in the same or in a different Xslt30Processor, by the Xslt30Processor's importPackage method which takes the SEF file name as argument. When an xsl:use-package declaration is found while compiling one package, the compiler searches for a matching package among those that have been imported by the Xslt30Processor in this way. It is possible to import several different versions of the same package, and the package-version attribute of xsl:use-package determines which of them is loaded.