2

I'm trying to translate my batch file calling the Saxon (version 8.9) into a XProc pipeline (Calabash). This is my batch call:

java -jar saxon8.jar -o out.xml in.xml style.xsl +config=config-file.cfg

The parameter config is defined in the stylesheet in this way:

<xsl:param name="config" as="document-node()"/>

The XProc part looks like this:

<p:load name="configLoad">
    <p:with-option name="href" select="'config-file.cfg'"/>
</p:load>
<p:xslt name="config">
    <p:input port="source">
        <p:document href="in.xml"/>
    </p:input>
    <p:input port="parameters">
        <p:inline>
            <c:param name="config">
                <p:pipe port="result" step="configLoad"/>
            </c:param>
        </p:inline>
    </p:input>
    <p:input port="stylesheet">
        <p:document href="style.xsl"/>
    </p:input>
</p:xslt>

The error message is this:

Required item type of value of variable $config is document-node(); supplied value has item type xs:string

I know the <p:exec> step but i don't want to use it, because the config-file shall be generated by other XSLT tranformations later. It shall also be reused by other XProc steps.

Is there a possibility to call the XSLT stylesheet with the correct parameter type? Thanks for your help!

potame
  • 7,597
  • 4
  • 26
  • 33

2 Answers2

2

Looks like you are out of luck with the current XProc standard. It states that parameters are name/value pairs where the data type of the values must be string of untypedAtomic. Don't ask me why..

http://www.w3.org/TR/xproc/#parameters

If you won't be composing the contents of your configuration dynamically, but are merely passing around contents of fixed files, you could pass through just a path to the appropriate config file, and use fn:doc() to read it from within the XSLT files.

I'd recommend against writing config files on the fly. Execution order within XProc may not be as sequentially as you might expect..

Alternative would be to pass through each config setting as a separate parameter, but then each setting would still have to comply to the flat parameter value type..

HTH!

grtjn
  • 20,254
  • 1
  • 24
  • 35
  • Thanks, that gives me certainty. I thought that, but i missed this lines you linked. Yeah, the execution order was one of the problems, I refused the p:exec step. Well I think I can force the order including it in own declared step. But it isn't a nice solution. Though, thanks for help! – Nico Kutscherauer Jul 26 '13 at 09:45
  • I meet the same problem. My XSLT receive 2 xml files, one for primary input, the second for parameter. The second one are also auto-generate by another XSLT in XProc. Now, the only way to workaround is generate the second file temporarily in XProc by p:store, pass the URL of this temporary file to XSLT, and delete it after the whole pipeline finish. – chansey Feb 26 '18 at 21:59
  • @chansey I'm pretty sure you can aggregate input from two sources, and feed those as one input doc into your second XSLT step. Writing and reading from disk is not guaranteed to be sequential nor synchronized. Maybe post a new question about this? – grtjn Feb 27 '18 at 11:14
  • @grtjn My current solution is connect 's parameters input to 's result output, is this not guaranteed to be sequential nor synchronized? – chansey Feb 27 '18 at 14:04
  • @grtjn I created a new question here: https://stackoverflow.com/questions/49011357/how-to-make-pxslt-aggregate-input-from-two-sources – chansey Feb 27 '18 at 14:46
0

Provided that your config-file.cfg file is a well-formed XML, and you can use XSLT 2,
you can either use fn:doc(), as suggested by grtjn, or

  1. rewrite your XProc pipeline this way:
    <p:load name="configLoad">
        <p:with-option name="href" select="'config-file.cfg'"/>
    </p:load>
    <p:xslt name="config" version="2.0">
        <p:input port="source">
            <p:document href="in.xml"/>
            <p:pipe port="result" step="configLoad"/>
        </p:input>
        <p:input port="parameters">
            <p:empty/>
        </p:input>
        <p:input port="stylesheet">
            <p:document href="style.xsl"/>
        </p:input>
    </p:xslt>
    
  2. rewrite the relevant section of your stylesheet this way:
    <xsl:param name="config" as="document-node()" select="subsequence(collection(), 2)"/>
    

This lets you access the secondary input document from the xslt default collection.


Please do note that no intermediate <p:store> step is needed.

Furthermore, if you don't plan to reuse the config-file.cfg loaded document in other steps, you don't even need <p:load> inside your pipeline: you can simply use <p:document> inside the source input port, like this:

<p:input port="source">
    <p:document href="in.xml"/>
    <p:document href="config-file.cfg"/>
</p:input>

I have tested this in Oxygen XML, and it works.

BTW, all credit for this answer goes to Martin Honnen, see here: https://stackoverflow.com/a/60436209

  • As a side note, this is not a perfectly elegant nor very good design, because it tightly couples the stylesheet and the pipeline - forcing the stylesheet to know at which position in the default collection it should find the config parameter value -, but: 1. the whole point here was to just show that another answer exists 2. the coupling may be mitigated by using, for the position of the config parameter value in the default collection, another dedicated parameter; that is ugly as well, but, at least, loosely couples to some extent – setedivento Jun 07 '20 at 13:56