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 a XsltExecutable object, and the instantiation of a stylesheet performing a single transformation by an XsltTransformer or Xslt30Transformerobject. 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 generate bytecode, 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.

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.