Error Handling With <p:try/>
There are various exceptions that can cause a pipeline to fail: a document failed to load, a schema validation fails, or the output generated by one step does not match the input requirements of the following step. You can also intentionally crash a pipeline with the p:error step. If you want to catch these errors and continue the pipeline, you can help yourself with p:try.
Like other programming languages, XProc offers a try/catch/finally method:
(1) The p:try contains an initial subpipeline wrapped in a p:group. In case there are no errors, the outputs of that pipeline are the outputs of the p:try step.
(2) If any errors occur and there is a p:catch branch, this subpipeline is executed and becomes the output of p:try. If there are multiple p:catch branches, all but the last p:catch must contain an @error attribute in order the appropriate error branch could be selected for the given error code. In case there is no p:catch that matches the error code, the last p:catch is evaluated.
(3) However, if there is a p:finally available, this subpipeline will be executed regardless whether the initial pipeline or the p:catch succeeds or fails. p:finally must not yield any outputs because its considered for clean-up tasks that should not interfere with the outputs of either the initial subpipeline or the p:catch branch.
The pipeline below includes a p:error step causing the initial pipeline to fail. Then the p:catch branch is executed which just generates an error message. After the catch-branch, the p:finally is started that includes a step without an output port.
<?xml version="1.0" encoding="UTF-8"?>
<p:declare-step xmlns:p="http://www.w3.org/ns/xproc" version="3.0">
<p:input port="source">
<p:inline>
<doc>Hello XPorc!</doc>
</p:inline>
</p:input>
<p:output port="result"/>
<p:try>
<p:group>
<p:error code="error-raised-by-myself"/>
</p:group>
<p:catch>
<p:identity>
<p:with-input>
<p:inline>
<err>An error occurred!</err>
</p:inline>
</p:with-input>
</p:identity>
</p:catch>
<p:finally>
<p:sink name="do-nothing"/>
</p:finally>
</p:try>
</p:declare-step>
Output
<?xml version="1.0" encoding="UTF-8"?> <err>An error occurred!</err>
The Error Port
The p:catch has an input port named error. Errors produced by steps are passed as messages to this port and can be used as input to steps within p:catch. In the example below, we pipe the error message to the output, which can be useful for displaying the errors to the user later.
<?xml version="1.0" encoding="UTF-8"?>
<p:declare-step xmlns:p="http://www.w3.org/ns/xproc" version="3.0">
<p:output port="result"/>
<p:try>
<p:group>
<p:load href="this-should-be-the-path/my-file.xml"/>
</p:group>
<p:catch name="my-catch">
<p:identity>
<p:with-input pipe="error@my-catch"/>
</p:identity>
</p:catch>
</p:try>
</p:declare-step>
Output
<?xml version="1.0" encoding="UTF-8"?>
<c:errors xmlns:c="http://www.w3.org/ns/xproc-step">
<c:error code="err:XD0011"
href="my-pipeline.xpl"
line="9" column="59" xmlns:err="http://www.w3.org/ns/xproc-error">
Error while loading. Resource not found:
C:\this-should-be-the-path\my-file.xml
</c:error>
</c:errors>