Is it possible to call function indirectly in xslt 2.0?
The answer is yes, however implementation uses dull trick of template matching to select a function handler. Template matching is a beautiful thing. Definitely it was not devised to make this trick possible.
The following example defines two functions t:sum, and t:count to call indirectly by t:test.
Function id (a.k.a. function pointer) is defined by t:sum, and t:count variables.
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:t="http://www.nesterovsky-bros.com"
exclude-result-prefixes="xs t">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/">
<xsl:variable name="items" as="element()*">
<value>1</value>
<value>2</value>
<value>3</value>
<value>4</value>
<value>5</value>
</xsl:variable>
<root>
<sum>
<xsl:sequence select="t:test($items, $t:sum)"/>
</sum>
<count>
<xsl:sequence select="t:test($items, $t:count)"/>
</count>
</root>
</xsl:template>
<!-- Mode "t:function-call". Default match. -->
<xsl:template mode="t:function-call" match="@* | node()">
<xsl:sequence select="
error
(
xs:QName('invalid-call'),
concat('Unbound function call. Id: ', name())
)"/>
</xsl:template>
<!-- Id of the function t:sum. -->
<xsl:variable name="t:sum" as="item()">
<t:sum/>
</xsl:variable>
<!-- Mode "t:function-call". t:sum handler. -->
<xsl:template mode="t:function-call" match="t:sum">
<xsl:param name="items" as="element()*"/>
<xsl:sequence select="t:sum($items)"/>
</xsl:template>
<!--
Calculates a sum of elements.
$param - items to sum.
Returns sum of element values.
-->
<xsl:function name="t:sum" as="xs:integer">
<xsl:param name="items" as="element()*"/>
<xsl:sequence select="sum($items/xs:integer(.))"/>
</xsl:function>
<!-- Id of the function t:count. -->
<xsl:variable name="t:count" as="item()">
<t:count/>
</xsl:variable>
<!-- Mode "t:function-call". t:count handler. -->
<xsl:template mode="t:function-call" match="t:count">
<xsl:param name="items" as="element()*"/>
<xsl:sequence select="t:count($items)"/>
</xsl:template>
<!--
Calculates the number of elements in a sequence.
$param - items to count.
Returns count of element values.
-->
<xsl:function name="t:count" as="xs:integer">
<xsl:param name="items" as="element()*"/>
<xsl:sequence select="count($items)"/>
</xsl:function>
<!--
A function that performs indirect call.
$param - items to pass to an indirect call.
$function-id - a function id.
Returns a value calculated in the indirect function.
-->
<xsl:function name="t:test" as="xs:integer">
<xsl:param name="items" as="element()*"/>
<xsl:param name="function-id" as="item()"/>
<xsl:variable name="result" as="xs:integer">
<xsl:apply-templates mode="t:function-call" select="$function-id">
<xsl:with-param name="items" select="$items"/>
</xsl:apply-templates>
</xsl:variable>
<xsl:sequence select="$result"/>
</xsl:function>
</xsl:stylesheet>