Streaming using XSLT 3.0

Saxon-EE (from Saxon 9.8) is fully conformant to the final XSLT 3.0 recommendation in terms of the streaming facilities it supports. A few gaps in coverage that were found after release were fixed for Saxon 9.9. There are also some extensions.

There are two main ways to initiate a streaming transformation:

  1. Using the xsl:source-document instruction, with the attribute streamable="yes". Here the source document is identified within the stylesheet itself. Typically such a stylesheet will have a named template as its entry point, and will not have any principal source document supplied externally.

  2. By supplying a source document as input to a stylesheet whose initial mode is declared with streamable="yes" in an xsl:mode declaration. In this case the source document must be supplied as a stream, and not as an in-memory tree. The details depend on which API is being used:

    • With the Java s9api API, compile the stylesheet to create an XsltExecutable, and then use the load30 method to create an Xslt30Transformer. Invoke the streamed transformation using the applyTemplates method of the Xslt30Transformer, supplying the input as a StreamSource or SAXSource.

    • Similarly with the Saxon.Api interface on .NET, use the method Xslt30Transformer.ApplyTemplates(), supplying a Stream as input.

    • With the JAXP API, start by instantiating a com.saxonica.config.StreamingTransformerFactory. Invoke the transformation in the usual way by creating a Transformer (optionally via a Templates object). When the transform() method is called with a StreamSource or SAXSource as input, and when the initial mode is a streamable mode, the input will be streamed. In consequence, this approach breaks the normal JAXP convention whereby the document supplied as the Source argument to the transform() method also becomes the global context item (the value of "." when accessed within the initializer of a global variable). Instead such a reference fails with an XPDY0002 dynamic error.

      The StreamingTransformerFactory can also be used to create an XMLFilter which takes streamed input and produces streamed output, and a pipeline can be built from a sequence of such filters connected end-to-end in the usual JAXP way.

The saxon:stream extension function used in previous releases is still supported for the time being. In Saxon 9.8 and later a call on saxon:stream is translated at compile time into a call on the XSLT 3.0 <xsl:source-document> instruction. The original Saxon mechanism for streaming, namely the saxon:read-once attribute on xsl:copy-of, was dropped in Saxon 9.6.

The rules for whether a construct is streamable or not are largely the same in Saxon as in the XSLT 3.0 specification. Saxon applies these rules after doing any optimization re-writes, so some constructs end up being streamable in Saxon even though they are not guaranteed streamable in the W3C spec, because the Saxon optimizer rewrites the expression into a streamable form. An example of this effect is where variables or functions are inlined before doing the streamability analysis. In contrast, when streaming is requested, the optimizer takes care to avoid rewriting streamable constructs into a non-streamable form.

This documentation does not attempt to provide a tutorial introduction to the streaming capabilities of XSLT 3.0. The specification itself is not easy to read, especially the detailed rules on which constructs are deemed streamable. However, for the most part it is not necessary to be familiar with the detailed rules. The main things to remember are:

The XSLT 3.0 constructs most relevant to streaming are:

All these facilities are available in Saxon-EE only.