Reputation: 3528
I'm using Saxon 9.4 and XSLT 2.0
I have the following code snippet in my stylesheet :-
<xsl:template name="some_template">
<xsl:param name="some_param" as="xs:integer?"/>
</xsl:template>
This is basically a template that takes in an optional integer parameter. When I try to call it like this however,
<xsl:call-template name="some_template>
<xsl:with-param name="some_param">
<xsl:if test="some_condition">
<xsl:value-of select="xs:integer(./@attr div 20)"/>
</xsl:if>
</xsl:with-param>
</xsl:call-template>
I get an error message saying :-
Validation error FORG0001: Cannot convert zero-length string to an integer
However, the following two stylesheets don't give me an error :-
<xsl:call-template name="some_template>
<xsl:with-param name="some_param">
<xsl:value-of select="xs:integer(./@attr div 20)"/>
</xsl:with-param>
</xsl:call-template>
or
<xsl:variable name="dummy" as="xs:integer?">
<xsl:if test="some_condition">
<xsl:value-of select="xs:integer(./@attr div 20)"/>
</xsl:if>
</xsl:variable>
<xsl:call-template name="some_template>
<xsl:with-param name="some_param" select="$dummy"/>
</xsl:call-template>
So clearly the type information is not being preserved across the block. Any idea how to get the first thing to work? The third stylesheet does what I want semantically but I'd rather not go around creating (several) dummy variables just to be able to do this.
Thanks!
Upvotes: 1
Views: 869
Reputation: 163595
It's not entirely clear to me what's happening here, but what is clear is how to improve your code so it's not so confusing. With your code as written, in the true case you are computing a double, converting that to an integer, converting the integer to a text node, wrapping that in a document node, passing the document node as the parameter, having this atomized to untyped atomic at the receiving end because the expected type is atomic, then having the untyped atomic value converted to an integer. All this should work, but is really circuitous, and is easily avoided by an "as="xs:integer"" on the xsl:with-param.
In the false case, you are passing a document node with no children, and conversion of that to xs:integer? will fail - it won't convert to an empty sequence. So despite what you say, I think it's failing on the false path.
Upvotes: 1
Reputation: 243579
This transformation:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xsl:output method="text"/>
<xsl:template match="/*">
<xsl:call-template name="some_template">
<xsl:with-param name="some_param" select=
"if(some_condition)
then xs:integer(@attr div 20)
else ()
"/>
</xsl:call-template>
</xsl:template>
<xsl:template name="some_template">
<xsl:param name="some_param" as="xs:integer?"/>
XXX
</xsl:template>
</xsl:stylesheet>
when applied on each of the following XML documents:
<t attr="20">
<some_condition/>
</t>
,
<t>
<some_condition/>
</t>
,
<t attr="20">
</t>
and
<t>
</t>
produces the wanted, correct result (without raising any exceptions):
XXX
Upvotes: 1
Reputation: 43421
I reckon the error come when your <xsl:if>
is false meaning no value is assigned to your param. You can try one of this solution :
Did you tried to set a default value for your <xsl:param>
?
<xsl:template name="some_template">
<xsl:param name="some_param" select="-1" as="xs:integer?" />
</xsl:template>
false
caseAlways set a value when you call your template using XPath2.0 if-then-else expression:
<xsl:call-template name="some_template>
<xsl:with-param name="some_param" select="
if (some_condition)
then xs:integer(./@attr div 20)
else -1"
/>
</xsl:call-template>
I use -1
as value for the false
case.
Upvotes: 1