So assume we have created a pipeline using the job ticket pattern, how do we get this started from the command line? It turned out that adding a “command wrapper step” made a lot of sense. Here is how this works:
The command on the command-line starts a batch/shell script that fires the XProc processor (with all the correct flags and arguments).
This starts a “command wrapper step”: an XProc step whose sole purpose is to unravel and interpret the command line.
The command wrapper step then fires the appropriate step(s) that implements the actual functionality of what we’re trying to achieve.
Why is this useful? In XProc steps you’ve written can be easily re-used. So it makes sense to keep steps that implement application logic “pure”: as unaware of the environment they’re running in as possible. Sometimes you’re using them as part of a command line tool and, maybe, sometimes in other contexts. Making them aware of things like command line arguments severely hinders re-use. So best to keep the interface of the functional steps simple using ”straight” options (booleans, strings, numbers etc.).
What would such a command-line wrapper step look like? You can of course make this is complex as you like. I used a fairly simple setup that turned out to be sufficient for my purposes:
<p:declare-step … > <p:option name="commandLine" as="xs:string"/> … <p:variable name="commandParts" as="xs:string*" select="tokenize($commandLine, '\s+')[.]"/> <p:variable name="commandFlags" as="xs:string*" select="$commandParts[starts-with(., '-')]"/> <p:variable name="commandArguments" as="xs:string*" select="$commandParts[not(starts-with(., '-'))]"/> <p:choose> <p:when test="'-help' = $commandArguments"> … (output a help text) </p:when … </p:choose> </p:declare-step>
The full, unparsed, command line is passed to the command wrapper step in the $commandLine
option.
This is tokenized into words (based on whitespace as separator) and then separated into:
Flags (anything that starts with a hyphen, for instance -help
)
Arguments (anything else)
A <p:choose>
makes decisions based on the flags/arguments present.