1

After reading the XProc question below:

XSLT with XProc - parameter binding in the required type

Passing document() parameter to an xslt in XProc pipeline

It seems impossible to pass document-node() type parameter to XSLT in XProc.

So the only way to workaround is: generate temporary file and pass the URL of temporary file as parameter to XSLT.

Look following example:

big-command.xpl

<?xml version="1.0" encoding="UTF-8"?>
<p:declare-step xmlns:p="http://www.w3.org/ns/xproc"
    xmlns:c="http://www.w3.org/ns/xproc-step" version="1.0">
    <p:output port="result">
        <p:pipe port="result" step="final-calculation"/>
    </p:output>

    <p:xslt name="generate-temp-data" template-name="main">
        <p:input port="source">
            <p:empty/>
        </p:input>
        <p:input port="stylesheet">
            <p:document href="generate-temp-data.xsl"/>
        </p:input>
        <p:input port="parameters">
            <p:empty/>
        </p:input>
    </p:xslt>

    <p:store name="store-temp-data" href="temp-data.xml"/>

    <p:xslt name="final-calculation" >
        <p:input port="source">
            <p:document href="source-data.xml"/>
        </p:input>
        <p:input port="stylesheet">
            <p:document href="final-calculation.xsl"/>
        </p:input>
        <p:with-param name="temp-data" select="/">
            <p:pipe port="result" step="store-temp-data"/>
        </p:with-param>
    </p:xslt>
</p:declare-step>

final-calculation.xsl

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    exclude-result-prefixes="xs"
    version="2.0">

    <xsl:param name="temp-data"/>
    <xsl:variable name="temp-data-doc" select="doc($temp-data)"/>

    <xsl:template match="/">
        <final>
            <xsl:for-each select="$temp-data-doc//record">
                <xsl:value-of select="."/>
            </xsl:for-each>
        </final>
    </xsl:template>
</xsl:stylesheet>

generate-temp-data.xsl

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    exclude-result-prefixes="xs"
    version="2.0">

    <xsl:template name="main">
        <temp-data>
            <record>1</record>
            <record>2</record>
            <record>3</record>
        </temp-data>
    </xsl:template>
</xsl:stylesheet>

source-data.xml

<?xml version="1.0" encoding="UTF-8"?>
<x/>

My question is:

Is this solution has sequential nor synchronized problem?

Is there any new solution in 2018?

How to safe delete temporary file: temp-data.xml?

@grtjn

chansey
  • 1,266
  • 9
  • 20

3 Answers3

1

My XProc knowledge is a bit rusty, but let me try to answer anyhow..

The issue with above code is that the final-calculation.xsl might try to read temp-data.xml before it is written to disk. You could get a not found error, an error stating you cannot write because it is being read elsewhere, or worst of all you could end up reading an old copy of the temp file in case you run repeatedly.

Your best bet is to use p:wrap-sequence with a p:input that pulls in two source streams by simply adding multiple references inside it. You then use that as primary input for you second xsl, in which you take the input back apart into the two pieces you need.

So instead of p:store something like (untested):

<p:wrap-sequence wrapper="wrapper">
  <p:input>
    <p:document href="source-data.xml"/>
    <p:pipe step="generate-temp-data" pipe="result"/>
  </p:input>
</p:wrap-sequence>

With this you should not need the temp-data param on your xsl anymore, and inside you just need to keep in mind that there is an extra wrapper element that you need to unwrap inside the xsl, and that the temp-data is the second child within that wrapper element.

HTH!

grtjn
  • 20,254
  • 1
  • 24
  • 35
  • Thanks grtjn. But that solution break XSLT code desgin. (We must change XSLT code to conform XProc) In the iterative development process, XProc is the last step, we should not change the original XSLT to conform XProc. – chansey Feb 28 '18 at 13:35
  • "final-calculation.xsl might try to read temp-data.xml before it is written to disk" Can you tell me where describes this limitation about p:store? I can't find it in https://www.w3.org/TR/xproc/#c.store. Or it is a implement detail? Of course, If it has synchronized option, every thing is OK. – chansey Feb 28 '18 at 13:41
1

