Runs a dynamically loaded pipeline.
In using XProc, there are cases where it is useful to be able to run a dynamically loaded pipeline. The p:run
step
makes this possible. For instance:
Assume you have an XProc pipeline that processes/executes some DSL (Domain Specific Language). This language refers to XProc pipelines (by URI) that need to be executed as part of the DSL processing.
Your pipeline gets so complicated that it becomes easier to dynamically construct another pipeline and run this as part of your main pipeline.
Without p:run
, all this wouldn’t be possible. Unfortunately, because various requirements surrounding dynamic pipeline execution,
the p:run
step is very different from other steps: it has a totally different set of child elements. Therefore, the step
will be explained as if it was a separate XML element:
Child element | # | Description |
---|---|---|
| 1 | Anonymous input port that receives the pipeline to run. This is not the step’s primary port! Its attributes and child elements are similar to the standard XProc See also Details specifying the pipeline to run. |
| 1 | Element for connecting the input ports of the pipeline being run. Its attributes and child elements are similar to the standard XProc See also Details connecting input ports. |
| 1 | Element for passing options to the pipeline being run. Its attributes and child elements are similar to the standard XProc See also Details specifying options. |
| 1 | Element that declares an output port of the pipeline being run. See also Details specifying output ports. |
In handling all this, there are quite a few details involved, which are discussed in the sections below. However, in the vast majority of
cases, using p:run
is not very difficult. You may want to look at the examples before diving into the details.
The pipeline to run (the dynamically executed pipeline) must be provided on the anonymous input port of p:run
(its
“pipeline” port). This must of course be a valid XProc pipeline and it must have a version
attribute.
You connect this anonymous “pipeline” port by adding a single <p:with-input>
child element to the p:run
, without
a port
attribute. For example, assume there is a step in my pipeline, named pipeline-generating-step
, that produces
a pipeline on its primary result
port. To execute this pipeline using p:run
, I would have to write:
<p:run> <p:with-input pipe="result@pipeline-generating-step"/> … </p:run>
Take care: this anonymous “pipeline” port is not the primary port of p:run
. So you must
always connect it, even if the pipeline to run flows out of the primary output port of the step right before (in XProc
terms: even if it is the DRP, the Default Readable Port).
The <p:run-input>
element is used to connect the input ports of the dynamically executed pipeline. Its attributes and child
elements are almost similar to the standard XProc <p:with-input>
element.
For example, to connect the primary source
input port of the dynamically executed pipeline to some document on disk, you
could write:
<p:run> <p:with-input href="my-dynamic-pipeline.xpl"/> <p:run-input port="source" href="doc.xml"/> … </p:run>
There are a few things you need to keep in mind when connecting the input ports of the dynamically executed pipeline:
The additional boolean primary
attribute of <p:run-input>
can be used to declare that this port in the
dynamically executed pipeline is primary. Its default value depends:
If there is a single <p:run-input>
element, its default value is true
.
If there are multiple <p:run-input>
elements, its default value is false
.
If the primary input port of the pipeline to run is not explicitly connected to somewhere (in its <p:run-input>
element), it
gets connected to the default readable port of p:run
.
The name of the primary input port, as declared by the <p:run-input>
element of p:run
, must be the
same as the name of the primary input port of the dynamically executed step. If not, error XC0206
is
raised.
Any input ports of the dynamically executed step for which there is no corresponding <p:run-input>
element receive an empty
connection (<p:empty/>
).
Any input ports mentioned in <p:run-input>
elements that do not exist in the dynamically executed pipeline are silently
ignored.
Options for the dynamically executed pipeline can be specified using one or more <p:run-option>
elements. Its attributes and
child elements are almost similar to the standard XProc <p:with-option>
element.
There are a few additional details to reckon with:
The <p:run-option>
element has an additional boolean attribute static
, which defaults to false
.
Using static="true"
allows you to specify static options for the pipeline to run.
Any options of the dynamically executed pipeline that are not specified using <p:run-option>
are handled as expected: if they
are required, an error will be raised, and if not, their default value applies.
Any options set by <p:run-option>
that do not exist in the dynamically executed pipeline are silently ignored.
To be able to access the output ports of the dynamically executed pipeline, you have to declare these ports on the p:run
invocation
using <p:output>
elements. For example, if your dynamic pipeline has a primary result
output port and you want to access
what comes out of this port in the pipeline that does the p:run
, you must write something like:
<p:run> <p:with-input href="my-dynamic-pipeline.xpl"/> <p:output port="result" primary="true"/> … </p:run>
A few details to consider:
The <p:output>
child element of p:run
has the same definition as a normal <p:output>
element, but here it may not
establish a connection to another port/step in the pipeline. In other words: you cannot use the pipe
attribute or a child
<p:pipe>
element.
The name of the primary output port, as declared by the <p:output>
element of p:run
, must be the same
as the name of the primary output port of the dynamically executed step. If not, error XC0207
is raised.
If the dynamically executed pipeline has output ports that are not declared in <p:output>
elements of p:run
, their outputs
will be silently discarded.
If the p:run
step declares additional output ports that are not present in the dynamically executed pipeline, their outputs will be
empty (<p:empty/>
).
Suppose we have some kind of XML content in which we want to dynamically generate other content using XProc pipelines. For example:
<body> <p>Let's do some additions:</p> <ul> <li> <generate href-pipeline="add-them.xpl" a="1" b="1"/> </li> <li> <generate href-pipeline="add-them.xpl" a="7" b="3"/> </li> </ul> </body>
The <generate>
elements invokes another pipeline (named in its href-pipeline
attribute) using p:run
:
The input to these generator pipelines, on their primary source
port, is the <generate>
element itself (so it can
access any attributes/child elements).
The output of these generator pipelines, on their primary result
port, is inserted back into the original document,
replacing the <generate>
element.
For this example, we only use one generator pipeline, called add-them.xpl
. This simply adds the attributes a
and
b
and reports about this:
<p:declare-step xmlns:p="http://www.w3.org/ns/xproc" xmlns:xs="http://www.w3.org/2001/XMLSchema" version="3.0" exclude-inline-prefixes="#all"> <p:input port="source"/> <p:output port="result"/> <p:variable name="a" as="xs:integer" select="xs:integer(/*/@a)"/> <p:variable name="b" as="xs:integer" select="xs:integer(/*/@b)"/> <p:identity> <p:with-input> <p>Adding {$a} to {$b} results in {$a + $b}!</p> </p:with-input> </p:identity> </p:declare-step>
The main pipeline and its output are as follows:
<p:declare-step xmlns:p="http://www.w3.org/ns/xproc" version="3.0"> <p:input port="source"/> <p:output port="result"/> <p:viewport match="generate"> <p:run> <p:with-input href="{/*/@href-pipeline}"/> <p:run-input port="source"/> <p:output port="result"/> </p:run> </p:viewport> </p:declare-step>
Result document:
<body> <p>Let's do some additions:</p> <ul> <li> <p>Adding 1 to 1 results in 2!</p> </li> <li> <p>Adding 7 to 3 results in 10!</p> </li> </ul> </body>
Building on the Basic usage example, we’re going to add and use an option that specifies the language of the
generator output. For now this will only accept nl
for Dutch. Any other language will default to English.
The extended version of the generator pipeline, called add-them-extended.xpl
, looks like this:
<p:declare-step xmlns:p="http://www.w3.org/ns/xproc" xmlns:xs="http://www.w3.org/2001/XMLSchema" version="3.0" exclude-inline-prefixes="#all"> <p:input port="source"/> <p:output port="result"/> <p:option name="language" as="xs:string" required="true"/> <p:variable name="a" as="xs:integer" select="xs:integer(/*/@a)"/> <p:variable name="b" as="xs:integer" select="xs:integer(/*/@b)"/> <p:choose> <p:when test="$language eq 'nl'"> <p:identity> <p:with-input> <p>Als we {$a} optellen bij {$b} krijgen we {$a + $b}!</p> </p:with-input> </p:identity> </p:when> <p:otherwise> <!-- Default language is English: --> <p:identity> <p:with-input> <p>Adding {$a} to {$b} results in {$a + $b}!</p> </p:with-input> </p:identity> </p:otherwise> </p:choose> </p:declare-step>
Let’s generate a Dutch version of our output:
Source document:
<body> <p>Laten we optellen:</p> <ul> <li> <generate href-pipeline="add-them-extended.xpl" a="1" b="1"/> </li> <li> <generate href-pipeline="add-them-extended.xpl" a="7" b="3"/> </li> </ul> </body>
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:viewport match="generate"> <p:run> <p:with-input href="{/*/@href-pipeline}"/> <p:run-input port="source"/> <p:run-option name="language" select="'nl'"/> <p:output port="result"/> </p:run> </p:viewport> </p:declare-step>
Result document:
<body> <p>Laten we optellen:</p> <ul> <li> <p>Als we 1 optellen bij 1 krijgen we 2!</p> </li> <li> <p>Als we 7 optellen bij 3 krijgen we 10!</p> </li> </ul> </body>
What happens with any document-properties depends entirely on how the dynamically executed pipeline handles these.
Error code | Description |
---|---|
It is a dynamic error if the pipeline input to the p:run step is not a valid pipeline. | |
It is a dynamic error if the dynamically executed pipeline implicitly or explicitly declares a primary input port with a different name than implicitly or explicitly specified in the p:run invocation. | |
It is a dynamic error if the dynamically executed pipeline implicitly or explicitly declares a primary output port with a different name than implicitly or explicitly specified in the p:run invocation. |
This description of the p:run
step is for XProc version: 3.0. This is a non-required step (an XProc 3.0 processor does not have to support this).
The formal specification for the p:run
step can be found here.
The p:run
step is part of category: XProc dynamic pipeline execution steps.
The p:run
step is also present in version:
3.1.