Invoke an XSLT stylesheet.
<p:declare-step type="p:xslt"> <input port="source" primary="true" content-types="any" sequence="true"/> <output port="result" primary="true" content-types="any" sequence="true"/> <input port="stylesheet" primary="false" content-types="xml" sequence="false"/> <output port="secondary" primary="false" content-types="any" sequence="true"/> <option name="global-context-item" as="item()?" required="false" select="()"/> <option name="initial-mode" as="xs:QName?" required="false" select="()"/> <option name="output-base-uri" as="xs:anyURI?" required="false" select="()"/> <option name="parameters" as="map(xs:QName,item()*)?" required="false" select="()"/> <option name="populate-default-collection" as="xs:boolean?" required="false" select="true()"/> <option name="static-parameters" as="map(xs:QName,item()*)?" required="false" select="()"/> <option name="template-name" as="xs:QName?" required="false" select="()"/> <option name="version" as="xs:string?" required="false" select="()"/> </p:declare-step>
The p:xslt
step invokes the XSLT stylesheet that appears on the stylesheet
port. What exactly happens depends on the XSLT
version used.
Ports:
Port | Type | Primary? | Content types | Seq? | Description |
---|---|---|---|---|---|
|
|
|
|
| The source document(s) to transform. What exactly happens with these documents depends on the XSLT stylesheet version. See below. |
|
|
|
|
| The principal resulting document(s) of the transformation. |
|
|
|
|
| The XSLT stylesheet to invoke. |
|
|
|
|
| Any secondary documents created by the transformation. Starting with XSLT version 2.0, you can use the XSLT |
Options:
The p:xslt
step invokes the XSLT stylesheet that appears on the stylesheet
port. What is used as input, how the XSLT
processing starts and where/how the results appear depends on the XSLT version used. This is explained in the sections below.
Because of all the details, invoking the p:xslt
step seems complicated. However, presumably, in the vast majority of cases it will be used
in a classical manner: invoke an XSLT stylesheet on a source document and continue the pipeline using its result. Maybe with some parameters,
maybe with some secondary results. For this, have a look at the Basic usage and Basic usage with secondary documents
examples and don’t let all the details overwhelm you.
Specifying the XSLT version is important but, in most cases, rather simple: most likely the version as specified on the XSLT stylesheet root
element (the xsl:stylesheet/@version
or xsl:transform/@version
attribute) is used. Since such a version attribute is
required anyway, there usually won’t be anything special you need to do. However, if you want you can set the version explicitly using
the version
option.
If the stylesheet version is determined as 3.0, the following happens:
The parameters as set by the static-parameters
option are passed to the stylesheet invocation as values for its
static parameters.
An XSLT version 3.0 stylesheet has a global context item, the data the stylesheet works upon. This is determined as follows:
If the global-context-item
option is set, this becomes the global context item.
If the global-context-item
option is not set and a single document
appears on the source
port, this will become the global context item.
If the global-context-item
option is not set and none or multiple
documents appear on the source
port, the global context item is absent/empty.
If the populate-default-collection
is set to true
, all documents that appear on the source
port become the default collection, accessible using the XPath collection() function.
Then it is determined how to start the stylesheet processing:
If the template-name
is not set, the normal “apply-template invocation” is
performed. The document(s) that appear on the source
port are used, one by one, for the initial match.
If the initial-mode
option is set, processing starts in that mode.
If the template-name
is set, the named template with that name (<xsl:template name="…">
) is
invoked.
The initial-mode
option is ignored.
The stylesheet processes.
The result(s) appears on the output port(s):
All principal results of the stylesheet appear on the result
port.
Any results created by <xsl:result-document>
instructions appear on the secondary
port.
Finally, the base URIs of the resulting documents (their base-uri
document-property values) are determined. For
this we first need to determine the base-output-URI:
If the base-output-uri
option is set, this value is used as base-output-URI.
If the base-output-uri
option is not set and there are documents on the
source
port, the base URI of the first document on the source
port is used as base
output URI.
If the base-output-uri
option is not set and there are
no documents on the source
port, the base URI of the stylesheet is used as base-output-URI.
The base URIs of the resulting documents (their base-uri
document-property values) are now computed using this
base-output-URI:
The base URI of the principal output document(s) becomes the base-output-URI. This means that when there are multiple principal documents, they all have the same base URI!
For all documents appearing on the secondary
port, the base URI is determined by the
xsl:result-document/@href
attribute. A relative value is made absolute against the base-output-URI.
If the stylesheet version is determined as 3.0, the following happens:
The following options are ignored: static-parameters
, global-context-item
.
An XSLT version 2.0 stylesheet has an initial context node, the initial data the stylesheet works upon. This is determined as follows:
When no documents appear on the source
port, the initial context node is undefined/empty.
When one or multiple documents appear on the source
port, only the first document becomes the
initial context node.
If the populate-default-collection
is set to true
, all documents that appear on the source
port become the default collection, accessible using the XPath collection() function.
Then it is determined how to start the stylesheet processing:
If the template-name
is not set, the normal “apply-template invocation” is
performed. The document(s) that appear on the source
port are used, one by one, for the initial match.
If the initial-mode
option is set, processing starts in that mode.
If the template-name
is set, the named template with that name (<xsl:template name="…">
) is
invoked.
The initial-mode
option is ignored.
The stylesheet processes.
The result(s) appears on the output port(s):
The principal result document of the stylesheet appears on the result
port.
Any results created by <xsl:result-document>
instructions appear on the secondary
port.
Finally, the base URIs of the resulting documents (their base-uri
document-property values) are determined. For
this we first need to determine the base-output-URI:
If the base-output-uri
option is set, this value is used as base-output-URI.
If the base-output-uri
option is not set and there are documents on the
source
port, the base URI of the first document on the source
port is used as base
output URI.
If the base-output-uri
option is not set and there are
no documents on the source
port, the base URI of the stylesheet is used as base-output-URI.
The base URIs of the resulting documents (their base-uri
document-property values) are now computed using this
base-output-URI:
The base URI of the principal output document becomes the base-output-URI.
For all documents appearing on the secondary
port, the base URI is determined by the
xsl:result-document/@href
attribute. A relative value is made absolute against the base-output-URI.
If the stylesheet version is determined as 1.0, the following happens:
The following options are ignored: global-context-item
, initial-mode
,
populate-default-collection
, static-parameters
, template-name
.
There must be exactly one document appearing on the source
port. This document will be processed.
The stylesheet processes.
The resulting document appears on the result
port. The secondary
port will always be empty.
Finally, the base URI of the resulting document (its base-uri
document-property value) is determined. For this we
first need to determine the base-output-URI:
If the base-output-uri
option is set, this value is used as base-output-URI.
If the base-output-uri
option is not set, the base URI of the first
document on the source
port is used as base-output-URI.
The base URI of the output document becomes the base-output-URI.
For the following example, we’ll use a very simple (3.0) stylesheet, called add-comment.xsl
, that adds a comment as the
first child of the root element:
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" expand-text="true"> <xsl:mode on-no-match="shallow-copy"/> <xsl:param name="comment-text" as="xs:string" required="false" select="'This is an added comment'"/> <xsl:template match="/*"> <xsl:copy> <xsl:apply-templates select="@*"/> <xsl:comment> == {current-dateTime()} - {$comment-text} == </xsl:comment> <xsl:apply-templates/> </xsl:copy> </xsl:template> </xsl:stylesheet>
Running this without any bells and whistles is as follows:
Source document:
<customers> <customer> <name>PXSLT Company Ltd</name> </customer> </customers>
Pipeline document:
<p:declare-step xmlns:p="http://www.w3.org/ns/xproc" version="3.0"> <p:input port="source"/> <p:output port="result"/> <p:xslt> <p:with-input port="stylesheet" href="add-comment.xsl"/> </p:xslt> </p:declare-step>
Result document:
<customers><!-- == 2024-12-02T13:40:21.0310538+01:00 - This is an added comment == --> <customer> <name>PXSLT Company Ltd</name> </customer> </customers>
Setting a stylesheet parameter is done by supplying a map with parameter name/value pairs as the value of the
parameters
option:
<p:declare-step xmlns:p="http://www.w3.org/ns/xproc" version="3.0"> <p:input port="source"/> <p:output port="result"/> <p:xslt parameters="map{'comment-text': 'Special comment text by parameter!'}"> <p:with-input port="stylesheet" href="add-comment.xsl"/> </p:xslt> </p:declare-step>
Result document:
<customers><!-- == 2024-12-02T13:40:21.0878627+01:00 - Special comment text by parameter! == --> <customer> <name>PXSLT Company Ltd</name> </customer> </customers>
The output of <xsl:result-document>
stylesheet instructions is written to the secondary
port of the p:xslt
invocation. The base URI of these documents is the value of the xsl:result-document/@href
attribute.
The following stylesheet, called split-documents.xsl
, writes the contents of each <document>
element to a separate,
secondary, document. The base URI of the output documents is inferred from the document/@name
attribute. The primary output of the
stylesheet is almost identical to its input: the full URI of each written secondary output document is added to the <document>
element
in an href
attribute.
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" expand-text="true"> <xsl:mode on-no-match="shallow-copy"/> <xsl:template match="document"> <xsl:variable name="href" as="xs:string" select="resolve-uri('tmp/' || @name)"/> <xsl:result-document href="{$href}"> <xsl:sequence select="*"/> </xsl:result-document> <xsl:copy> <xsl:copy-of select="@*"/> <xsl:attribute name="href" select="$href"/> <xsl:apply-templates/> </xsl:copy> </xsl:template> </xsl:stylesheet>
When using this stylesheet in an XProc pipeline, the documents, written by <xsl:result-document>
instructions, end up on the
secondary
port. If we want these written to disk, we need to add some code for it.
Source document:
<documents> <document name="x1.xml"> <document-1/> </document> <document name="x2.xml"> <document-2/> </document> </documents>
Pipeline document:
<p:declare-step xmlns:p="http://www.w3.org/ns/xproc" version="3.0"> <p:input port="source"/> <p:output port="result" pipe="result@create-secondary-documents"/> <p:xslt name="create-secondary-documents"> <p:with-input port="stylesheet" href="split-documents.xsl"/> </p:xslt> <p:for-each> <p:with-input pipe="secondary"/> <p:store href="{base-uri(/)}"/> </p:for-each> </p:declare-step>
Result document:
<documents> <document name="x1.xml" href="file:/…/…/tmp/x1.xml"> <document-1/> </document> <document name="x2.xml" href="file:/…/…/tmp/x2.xml"> <document-2/> </document> </documents>
The primary output of the p:xslt
is explicitly piped to the output port of the pipeline here (by the p:output/@pipe
attribute).
The p:for-each
after the p:xslt
iterates over all secondary documents and invokes p:store
to store them to
disk, using their base URI, that was set by the stylesheet. The result will be two documents, called x1.xml
and
x2.xml
, in the tmp/
folder underneath the stylesheet location.
Which XSLT version(s) is/are supported is implementation-defined and therefore depends on the XProc processor used. In most cases at least version 3.0 will be supported.
No document-properties from the source document(s) are preserved.
The base-uri
document of each result document (both for the result
and the secondary
port) is
determined by the transformation. If the transformation does not establish a base URI, the document will not have a
base-uri
document-property.
If the template-name
option is set, the initial-mode
option is ignored.
A relative value for the output-base-uri
option is made absolute against the base URI of the element in the pipeline it is
specified on. In most cases this will be the path of the pipeline document.
An XSLT stylesheet can terminate processing using an <xsl:message terminate="true">
instruction. How such a termination is reported
by the XProc processor is implementation-defined and therefore depends on the XProc processor used.
The order in which result documents appear on the secondary
port is implementation-defined and therefore depends on the XProc
processor used.
Error code | Description |
---|---|
It is a dynamic error if any key in | |
It is a dynamic error if the stylesheet does not support a given mode. | |
It is a dynamic error if the specified xslt version is not available. | |
It is a dynamic error if the source port does not contain exactly one XML document or one HTML document if XSLT 1.0 is used. | |
It is a dynamic error if the stylesheet does not provide a given template. | |
It is a dynamic error if a static error occurs during the static analysis of the XSLT stylesheet. | |
It is a dynamic error if any document supplied on the source port is not an XML document, an HTML documents, or a Text document if XSLT 2.0 is used. | |
It is a dynamic error if an error occurred during the transformation. | |
It is a dynamic error if the transformation is terminated by XSLT message termination. | |
It is a dynamic error if an XSLT 1.0 stylesheet is invoked and option | |
It is a dynamic error if a document appearing on the |
This description of the p:xslt
step is for XProc version: 3.0. This is a required step (an XProc 3.0 processor must support this).
The formal specification for the p:xslt
step can be found here.
The p:xslt
step is part of categories:
The p:xslt
step is also present in version:
3.1.