RSS 2.0
Sign In
# Monday, 18 February 2008

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>

Archive
<2017 August>
SunMonTueWedThuFriSat
303112345
6789101112
13141516171819
20212223242526
272829303112
3456789
Statistics
Total Posts: 351
This Year: 6
This Month: 0
This Week: 0
Comments: 225
Locations of visitors to this page
Disclaimer
The opinions expressed herein are our own personal opinions and do not represent our employer's view in anyway.

© 2017, Nesterovsky bros
All Content © 2017, Nesterovsky bros
DasBlog theme 'Business' created by Christoph De Baene (delarou)