xproc

Xproc (calabash): order of execution


I am trying to write an xproc that needs to do several p:xslt step sequentially. First, it writes two normalized XML files to disk and then a third p:xslt should take these normalized files as input.

UPDATE: first problem (third p:xslt fires before second p:store finished writing to disk) solved by adding explicit connection between second p:store and third p:xslt. (modified in code below)

UPDATE 2 Next problem is that I want to delete the temporary files with the pxf:delete instruction. This gives same order of execution problem: pxf:delete is fired before the file it is supposed to delete is written to disk. It seems there is no p:input possible on pxf:delete. Therefore, the previous strategy of connecting the step explicitly to the last step does not seem to be possible. Any thoughts how to force pxf:delete to wait?

(Question below modified, sorry about the mess)

The xproc looks like this:

<?xml version="1.0" encoding="UTF-8"?>
<p:declare-step type="doc:compare_files" xmlns:p="http://www.w3.org/ns/xproc" xmlns:c="http://www.w3.org/ns/xproc-step" version="1.0" xmlns:cx="http://xmlcalabash.com/ns/extensions" name="current" xmlns:doc="http://technische-documentatie.oep.overheid.nl/namespaces/doc" xmlns:pxf="http://xmlcalabash.com/ns/extensions/fileutils" >
<p:output port="result">
  <p:pipe port="result" step="big_transform"/>
</p:output>

<p:option name="filename1" required="true"/>
<p:option name="filename2" required="true"/> 

<p:load name="load-filename1">
  <p:with-option name="href" select="$filename1"/>
</p:load>

<p:load name="load-filename2">
  <p:with-option name="href" select="$filename2"/>
</p:load>

<p:xslt name="prepare_transform_1">
  <p:input port="source">
     <p:pipe port="result" step="load-filename1"/>
  </p:input>
  <p:input port="stylesheet">
    <p:document href="prepare_for_hash_identity_transform.xsl"/>
  </p:input>
  <p:input port="parameters" kind="parameter" sequence="true">
    <p:inline>
      <c:param-set>
        <c:param name="commentsFilteren" value="ja"/>
      </c:param-set>
    </p:inline>
  </p:input>
 </p:xslt>

<p:store href="t1.xml"/>

<p:xslt name="prepare_transform_2">
  <p:input port="source">
    <p:pipe port="result" step="load-filename2"/>
  </p:input>
  <p:input port="stylesheet">
    <p:document href="prepare_for_hash_identity_transform.xsl"/>
  </p:input>
  <p:input port="parameters" kind="parameter" sequence="true">
    <p:inline>
      <c:param-set>
        <c:param name="commentsFilteren" value="ja"/>
      </c:param-set>
    </p:inline>
  </p:input>
 </p:xslt>

<p:store href="t2.xml" name="store2"/>

<p:xslt name="big_transform">
  <p:input port="source">
     <p:pipe port="result" step="store2">
  </p:input>
  <p:input port="stylesheet">
    <p:document href="generate_hash.xsl"/>
  </p:input>
  <p:input port="parameters" kind="parameter" sequence="true">
    <p:inline>
      <c:param-set>
        <c:param name="file1" value="t1.xml"/>
        <c:param name="file2" value="t2.xml"/>
      </c:param-set>
    </p:inline>
   </p:input>
</p:xslt>

<p:import href="http://xmlcalabash.com/extension/steps/fileutils.xpl"/>
<pxf:delete href="t1.xml"/>
<pxf:delete href="t2.xml"/>

</p:declare-step>

