2014-11-21 11:00:20 -05:00
|
|
|
<!---
|
|
|
|
Copyright (C) 2014 LoVullo Associates, Inc.
|
2015-10-08 00:00:17 -04:00
|
|
|
Copyright (C) 2015 Mike Gerwitz
|
2014-11-21 11:00:20 -05:00
|
|
|
|
|
|
|
Permission is granted to copy, distribute and/or modify this
|
|
|
|
document under the terms of the GNU Free Documentation License,
|
|
|
|
Version 1.3 or any later version published by the Free Software
|
|
|
|
Foundation; with no Invariant Sections, no Front-Cover Texts, and no
|
|
|
|
Back-Cover Texts. A copy of the license is included the file
|
|
|
|
COPYING.FDL.
|
|
|
|
-->
|
2015-10-08 00:00:17 -04:00
|
|
|
# Higher-Order XSLT
|
2014-11-21 10:53:19 -05:00
|
|
|
hoxsl is a library for XSLT 2.0, written in pure XSLT, introducing
|
|
|
|
various types of higher-order logic; 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
|
2014-11-27 00:26:58 -05:00
|
|
|
documentation as this project gets under way. This README will serve
|
|
|
|
as an informal manual until official documentation is produced.
|
2014-11-21 10:53:19 -05:00
|
|
|
|
|
|
|
|
|
|
|
## Higher-Order Functions
|
|
|
|
[Higher-order functions][xslt-30-ho] 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
|
2014-11-27 00:26:58 -05:00
|
|
|
versions of XSLT; the basis of this implementation is motivated by
|
|
|
|
Dimitre Novatchev's work on [higher-order functions in FXSL][nova-ho].
|
2014-11-21 10:53:19 -05:00
|
|
|
|
|
|
|
For example, consider an implementation of a filter function that
|
|
|
|
accepts a node set and a predicate:
|
|
|
|
|
|
|
|
```xml
|
|
|
|
<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:
|
|
|
|
|
|
|
|
```xml
|
|
|
|
<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.
|
|
|
|
|
|
|
|
|
2014-11-27 00:26:58 -05:00
|
|
|
### 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
|
2014-12-02 16:43:05 -05:00
|
|
|
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:
|
2014-11-27 00:26:58 -05:00
|
|
|
|
|
|
|
```xml
|
|
|
|
<!-- produces a new dynamic function of arity 5 - 3 = 2 -->
|
|
|
|
<variable name="partial"
|
2014-12-02 16:43:05 -05:00
|
|
|
select="my:arity5( 1, 2, 3 )" />
|
|
|
|
|
|
|
|
<!-- does the same, the long way -->
|
|
|
|
<variable name="partial-long"
|
2014-11-27 00:26:58 -05:00
|
|
|
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
|
2014-12-02 16:43:05 -05:00
|
|
|
= f:apply( my:arity5( 1, 2, 3 ), 4, 5 )
|
2014-11-27 00:26:58 -05:00
|
|
|
= 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][nova-ho] by
|
|
|
|
using only sequences, allowing arguments to retain their type and
|
|
|
|
context.
|
|
|
|
|
|
|
|
|
2014-11-21 10:53:19 -05:00
|
|
|
## 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.
|
|
|
|
|
|
|
|
[nova-ho]: http://conferences.idealliance.org/extreme/html/2006/Novatchev01/EML2006Novatchev01.html
|
|
|
|
[xslt-30-ho]: http://www.w3.org/TR/xslt-30/#dt-higher-order-operand
|