Higher-Order and Map Functions

Higher-Order and Map Functions in XSLT

Functions are values in XSLT 3.0: an xsl:function can return a closure (an inline function that remembers $pct), maps index data by key, and system-property() tells the stylesheet where it runs. Run xslt3 -s:booknest-catalog.xml -xsl:hof.xsl:

hof.xsl: a function factory, a price map and system propertiesXML
<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:bn="urn:booknest:fn"
    xmlns:map="http://www.w3.org/2005/xpath-functions/map" expand-text="yes">
  <xsl:output method="text"/>
  <xsl:function name="bn:discounter" as="function(xs:decimal) as xs:decimal">
    <xsl:param name="pct" as="xs:decimal"/>
    <xsl:sequence select="function($p) { round($p * (100 - $pct) div 100, 2) }"/>
  </xsl:function>
  <xsl:template match="/catalog">
    <xsl:variable name="prices" as="map(xs:string, xs:decimal)"
        select="map:merge(book ! map { string(@id): xs:decimal(.//price) })"/>
    <xsl:variable name="sale" select="bn:discounter(20)"/>
    <xsl:text>From $20: {map:keys($prices)[$prices(.) ge 20] => sort()}&#10;</xsl:text>
    <xsl:text>Sale total: {sum($prices?* ! $sale(.))}&#10;</xsl:text>
    <xsl:text>{('xsl:product-name', 'xsl:product-version', 'xsl:supports-streaming')
                ! system-property(.)}&#10;</xsl:text>
  </xsl:template>
</xsl:stylesheet>
Output
From $20: b2 b3 b6
Sale total: 107.79
SAXON HE 12.10 no

$prices?* returns the map's values. Feature tests such as system-property('xsl:supports-streaming') and function-available() in use-when let one stylesheet adapt to each processor.


Other Built in Functions

document(), json-to-xml(), xml-to-json()

document() is equivalent to doc():
<xsl:value-of select="document('zoo.xml')"/>
<xsl:value-of select="doc('zoo.xml')"/>

Both instructions are equivalent.

json-to-xml() converts a JSON string into an XML representation using the http://www.w3.org/2013/XSL/json namespace:
json-to-xml('{"x": 1, "y": [3,4,5]}')
<map xmlns="http://www.w3.org/2013/XSL/json">
<number key="x">1</number>
<array key="y">
<number>3</number>
<number>4</number>
<number>5</number>
</array>
</map>

Result of the call above.

xml-to-json() performs the reverse conversion, and has two signatures:

element-available(), function-available(), type-available()

These functions test, at run time, whether a given instruction, function or type is supported by the processor. The example below tests <xsl:for-each>, substring() and xs:string.
ch06-available.xslXML
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="3.0"
            xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
            xmlns:xs="http://www.w3.org/2001/XMLSchema" >
   <xsl:template match="/">
      <xsl:value-of select="element-available('xsl:for-each')"/>
      <xsl:value-of select="function-available('substring')"/>
      <xsl:value-of select="type-available('xs:string')"/>
   </xsl:template>
</xsl:stylesheet>
Output
<?xml version="1.0" encoding="UTF-8"?>truetruetrue

current(), system-property(), unparsed-entity-public-id(), unparsed-entity-uri(), snapshot()

current() refers to the context item that was current when the containing expression began evaluating, which is not necessarily the same as a bare, optional leading dot ('.'):
<xsl:apply-templates select="//glossary/entry[@name=current()/@ref]"/>
<xsl:apply-templates select="//glossary/entry[@name=./@ref]"/>

In the first line, current() refers to the outer context item. In the second line, the dot is simply optional, and @ref belongs to the entry elements being tested — the two expressions are not equivalent.

system-property($property) returns the value of a system property; $property can be one of: 'xsl:version', 'xsl:vendor', 'xsl:vendor-url', 'xsl:product-name', 'xsl:product-version', 'xsl:is-schema-aware', 'xsl:supports-serialization', 'xsl:supports-backwards-compatibility', 'xsl:supports-namespace-axis', 'xsl:supports-streaming', 'xsl:supports-dynamic-evaluation'.
unparsed-entity-public-id($entity) returns the public identifier of the unparsed entity named by the string $entity.
unparsed-entity-uri($entity) returns the URI (system identifier) of the unparsed entity named by the string $entity.
snapshot($nodes) returns a copy of a node together with its ancestors and descendants, and their attributes and namespaces.