Solution

  • If you perform transformations within XProc to create filename1 and filename2, then why not pass the results through themselves. Simply declare two input ports on the step, and connect the result ports of earlier transformations to the input ports of your custom step. No temp files, and no need to delete temp files.

    You can of course still write intermediate results, for debugging purposes. Nothing stops you from tieing one result port to multiple input ports.

    update:

    Redirecting output of earlier transforms as input for parameters is done the same way as you redirect output of earlier steps to input for latter steps. The only catch is that you must conform to the syntax of parameters (c:param-set/c:param etc). So if your earlier transforms produce that syntax, then you can do this:

    <?xml version="1.0" encoding="UTF-8"?>
    <p:declare-step type="doc:compare_files" xmlns:p="http://www.w3.org/ns/xproc" xmlns:c="http://www.w3.org/ns/xproc-step" version="1.0" xmlns:cx="http://xmlcalabash.com/ns/extensions" name="current" xmlns:doc="http://technische-documentatie.oep.overheid.nl/namespaces/doc" xmlns:pxf="http://xmlcalabash.com/ns/extensions/fileutils" >
    <p:input port="file1"/>
    
    <p:input port="file2"/>
    
    <p:output port="result">
      <p:pipe port="result" step="big_transform"/>
    </p:output>
    
    <p:xslt name="prepare_transform_1">
      <p:input port="source">
         <p:pipe port="file1" step="current"/>
      </p:input>
      <p:input port="stylesheet">
        <p:document href="prepare_for_hash_identity_transform.xsl"/>
      </p:input>
      <p:input port="parameters" kind="parameter" sequence="true">
        <p:inline>
          <c:param-set>
            <c:param name="param-name" value="file1"/>
            <c:param name="commentsFilteren" value="ja"/>
          </c:param-set>
        </p:inline>
      </p:input>
     </p:xslt>
    
    <p:xslt name="prepare_transform_2">
      <p:input port="source">
        <p:pipe port="file2" step="current"/>
      </p:input>
      <p:input port="stylesheet">
        <p:document href="prepare_for_hash_identity_transform.xsl"/>
      </p:input>
      <p:input port="parameters" kind="parameter" sequence="true">
        <p:inline>
          <c:param-set>
            <c:param name="param-name" value="file2"/>
            <c:param name="commentsFilteren" value="ja"/>
          </c:param-set>
        </p:inline>
      </p:input>
     </p:xslt>
    
    <p:xslt name="big_transform">
      <p:input port="source">
         <p:pipe port="file2" step="current"/>
      </p:input>
      <p:input port="stylesheet">
        <p:document href="generate_hash.xsl"/>
      </p:input>
      <p:input port="parameters" kind="parameter" sequence="true">
        <p:pipe port="result" step="prepare_transform_1"/>
        <p:pipe port="result" step="prepare_transform_2"/>
       </p:input>
    </p:xslt>
    
    </p:declare-step>
    

    I tested it with this command-line:

    calabash --input file1=file1.xml --input file2=file2.xml --output result=out.xml test.xpl
    

    file1.xml, and file2.xml contained dummy xml (<x/>). The prepare_for_hash_identity_transform.xsl contained:

    <?xml version="1.0" encoding="utf-8"?>
    <xsl:stylesheet version="2.0"
        xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
         xmlns:c="http://www.w3.org/ns/xproc-step">
    
        <xsl:output method="xml" version="1.0" encoding="utf-8" indent="yes"/>
    
        <xsl:strip-space elements="*" />
    
        <xsl:param name="param-name"/>
    
        <xsl:template match="/">
            <c:param-set>
                <c:param name="{$param-name}" value="{base-uri(/)}"/>
            </c:param-set>
        </xsl:template>
    
    </xsl:stylesheet>
    

    The generate_hash.xsl contained:

    <?xml version="1.0" encoding="utf-8"?>
    <xsl:stylesheet version="2.0"
        xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
         xmlns:c="http://www.w3.org/ns/xproc-step">
    
        <xsl:output method="xml" version="1.0" encoding="utf-8" indent="yes"/>
    
        <xsl:strip-space elements="*" />
    
        <xsl:param name="file1"/>
        <xsl:param name="file2"/>
    
        <xsl:template match="/">
            <c:param-set>
                <c:param name="file1" value="{$file1}"/>
                <c:param name="file2" value="{$file2}"/>
            </c:param-set>
        </xsl:template>
    
    </xsl:stylesheet>
    

    HTH!