- From: Jeni Tennison <jeni@jenitennison.com>
- Date: Mon, 24 Jul 2006 12:38:48 +0100
- To: public-xml-processing-model-wg@w3.org
Norm Walsh wrote:
> A for-each looks like:
> 
>   for-each := ($over, $select?, $label, with-output, {body})
> 
> Where $over identifies a stream over which the XPath expression in
> $select should be applied. The body of the element is applied to each
> node (or nodes) selected. The nodes are available as a a document
> (with the label $label) to the body of the for-each.
> 
> The single with-output element (which must have the name 'result')
> identifies which output from the steps in the body is to be considered
> the output of each application.
> 
> The result of the entire step is the sequence of results obtained from
> each application.
Some thoughts on for-each:
1. I think we need more than one with-ouput (or declare-output as we 
have it now). The contained steps can produce multiple outputs; it seems 
weird to lose those outputs. For example, say that the 'validate' step 
produces a copy of the original document with defaulted & fixed 
attributes/elements added, plus a set of errors/warnings from the 
document. To validate each chapter and capture all the validated 
documents and errors, you'd need:
   <p:for-each select="//chapter" ref="#pipe/document" name="loop">
     <p:declare-output port="validated" />
     <p:declare-output port="errors" />
     <p:step kind="validate" name="validate">
       <p:input port="document" ref="#loop/#matched" />
       <p:output port="validated" ref="#loop/validated" />
       <p:output port="errors" ref="#loop/errors" />
     </p:step>
   </p:for-each>
2. Rather than using #loop/#matched (or something similar) to reference 
the individual input documents, as in the above, I think we should let 
the user provide names for them. A design like:
   <p:for-each name="loop">
     <p:declare-input port="chapter"
                      ref-each="#pipe/document"
                      select="//chapter" />
     <p:declare-output port="validated" />
     <p:declare-output port="errors" />
     <p:step kind="validate" name="validate">
       <p:input port="document" ref="#loop/chapter" />
       <p:output port="validated" ref="#loop/validated" />
       <p:output port="errors" ref="#loop/errors" />
     </p:step>
   </p:for-each>
would enable this. (The 'ref-each' attribute indicates that the input is 
one that should be iterated over, rather than a normal input, to enable 
other kinds of input to be declared too.)
3. If we adopted the above design, we *could* support joins. For 
example, the following would transform each of the chapters in the 
pipe's document input with each of the stylesheets in the pipe's 
stylesheets input:
<p:pipeline name="pipe">
   <p:declare-input port="document" />
   <p:declare-input port="stylesheets" />
   <p:declare-output port="results" />
   <p:for-each name="loop">
     <p:declare-input port="chapter"
                      ref-each="#pipe/document"
                      select="//chapter" />
     <p:declare-input port="stylesheet"
                      ref-each="#pipe/stylesheets" />
     <p:declare-output port="results" ref="#pipe/results" />
     <p:step kind="xslt" name="transform">
       <p:input port="document" ref="#loop/chapter" />
       <p:input port="stylesheet" ref="#loop/stylesheet" />
       <p:output port="result" ref="#loop/results" />
     </p:step>
   </p:for-each>
</p:pipeline>
You'd invoke it with something like:
   <p:step kind="pipe">
     <p:input port="document" href="book.xml" />
     <p:input port="stylesheets"
              href="docbook2html.xsl docbook2fo.xsl" />
     <p:output port="result" />
   </p:step>
The alternative is nested for-eaches, of course:
<p:pipeline name="pipe">
   <p:declare-input port="document" />
   <p:declare-input port="stylesheets" />
   <p:declare-output port="results" />
   <p:for-each name="loop1">
     <p:declare-input port="chapter"
                      ref-each="#pipe/document"
                      select="//chapter" />
     <p:declare-output port="results" ref="#pipe/results" />
     <p:for-each name="loop2">
       <p:declare-input port="stylesheet"
                        ref-each="#pipe/stylesheets" />
       <p:declare-output port="results" ref="#loop1/results" />
       <p:step kind="xslt" name="transform">
         <p:input port="document" ref="#loop1/chapter" />
         <p:input port="stylesheet" ref="#loop2/stylesheet" />
         <p:output port="result" ref="#loop2/results" />
       </p:step>
     </p:for-each>
   </p:for-each>
</p:pipeline>
which isn't too bad.
Cheers,
Jeni
-- 
Jeni Tennison
http://www.jenitennison.com
Received on Monday, 24 July 2006 12:58:49 UTC