I think you can pass in several documents on the input port to the p:xslt step if you use XSLT 2.0 with version="2.0" and then inside the XSLT code you are able and willing to access the collection:

<?xml version="1.0" encoding="UTF-8"?>
<p:declare-step xmlns:p="http://www.w3.org/ns/xproc"
    xmlns:c="http://www.w3.org/ns/xproc-step" version="1.0" xpath-version="2.0">
    <p:output port="result">
        <p:pipe port="result" step="final-calculation"/>
    </p:output>

    <p:xslt name="generate-temp-data" template-name="main">
        <p:input port="source">
            <p:empty/>
        </p:input>
        <p:input port="stylesheet">
            <p:document href="generate-temp-data.xsl"/>
        </p:input>
        <p:input port="parameters">
            <p:empty/>
        </p:input>
    </p:xslt>

    <p:xslt name="final-calculation" version="2.0">
        <p:input port="source">
            <p:document href="source-data.xml"/>
            <p:pipe port="result" step="generate-temp-data"/>
        </p:input>
        <p:input port="stylesheet">
            <p:document href="final-calculation.xsl"/>
        </p:input>
        <p:input port="parameters">
            <p:empty/>
        </p:input>
    </p:xslt>
</p:declare-step>



<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    exclude-result-prefixes="xs"
    version="2.0">

    <xsl:variable name="temp-data-doc" select="collection()[2]"/>

    <xsl:template match="/">
        <final>
            <xsl:for-each select="$temp-data-doc//record">
                <xsl:value-of select="."/>
            </xsl:for-each>
        </final>
    </xsl:template>
</xsl:stylesheet>
Martin Honnen
  • 160,499
  • 6
  • 90
  • 110
  • Using `fn:collection()[position]` is a very good idea, indeed! I had a similar problem, where I wanted to compose a single page from two input fragments, and passing them from a single `p:input` to the default input port of `p:xslt` and parsing them as collection in the stylesheet was indeed solving the issue. Before that, I tried passing the document via `p:with-param`, but that only transports atomic types, effectively stringifying everything. – amix Jan 11 '21 at 13:45
0

After working a bit with XProc and seeing different solutions, I found now a way to implement this in XProc. It is a bit tricky, but it works:

<?xml version="1.0" encoding="UTF-8"?>
<p:declare-step xmlns:p="http://www.w3.org/ns/xproc" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:c="http://www.w3.org/ns/xproc-step" version="1.0">
    <p:output port="result">
        <p:pipe port="result" step="final-calculation"/>
    </p:output>

    <p:xslt name="generate-temp-data" template-name="main">
        <p:input port="source">
            <p:empty/>
        </p:input>
        <p:input port="stylesheet">
            <p:document href="generate-temp-data.xsl"/>
        </p:input>
        <p:input port="parameters">
            <p:empty/>
        </p:input>
    </p:xslt>
    <p:documentation>Create an empty temporary stylesheet which imports the final-calculation and has a parameter $temp-data-doc:</p:documentation>
    <p:identity>
        <p:input port="source">
            <p:inline>
                <xsl:stylesheet version="2.0">
                    <xsl:import href="final-calculation.xsl"/>
                    <xsl:param name="temp-data-doc" as="document-node()">
                        <xsl:document/>
                    </xsl:param>
                </xsl:stylesheet>
            </p:inline>
        </p:input>
    </p:identity>

    <p:documentation>Insert the temporary document as default value of the $temp-data-doc parameter:</p:documentation>
    <p:insert match="xsl:param[@name = 'temp-data-doc']/xsl:document" position="first-child" name="final-calculation-xsl">
        <p:input port="insertion">
            <p:pipe port="result" step="generate-temp-data"/>
        </p:input>
    </p:insert>

    <p:xslt name="final-calculation" >
        <p:input port="source">
            <p:document href="source-data.xml"/>
        </p:input>
        <p:documentation>Use the temporary stylesheet, not that from file system.</p:documentation>
        <p:input port="stylesheet">
            <p:pipe port="result" step="final-calculation-xsl"/>
        </p:input>
        <p:input port="parameters">
            <p:empty/>
        </p:input>
    </p:xslt>
</p:declare-step>

Please see the p:documentation elements for description, how it works.