Document templates in XProc

Volume 13, Issue 42; 07 Nov 2010

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.

—Posted by James Sulak on 08 Nov 2010 @ 02:06 UTC #

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.

—Posted by Stefan Krause on 28 Nov 2010 @ 11:55 UTC #

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.

—Posted by Norman Walsh on 07 Dec 2010 @ 12:24 UTC #