I’m using XProc 3.0 with XML Calabash 3. I have a pipeline where:
p:xinclude on a different document which depends on the files that were fixed and stored in step (2)<p:declare-step xmlns:p="http://www.w3.org/ns/xproc" xmlns:c="http://www.w3.org/ns/xproc-step" version="3.0" name="generateDocumentation">
<p:directory-list name="dl" path="../includes" include-filter=".+\.xml$"
exclude-filter=".+fixed\.xml$" max-depth="unbounded"/>
<p:make-absolute-uris match="@name"/>
<p:for-each name="fix-includes">
<!-- iterate over each c:file from the directory listing -->
<p:with-input select="//c:file"/>
<!-- in this iteration, the document is a single c:file -->
<p:variable name="in" select="string(/*/@name)"/>
<p:variable name="out" select="replace($in, '\.xml$', '.fixed.xml', 'i')"/>
<p:load href="{$in}" content-type="application/xml"/>
<p:xslt>
<p:with-input port="stylesheet" href="../stylesheets/fix-includes.xsl"/>
</p:xslt>
<p:store href="{$out}"/>
</p:for-each>
<p:xinclude name="include">
<p:with-input port="source">
<p:document href="index.xml" content-type="application/xml"/>
</p:with-input>
</p:xinclude>
<!-- EDIT: I have further steps here which need the result of <p:xinclude> -->
</p:declare-step>
The problem: Calabash lets p:xinclude start before the p:for-each has finished writing files, leading to missing-file errors in p:xinclude. I understand why this happens (no data dependency, the loop does not feed any data into the later step so its p:store steps look like side effects), but I can't figure out an idiomatic XProc 3 solution for this.
The question: How can I make sure that all the iterations of p:for-each complete, including all thep:store operations, before running a later step (p:xinclude) when there is no natural document flow between them?
Many thanks in advance!
I have tried my suggestion from the comment (to wrap the p:xinclude in a p:if that checks a file count taken by a p:count "after" the p:for-each):
<p:declare-step xmlns:p="http://www.w3.org/ns/xproc" xmlns:c="http://www.w3.org/ns/xproc-step" version="3.0" name="generateDocumentation">
<p:output port="result"/>
<p:directory-list name="dl" path="includes" include-filter=".+\.xml$"
exclude-filter=".+fixed\.xml$" max-depth="unbounded"/>
<p:make-absolute-uris match="@name"/>
<p:variable name="file-count" select="count(//c:file)"/>
<p:for-each name="fix-includes">
<!-- iterate over each c:file from the directory listing -->
<p:with-input select="//c:file"/>
<!-- in this iteration, the document is a single c:file -->
<p:variable name="in" select="string(/*/@name)"/>
<p:variable name="out" select="replace($in, '\.xml$', '.fixed.xml', 'i')"/>
<p:load href="{$in}" content-type="application/xml"/>
<p:xslt>
<p:with-input port="stylesheet" href="fix-includes.xsl"/>
</p:xslt>
<p:store href="{$out}" message="p:store {current-dateTime()}"/>
</p:for-each>
<p:count/>
<p:group name="do-include">
<p:output port="result"></p:output>
<p:if test=". = $file-count">
<p:xinclude name="include">
<p:with-input port="source">
<p:document href="index.xml" content-type="application/xml"/>
</p:with-input>
</p:xinclude>
<p:identity message="Inside if {current-dateTime()}"/>
<!-- EDIT: I have further steps which need the result of <p:xinclude> -->
</p:if>
</p:group>
<!-- You can't use outputs from <xi:include> directly, but you can use
<p:pipe step="do-include" port="result"/> instead. -->
</p:declare-step>
That seems to make sure the p:xinclude is run after the p:for-each, output is e.g.
p:store 2025-12-28T19:37:59.5199281+01:00
p:store 2025-12-28T19:37:59.5403036+01:00
p:store 2025-12-28T19:37:59.5510977+01:00
p:store 2025-12-28T19:37:59.563198+01:00
p:store 2025-12-28T19:37:59.5737237+01:00
Inside if 2025-12-28T19:37:59.58695+01:00
<root xmlns:xi="http://www.w3.org/2001/XInclude">...