Re: Parameters redux

The p:http-request discussion highlighted the fact that it is currently 
impossible to use an input XML document to set the parameters on a 
transformation. If you, as the pipeline author, know the parameters on a 
stylesheet in advance, then you can access them individually to build up 
a parameter set based on values in an XML document. However, if you 
don't know them in advance then you can't create an (input) 
configuration file for your pipeline looking like:

   <my:config>
     <my:stylesheet>
       <!-- put your stylesheet URI here -->
     </my:stylesheet>
     <my:params>
       <!-- put your stylesheet parameters here, in the form -->
       <!-- <my:param name="..." value="..." /> -->
     </my:params>
   </my:config>

I can imagine a number of (unusual, but real world) processes where this 
might be useful: pipelines that perform unit tests on XSLT stylesheets, 
or run them a number of times to get performance information, or do some 
pre-processing of the stylesheet before it gets run, or do some pre- or 
post-processing of the source document before transforming with a 
user-defined stylesheet, and so on.

It wouldn't bother me if this was hard. It does bother me that it's 
impossible.

Given that this is an unusual case and the requirement for parameter 
sets is an unusual case, I wonder if they can be solved through the same 
mechanism, leaving the majority cases absolutely transparent.

Here's a possibility:

1. We introduce the concept of "parameter ports". Parameter ports are 
just like normal input ports (and are added to the set of readable 
ports), but always expect a single document that must contain a 
<c:parameters> element that contains any number of <c:parameter> 
elements with name, namespace, and value attributes. They are defined 
with a <p:input> with parameters="yes".

2. All container steps have at least one parameter port. If they don't 
specify one explicitly, they have a default parameter port named 
'parameters'.

3. We remove the concept of in-scope parameters. Instead, there is the 
concept of the "default readable parameter port", which is similar to 
the "default readable port". If there is only one parameter port 
specified (implicitly or explicitly) on a step container, that becomes 
the default readable parameter port for its contained steps.

4. The document supplied to a parameter port can be supplied explicitly 
in one of two ways:

   (a) in the normal way, through a <p:input> in the step invocation 
whose port name is that of a parameter port

   (b) constructed from <p:parameter> elements used in the step 
invocation; if there's more than one parameter port on the step then an 
optional port attribute indicates which one the parameter goes to

If no document is supplied explicitly, the source is the default 
readable parameter port.

5. We remove <p:import-parameters>.


Some examples:
--------------

A. Basic use: Henry's example:

  > [invoke pipeline impl] my.xpl debug=1 < foo.xml

my.xpl:
   <p:pipeline>
    <p:xslt>
     <p:input port="stylesheet">
      <p:inline>
       <xsl:stylesheet>
        <xsl:param name="debug">0</xsl:param>
        . . .

works because the <p:pipeline> has an (undeclared) parameter input port 
that accepts the parameter passed from the command line and creates a 
<c:parameters> document from them; that document gets passed to the 
parameter port on <p:xslt>.

B. Parameter supplied as option:

<p:pipeline>
   <p:input port="source" />
   <p:option name="debug" value="false" />
   <p:xslt>
     <p:input port="stylesheet">...</p:input>
     <p:parameter name="debug" select="$debug" />
   </p:xslt>
</p:pipeline>

Here, the parameter document on the <p:xslt> step's parameter port is 
constructed from the <p:parameter> element. If the $debug option isn't 
set it will look like:

   <c:parameters>
     <c:parameter name="debug" value="false" />
   </c:parameters>

C. Passing a subset of parameters:

<p:pipeline name="pipe">
   <p:input port="source" />
   <p:xslt>
     <p:input port="stylesheet">...</p:input>
     <p:parameter name="foo"
       select="/c:parameters/c:parameter[@name = 'foo']">
       <p:pipe step="pipe" port="parameters" />
     </p:parameter>
   </p:xslt>
</p:pipeline>

or, if you need more than one:

<p:pipeline name="pipe">
   <p:input port="source" />
   <p:viewport name="filter-parameters" match="c:parameter">
     <p:viewport-source>
       <p:pipe step="pipe" port="parameters" />
     </p:viewport-source>
     <p:matching-documents>
       <p:option name="test"
         value="/c:parameter/@name = 'foo' or
                /c:parameter/@name = 'bar'" />
     </p:matching-documents>
   </p:viewport>
   <p:xslt>
     <p:input port="source">
       <p:pipe step="pipe" port="source" />
     </p:input>
     <p:input port="stylesheet">...</p:input>
     <p:input port="parameters">
       <p:pipe step="filter-parameters" port="result" />
     </p:input>
   </p:xslt>
</p:pipeline>

D. Supplying parameters in config files:

<p:pipeline name="pipe">
   <p:input port="source" />
   <p:input port="config" />
   <p:group name="extract-parameters">
     <p:output port="result" />
     <p:rename>
       <p:input port="source" select="/my:config/my:params">
         <p:pipe step="pipe" port="config" />
       </p:input>
       <p:option name="match" value="p:params" />
       <p:option name="name" value="c:parameters" />
     <p:rename>
     <p:rename>
       <p:option name="match" value="p:param" />
       <p:option name="name" value="c:parameter" />
     <p:rename>
   </p:group>
   <p:load name="load-stylesheet">
     <p:option name="href" select="/my:config/my:stylesheet">
       <p:pipe step="pipe" port="config" />
     </p:option>
   </p:load>
   <p:xslt>
     <p:input port="source">
       <p:pipe step="pipe" port="source" />
     </p:input>
     <p:input port="stylesheet">
       <p:pipe step="load-stylesheet" port="result" />
     </p:input>
     <p:input port="parameters">
       <p:pipe step="extract-parameters" port="result" />
     </p:input>
   </p:xslt>
</p:pipeline>

£. Supplying two sets of parameters:

<p:pipeline name="pipe">
   <p:input port="source" />
   <p:input port="preprocess" />
   <p:input port="preprocess-params" parameters="yes" />
   <p:input port="postprocess" />
   <p:input port="postprocess-params" parameters="yes" />
   ...
   <p:xslt>
     <p:input port="stylesheet">
       <p:pipe step="pipe" port="preprocess" />
     </p:input>
     <p:input port="parameters">
       <p:pipe step="pipe" port="preprocess-params" />
     </p:input>
   </p:xslt>
   ...
   <p:xslt>
     <p:input port="stylesheet">
       <p:pipe step="pipe" port="postprocess" />
     </p:input>
     <p:input port="parameters">
       <p:pipe step="pipe" port="postprocess-params" />
     </p:input>
   </p:xslt>
</p:pipeline>

The advantages of this approach are that it draws on existing, familiar, 
mechanisms rather than introducing new ones, and thus is very powerful 
and flexible, but retains usability and transparency for simple cases.

Thoughts?

Jeni
-- 
Jeni Tennison
http://www.jenitennison.com

Received on Sunday, 20 May 2007 05:24:33 UTC