Document templates in XProc
Exploring how to make XProc a little easier to use, at TPAC2010, the XProc WG decided to add a couple of new (optional) steps.
It's quite common in XProc
to construct documents using values computed by the pipeline.
This is particularly (but not exclusively) the case when the pipeline
uses the p:http-request
step. The input to
p:http-request
is a c:request
document;
attributes on the c:request
element control most of the request parameters; the
body of the document forms the body of the request (if the request has a body).
A typical c:request
element example looks like this:
<c:request method="POST" href="http://example.com/post"
username="user" password="password">
<c:body>
<computed-content/>
</c:body>
</c:request>
If we assume that the href
value and the computed
content come from an input document, and the username and password are pipeline options,
then a
typical pipeline to compute the request is quite complex:
<p:pipeline xmlns:p="http://www.w3.org/ns/xproc"
xmlns:c="http://www.w3.org/ns/xproc-step"
name="main" version="1.0">
<p:option name="username" required="true"/>
<p:option name="password" required="true"/>
<p:identity>
<p:input port="source">
<p:inline>
<c:request method="POST"/>
</p:inline>
</p:input>
</p:identity>
<p:add-attribute match="/c:request" attribute-name="href">
<p:with-option name="attribute-value" select="/doc/request/@uri">
<p:pipe step="main" port="source"/>
</p:with-option>
</p:add-attribute>
<p:add-attribute match="/c:request" attribute-name="username">
<p:with-option name="attribute-value" select="$username"/>
</p:add-attribute>
<p:add-attribute match="/c:request" attribute-name="password">
<p:with-option name="attribute-value" select="$password"/>
</p:add-attribute>
<p:insert position="first-child" match="/c:request">
<p:input port="insertion" select="/doc/request">
<p:pipe step="main" port="source"/>
</p:input>
</p:insert>
<p:unwrap match="/c:request/request"/>
</p:pipeline>
There's nothing wrong with this pipeline, but it requires several steps to accomplish what the pipeline author probably considers a single operation. What's more, on casual inspection, it's not even immediately obvious what these steps do.
There have been a few proposals to improve the situation, but the ones that seemed to have the greatest benefit also had the distinct disadvantage of not being compatible with the XProc 1.0 syntax.
At the XProc face-to-face meeting at TPAC 2010, I had fairly low expectations of solving the problem, so I'm delighted with how successful I think we were.
In order to make the simple construction case described above both literally
and conceptually simpler, we're going to introduce two new XProc steps:
p:in-scope-names
and p:document-template
.
Support for these steps is optional, but we'll strongly encourage
implementors to provide them. Taken together, they greatly simplify
the pipeline:
<p:pipeline xmlns:p="http://www.w3.org/ns/xproc"
xmlns:c="http://www.w3.org/ns/xproc-step"
name="main" version="1.0">
<p:option name="username" required="true"/>
<p:option name="password" required="true"/>
<p:in-scope-names name="vars"/>
<p:document-template>
<p:input port="template">
<p:inline>
<c:request method="POST" href="{/doc/request/@uri}"
username="{$username}" password="{$password}">
{ /doc/request/node() }
</c:request>
</p:inline>
</p:input>
<p:input port="source">
<p:pipe step="main" port="source"/>
</p:input>
<p:input port="parameters">
<p:pipe step="vars" port="result"/>
</p:input>
</p:document-template>
</p:pipeline>
The p:in-scope-names
step provides all of the in-scope options and variables
in a c:param-set
(this operation is exactly analagous to what the
p:parameters
step does, except that it operates on the options and variables instead
of on parameters).
The p:document-template
step searches for XPath
expressions, delimited by curly braces, in a template document and replaces each with
the
result of evaluating the expression. All of the parameters passed to the
p:document-template
step are available as in-scope variable names when evaluating
each XPath expression.
Where the expressions occur in attribute values, their string value is used. Where they appear in text content, their node values are used.
All in all, simpler and more straightforward. Not quite as simple as some of the more radical proposals, but entirely compatible with the current syntax.
The working group will publish a note shortly with the details. In the meantime, I've implemented these steps in XML Calabash.
Comments
That looks great! It should make things a lot simpler.
(and it looks similar in concept to a "resolve-placeholders" step I used in the exist xproc library. :) I'll have to update that to use the new steps.
Should'nt these steps be registered under http://exproc.org/proposed/steps/? It is hard to get a start with xproc, and any cross reference would be helpfull in gathering information.
They're going to be published as a W3C Note, but linking from exproc.org is a good idea. I'll put that on my list.