Higher-order XSLT 2.0 [archive]
 
 
 
 
Go to file
Mike Gerwitz 3dfd8eca2b
README.md: Terminology correction (logic=>operations)
This is _not_ higher-order logic.  I clearly had my terminology confused
at the time.
2023-03-19 22:40:45 -04:00
doc Update manual copyright for 2016 2016-04-01 22:04:03 -04:00
src apply-gen stylesheet version copy if provided 2016-07-05 00:16:36 -04:00
test apply-gen stylesheet version copy if provided 2016-07-05 00:16:36 -04:00
tools Remove lingering tools/xsltexi reference 2016-08-23 14:54:16 -04:00
.gitignore Use configure-time path for literate-xsl over submodule 2015-09-29 22:57:21 -04:00
.gitmodules Use configure-time path for literate-xsl over submodule 2015-09-29 22:57:21 -04:00
COPYING Project scaffolding modeled after xslink 2014-11-20 11:59:54 -05:00
COPYING.FDL README.md licensed under the FDL 1.3 2014-11-22 00:05:11 -05:00
INSTALL Add INSTALL 2016-07-20 00:20:15 -04:00
Makefile.am Add INSTALL to distribution 2016-07-20 00:21:45 -04:00
README.md README.md: Terminology correction (logic=>operations) 2023-03-19 22:40:45 -04:00
configure.ac Use configure-time path for literate-xsl over submodule 2015-09-29 22:57:21 -04:00

README.md

Higher-Order XSLT

hoxsl is a library for XSLT 2.0, written in pure XSLT, introducing various higher-order operations; this includes higher-order functions and XSLT templates that take XSLT as input and produce XSLT as output.

The system is fully tested---see the test cases for additional documentation as this project gets under way. The manual is "woven" from literate sources; a compiled version is available online.

Higher-Order Functions

Higher-order functions are a part of XSLT 3.0, but implementations that support them (such as Saxon) hide it behind proprietary versions of their software. Others still may wish to continue using XSLT 2.0.

There are various approaches/kluges for this problem in earlier versions of XSLT; the basis of this implementation is motivated by Dimitre Novatchev's work on higher-order functions in FXSL.

For example, consider an implementation of a filter function that accepts a node set and a predicate:

  <xsl:function name="my:filter" as="xs:element()*">
    <xsl:param name="nodes" as="xs:element()*" />
    <xsl:param name="pred" />

    <xsl:for-each select="$nodes">
      <xsl:if test="f:apply( $pred, . )">
        <xsl:sequence select="." />
      </xsl:if>
    </xsl:for-each>
  </xsl:function>


  <xsl:function name="my:pred" as="xs:boolean">
    <xsl:param name="node" as="element()" />

    <xsl:sequence select="$node/@foo = 'true'" />
  </xsl:function>

We could then apply a filter using this predicate like so:

  <sequence select="my:filter( $nodes, my:pred() )" />

hoxsl takes this a step further by providing a stylesheet to generate the boilerplate necessary for functions to be able to be applied using f:apply, as shown above. Applying tranform/apply-gen.xsl to the XSL stylesheet containing the above function definitions would produce output that can be directly imported (as a stylesheet); no additional work is needed. This can be included as part of a build process, and the output included within a distribution.

Partial Applications

Dynamic function applications using f:apply are partially applied if the number of arguments provided is less than the arity of the target function. For convenience, the apply-gen stylesheet will also generate functions to perform partial application without the use of f:apply for the first call, as in the first example below:

  <!-- produces a new dynamic function of arity 5 - 3 = 2 -->
  <variable name="partial"
            select="my:arity5( 1, 2, 3 )" />

  <!-- does the same, the long way -->
  <variable name="partial-long"
            select="f:apply( my:arity5(), 1, 2, 3 )" />

  <!-- consequently, currying is supported -->
  <variable name="result"
            select="f:apply( f:apply( $partial, 4 ), 5 )" />

  <!-- equiv = true() -->
  <variable name="equiv"
            select="$result
                    = f:apply( my:arity5( 1, 2, 3 ), 4, 5 )
                    = f:apply( my:arity5(), 1, 2, 3, 4, 5 )
                    = my:arity5( 1, 2, 3, 4, 5 )" />

The implementation of partial function applications avoids the complexity and inaccuracies of Novatchev's approach by using only sequences, allowing arguments to retain their type and context.

License

This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.