Project

Profile

Help

Difference between parameters with "as" attribute type declaration in xsl:function and xsl:iterate?

Added by Martin Honnen over 4 years ago

Using Saxon (tested with HE 10 but also found in 9.8 and 9.9), I have found a strange result using xsl:iterate with an iteration parameter declaring a type with e.g. as="xs:string". When I do this with functions or templates I am used to any node values being atomized while Saxon with xsl:iterate seems to either include the node or serialize it as XML.

An example stylesheet is

<?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="#all"
    xmlns:mf="http://example.com/mf"
    expand-text="yes"
    version="3.0">
    
    <xsl:mode on-no-match="shallow-copy"/>
    
    <xsl:output method="xml" indent="yes" />
    
    <xsl:template match="/" name="xsl:initial-template">
        <xsl:iterate select="1 to 5">
            <xsl:param name="p1" as="xs:string" select="'test'"/>
            <xsl:on-completion>
                <xsl:copy-of select="count($p1), $p1 instance of xs:string"/>
                <xsl:copy-of select="$p1"/>
                <xsl:copy-of select="$p1[1]"/>
                <xsl:value-of select="boolean($p1), string-length($p1) ne 0"/>
            </xsl:on-completion>
            <xsl:next-iteration>
                <xsl:with-param name="p1">
                    <xsl:copy-of select="$p1"/>
                    <item>test {.}</item>
                </xsl:with-param>
            </xsl:next-iteration>
        </xsl:iterate>
        <function-call>
            <xsl:sequence select="mf:test((1 to 5), 'test')"/>
        </function-call>
    </xsl:template>
    
    <xsl:function name="mf:test">
        <xsl:param name="seq" as="item()*"/>
        <xsl:param name="p1" as="xs:string"/>
        <xsl:choose>
            <xsl:when test="empty($seq)">
                <xsl:sequence select="$p1"/>
            </xsl:when>
            <xsl:otherwise>
                <xsl:variable name="item" as="element(item)"><item>Test {head($seq)}</item></xsl:variable>
                <xsl:variable name="p1">
                    <xsl:copy-of select="$p1, $item"/>
                </xsl:variable>
                <xsl:sequence select="mf:test(tail($seq), $p1)"/>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:function>
    
</xsl:stylesheet>

which outputs

<?xml version="1.0" encoding="UTF-8"?>1 truetest<item>test 1</item>
<item>test 2</item>
<item>test 3</item>
<item>test 4</item>
<item>test 5</item>test<item>test 1</item>
<item>test 2</item>
<item>test 3</item>
<item>test 4</item>
<item>test 5</item>true true<function-call>testTest 1Test 2Test 3Test 4Test 5</function-call>

with Saxon 10 HE for me while Exselt

<?xml version="1.0" encoding="UTF-8"?>1 true testtest 1test 2test 3test 4test 5 testtest 1test 2test 3test 4test 5true t
rue<function-call>testTest 1Test 2Test 3Test 4Test 5</function-call>

So for some reason the item element nodes passed in xsl:iterate to the p1 variable type as="xs:string" are being bound as nodes or as serialized <item>test x</item> while with a function Saxon does what I exepct and what Exselt does in both cases, namely just take the string value of the node.

I understand Exselt never got published adjusted to the final spec but I can't find anything in the XSLT 3 spec explaining Saxon's result for the values of $p in xsl:iterate containing all those <item>test n</item>.


    (1-1/1)

    Please register to reply