p:xslt (3.0)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><!-- == 2025-09-03T14:56:07.530839+02: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><!-- == 2025-09-03T14:56:07.5560896+02: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.