Is it possible to embed function (that constructs an element) by value (i.e. anonymous functions/lambdas)

53 views Asked by At

Is it possible to embed a function inside a map (for example) by value e.g.

<xsl:function name="kooks:stringAdd" as="xs:string">
    <xsl:param name="s1" as="xs:string"/>
    <xsl:param name="s2" as="xs:string"/>
    <xsl:sequence select="concat($s1,$s2)"/>
</xsl:function>

<xsl:variable name="stringMonoid" as="map(*)">
    <xsl:map>
        <xsl:map-entry key="'zero'" select="''" as="xs:string"/>
        <xsl:map-entry key="'add'" select="kooks:stringAdd#2"/>
    </xsl:map>
</xsl:variable>

can i write it (in psuedo xslt) like this.

<xsl:variable name="stringMonoid" as="map(*)">
    <xsl:map>
        <xsl:map-entry key="'zero'" select="''" as="xs:string"/>
        <xsl:map-entry key="'add'">
            <xsl:function as="xs:string">
                <xsl:param name="s1" as="xs:string"/>
                <xsl:param name="s2" as="xs:string"/>
                <xsl:sequence select="concat($s1,$s2)"/>
            </xsl:function>
        </xsl:map>
    </xsl:map>
</xsl:variable>

Clarification, the question is about XSLT functions, I want to be able to construct and return elements (sadly the example returns atomic types), and whilst you can embed xpath expressions that contain inline functions, I'm not sure these can construct elements.

1

There are 1 answers

13
Martin Honnen On BEST ANSWER

You can use an anonymous function/lambda expression as a key value e.g.

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  version="3.0"
  xmlns:xs="http://www.w3.org/2001/XMLSchema"
  exclude-result-prefixes="#all"
  expand-text="yes">

  <xsl:output method="xml" indent="yes"/>
  
  <xsl:variable name="stringMonoid" as="map(*)"
    select="map {
             'zero' : '',
             'add' : function($s1 as xs:string, $s2 as xs:string) { $s1 || $s2 }
           }"/>

  <xsl:mode on-no-match="shallow-copy"/>

  <xsl:template match="/" name="xsl:initial-template">
    <test>{$stringMonoid?add('This is a ', 'test')}</test>
    <xsl:comment xmlns:saxon="http://saxon.sf.net/">Run with {system-property('xsl:product-name')} {system-property('xsl:product-version')} at {current-dateTime()}</xsl:comment>
  </xsl:template>

</xsl:stylesheet>

outputs something like (the processor and date info will vary)

<?xml version="1.0" encoding="UTF-8"?>
<test>This is a test</test>
<!--Run with SAXON HE 10.6 at 2023-10-12T12:13:27.373+02:00-->

Example fiddle using SaxonC HE 12.3.

If you want to create the map with xsl:map then

  <xsl:variable name="stringMonoid" as="map(*)">
    <xsl:map>
      <xsl:map-entry key="'zero'" select="''"/>
      <xsl:map-entry key="'add'" select="function($s1 as xs:string, $s2 as xs:string) { $s1 || $s2 }"/>
    </xsl:map>
  </xsl:variable>

is possible for an anonymous function (created with XPath, admittedly). But it is not clear to me why you would want to use XSLT to create an anonymous function, if your first example has a named function defined with xsl:function, why doesn't that suffice?