Using packages
A package, once compiled into an XsltPackage
object, can be saved as a
stylesheet export file (SEF) using the save()
(Java) or Save()
(C#)
method of the XsltPackage
. The generated file is intended to be used for one purpose
only, namely for reconstituting the XsltPackage
at a different time and place.
The format is XML, but its interpretation is not published and should not be considered
stable. The file contains a checksum and cannot be loaded in the event of a checksum
failure, so modifications to the content are not permitted. The content of the file is
sufficiently far removed from the original source that distributing code in this form
achieves a useful level of IP protection, though like Java bytecode, it is not intended to
resist determined attempts at reverse engineering. Indeed, in the interests of run-time
diagnostics, it preserves information such as variable names and line numbers that are not
strictly needed at execution time.
There is no object corresponding to XsltPackage
in the SaxonC
API, but a package can be exported and saved as a stylesheet export file (SEF) using
methods on Xslt30Processor
(e.g. compileFromStringAndSave
,
compileFromFileAndSave
and compileFromXdmNodeAndSave
in C++).
The simplest way to generate an export file is from the command line, for example with Saxon-EE 12.0:
java -jar dir/saxon-ee-12.0.jar -xsl:stylesheet.xsl -export:stylesheet.sef -nogodotnet SaxonCS transform -xsl:stylesheet.xsl -export:stylesheet.sef -nogo./transform -xsl:stylesheet.xsl -export:stylesheet.sef -nogoHere, the option -nogo
suppresses any attempt to execute the stylesheet.
Additionally, the -relocate:on
option can be used to produce an export package
which can be deployed to a different location, with a different base URI.
The -target
option can be used to specify the edition of Saxon which will be used
to run the stylesheet export file. The accepted values are EE|PE|HE|JS
, and the
default is EE
. For instance, specify -target:HE
to produce an
export file which can be executed by Saxon-HE (this will suppress the generation of optimized
constructs that SaxonJ-HE cannot execute). The option -target:JS
is used when
generating stylesheets to be executed by SaxonJS (in the browser, or on Node.js); in this case
the SEF file is in JSON format rather than XML.
A stylesheet export file for a complete stylesheet (as distinct from a library package) is accepted by any Saxon interface that accepts a source stylesheet. For example, from the command line:
java -jar dir/saxon-ee-12.0.jar -xsl:stylesheet.sef -s:source.xmldotnet SaxonCS transform -xsl:stylesheet.sef -s:source.xml./transform -xsl:stylesheet.sef -s:source.xmlWhen exporting a package, all components (templates, functions, etc) from the packages it uses are also exported. It is possible therefore either to export an individual library package (typically having no dependencies on other packages), or a complete stylesheet (a package together with its tree of dependencies).
Packages that are used by a stylesheet can be identified in a number of ways.
They can be listed on the command line in the -pack
option, or
imported to the XsltCompiler
API in Java and C# using the methods
loadLibraryPackage
and loadExecutablePackage
(Java),
or LoadLibraryPackage
and LoadExecutablePackage
(C#).
Another option, probably the best option if many library packages are used, is to list
them in a configuration file.
From SaxonC 12.4, packages can be imported to the
Xslt30Processor
API using the importPackage
method
(import_package
in Python).
In the case of schema-aware stylesheets, the schema components needed by a stylesheet are not exported along with the stylesheet code. The user of the stylesheet needs to import the required schemas before the stylesheets can be loaded. The schema loaded at execution time must match the schema used when the stylesheet was compiled. Saxon is not draconian about checking this, and many minor changes will cause no trouble (for example, changing the regular expression used in a pattern facet). Structural changes that invalidate the assumptions made during XSLT compilation, however, are likely to cause execution to fail, not necessarily in predictable ways.
The computer on which the stylesheet is executed needs to have a Saxon license of sufficient capability to meet the requirements of the stylesheet. There are two ways this can be achieved. Either the run-time system can have a conventional Saxon license installed in the normal way, or it can take advantage of a license embedded within the exported stylesheet itself. Saxonica offers developers the option of purchasing a "developer master key" which, if installed, will cause all exported stylesheets to contain an embedded license key sufficient to execute the stylesheet in question. An embedded license key applies only to that stylesheet and cannot be used for any other code developed elsewhere; stylesheets that are exported with an embedded license can only be executed "as is", and cannot be incorporated as libraries into larger applications.
Exporting stylesheet packages requires Saxon-EE, optionally with the Developer Master Key if stylesheets with embedded license information are to be exported. From Saxon 9.9 (or from 11.1 for SaxonC), importing stylesheet packages is possible using any Saxon edition, provided that the run-time software and the run-time license key (where needed) support the features used by the stylesheet in question.
There are a small number of cases where a valid stylesheet cannot be exported; but they are rarely encountered in practice. Many of the restrictions relate to static global variables (or parameters). A stylesheet cannot be exported if it contains static global variables that are bound to:
- Functions defined in XQuery, for example, a variable initialized using
fn:load-query-module()
(this is because Saxon cannot export functions containing XQuery-specific constructs such as general FLWOR expressions) - Function items returned from
another stylesheet invoked by calling
fn:transform()
- External Java objects
Where a stylesheet being exported contains static variables bound to nodes, the nodes will be reconstructed on import. The reconstructed nodes will be parentless, and will lose their inter-node relationships. For example if the value of such a variable contains a sequence of ten elements that are siblings of each other, the reconstructed element nodes will not be siblings of each other (they will be parentless).