so

XProc tips and tricks

Volume 9, Issue 11; 21 Jul 2025

Maybe it’s time to start collecting “tips and tricks” for XProc pipelines? Perhaps I should revamp exproc.org? Tip: how can I make an empty sequence into an empty document?

Regardless of whether it’s time to start collecting “tips and tricks” or what I should do with exproc.org, I have a tip. Or a trick. Something.

Suppose you’re selecting items from a document and passing them to a step that does something with them:

<p:identity>
  <p:with-input select="/path/to/something"/>
</p:identity>

<ex:my-step-that-does-a-thing/>

If the primary input port of ex:my-step-that-does-a-thing doesn’t accept a sequence, then you’ll get an error if /path/to/something doesn’t select anything.

Suppose instead that you want to pass an empty document to the step. It’s not that difficult to imagine scenarios where that would be easier than dealing with a sequence (especially if you want to the processor to reject sequences of more than one document for you).

Here’s one way to do that:

<p:identity>
  <p:with-input select="/path/to/something"/>
</p:identity>

<p:if test="empty(collection())" collection="true">
  <p:identity>
    <p:with-input>
      <p:inline content-type="text/plain"></p:inline>
    </p:with-input>
  </p:identity>
</p:if>

<ex:my-step-that-does-a-thing/>

The semantics of p:if are that it returns the result of its subpipeline if the test expression is true and otherwise passes its inputs through unchanged. Setting collection to true means that the default collection will contain all of the documents that appeared as inputs to p:if. If that collection is empty, there were no documents.

So, if there are inputs, they are passed through unchanged, but if there aren’t any inputs, the result is a single text/plain document containing an empty text node. Obviously, you could produce something else as the default just by changing the inline.

It’s concise and useful, but it took me a good few minutes to figure it out the first time I needed it.

#XProc