Reputation: 642
Taking the t:mult3
example in the FXSL's testFunc-curry.xsl
file, I've changed it slightly so that the first 2 parameters are sequences. These sequences seem to loose any empty items when curried.
<xsl:function name="foo:bar" as="xs:anyAtomicType">
<xsl:param name="headers" as="xs:string*"/>
<xsl:param name="row" as="xs:anyAtomicType*"/>
<xsl:param name="column" as="xs:string"/>
<xsl:message select="$column"/>
<xsl:message select="count($row)"/>
<xsl:value-of select="$row[index-of($headers, $column)]"/>
</xsl:function>
This works fine when called directly, or when the first 2 paramters are curried, providing the row
sequence has no empty (string) items. However if one of the row
items is empty (eg think of CSV-style input where a column's value like the test_col_two
below is optional. Note the headers are mandatory and taken from the the first row of the CSV):
<xsl:variable name="row" select="tokenize(.,',')"/>
<xsl:variable name="rw" select="foo:bar($headers, $row)"/>
<xsl:message select="$rw"/>
<xsl:variable name="a" select="f:apply($rw,'test_col_one')"/>
<xsl:variable name="b" select="f:apply($rw,'test_col_two')"/>
<xsl:variable name="c" select="f:apply($rw,'test_col_three')"/>
<xsl:message select="concat($a,$b,$c)"/>
If test_col_two
is empty, variable b
will contain the value of test_col_three
, not test_col_two
.
Have I misunderstood the example, or is this an issue with FXSL?
I can see that the XML output by foo:bar($headers, $row)
does include empty elements representing the empty strings, so the information is at least initially captured correctly from what I see.
Full code below.
<xsl:import href="fxsl-xslt2/f/func-curry.xsl"/>
<foo:bar/>
<xsl:function name="foo:bar" as="node()">
<xsl:sequence select="document('')/*/foo:bar[1]"/>
</xsl:function>
<xsl:function name="foo:bar" as="xs:anyAtomicType">
<xsl:param name="headers" as="xs:string*"/>
<xsl:param name="row" as="xs:anyAtomicType*"/>
<xsl:param name="column" as="xs:string"/>
<xsl:message select="$column"/>
<xsl:message select="count($row)"/>
<xsl:value-of select="$row[index-of($headers, $column)]"/>
</xsl:function>
<xsl:function name="foo:bar" as="node()">
<xsl:param name="headers" as="xs:string*"/>
<xsl:sequence select="f:curry(foo:bar(), 3, $headers)"/>
</xsl:function>
<xsl:function name="foo:bar" as="node()">
<xsl:param name="headers" as="xs:string*"/>
<xsl:param name="row" as="xs:anyAtomicType*"/>
<xsl:sequence select="f:curry(foo:bar(), 3, $headers, $row)"/>
</xsl:function>
<xsl:template match="foo:bar" mode="f:FXSL">
<xsl:param name="arg1" as="xs:string*"/>
<xsl:param name="arg2" as="xs:anyAtomicType*"/>
<xsl:param name="arg3" as="xs:string"/>
<xsl:sequence select="foo:bar($arg1,$arg2,$arg3)"/>
</xsl:template>
Upvotes: 1
Views: 107
Reputation: 167696
Looking at
<xsl:function name="int:makeArg" as="element()">
<xsl:param name="arg1"/>
<arg>
<xsl:choose>
<xsl:when test="exists($arg1[2])">
<xsl:attribute name="s"/>
<xsl:for-each select="$arg1">
<e t="{f:type(.)}"><xsl:sequence select="."/></e>
</xsl:for-each>
</xsl:when>
<xsl:otherwise>
<xsl:attribute name="t" select="f:type($arg1)"/>
<xsl:sequence select="$arg1"/>
</xsl:otherwise>
</xsl:choose>
</arg>
</xsl:function>
<xsl:function name="int:getArg">
<xsl:param name="pargNode" as="element()*"/>
<xsl:sequence select=
"if(not($pargNode/@s))
then
if(not($pargNode/@t) or $pargNode/@t = 'xml:node')
then $pargNode/node()
else
f:apply(f:Constructor($pargNode/@t), $pargNode/node() )
else
for $varg in $pargNode/e/node()
return
if(not($varg/../@t) or $varg/../@t = 'xml:node')
then $varg
else
f:apply(f:Constructor($varg/../@t), $varg )
"
/>
</xsl:function>
where arguments are created with int:makeArg
and processed with int:getArg
it seems that makeArg
sets up an e
element with the value of the original arg as the contents (<e t="{f:type(.)}"><xsl:sequence select="."/></e>
) and then getArg
expects a child node in e
as it does for $varg in $pargNode/e/node()
. However, if you have a sequence with empty strings inside then I think this approach swallows the empty strings as xsl:sequence select="''"
with not construct any child node in the e
element and then the getArg
with e/node()
obviously fails to find that argument. So it looks that FXSL has some flaw there, perhaps rewriting
for $varg in $pargNode/e/node()
return
if(not($varg/../@t) or $varg/../@t = 'xml:node')
then $varg
else
f:apply(f:Constructor($varg/../@t), $varg )
as
for $varg in $pargNode/e
return
if(not($varg/@t) or $varg/@t = 'xml:node')
then $varg/node()
else
f:apply(f:Constructor($varg/@t), $varg )
suffices. Hopefully Dimitre Novatchev @DimitreNovatchev can tell you more about this as the author of the library.
Upvotes: 1