Page 2 of 11

 

  Previous Page Table Of ContentsNext Page
Table of Contents

 Introduction
 Starting point
 Major FP design patterns/functions in XSLT
 List processing
 Tree processing
 Lazy evaluation
 Advanced XSLT FP applications
 Square root
 Numerical differentiation
 Numerical integration
 Summary


The Functional Programming Language XSLT - A proof through examples

Starting point

As a starting point, let's define some basic terminology and present examples of the use of higher-order functions in FP. Then, we'll take a first step towards our FP implementation in XSLT by defining the  "template reference" data type and demonstrate a simple example of its use.

Imperative programming

The imperative style of programming describes a system as evolving from an initial state through a series of state changes to a set of desired final states. A program consists of commands that change the state of the system. For example:

   y = y + 3

will bring the system into a new state, in which the variable y has a new value, which has been obtained by adding 3 to the value of y in the previous state of the system.

Declarative programming

The declarative programming style specifies relationships between different variables, e.g. the equation

 z = y + 3 

declares z to have a value of three more than the value of y. Variables, once declared, cannot change their value. Typically, there is no concept of state, order of execution, memory,... etc.

 In XSLT, the declarative approach is used: e.g.:

<xsl:variable name="z" select= "$y + 3" /> 

is the XSLT version of the mathematical equation above.

Functional programming

A function is a relationship between a set of inputs and an output. It can also be regarded as an operation, which when passed specific values as input produces a specific output.

A functional program is made up of a series of definitions of functions and other values [7].

The functional programming style builds upon the declarative programming style by adding the ability to treat functions as first-class objects -- that means among other things that functions can be passed as arguments to other functions. A function can also return another function as its result.

Higher-order functions in FP languages

A function is higher order if it takes a function as an argument or returns a function as a result, or both [7].

      Examples. 

A classical example is the map function, which can be defined in Haskell in the following two ways:

map   f    xs     =  [ f  x  |   x  <-  xs ]                             (1)
or
map   f   [ ]     =  [ ]
                                                                         (2)
map   f  (x:xs)   =   f  x   :   map   f    xs

 

The map function takes two arguments  --  another function   f  and a list  xs . The result is a list, every element of which is the result of applying  f  to the corresponding element of the list  xs .

If we define f as :

f x = x + 3

and xs as

[1, 2, 3]

Then  the value of 

map   f    xs  

is

[4, 5, 6]

 

The map  function can be used to produce many other functions. For example, we can define a function to produce from a list a new one, whose elements' values are twice as big as the values of the elements of the input list:

doubleall  xs  =  map (* 2) xs

where (* 2) is a function, that produces a result twice as bigger as its input.

Another classical example is functional composition:

(.) f g x  =  f (g x)

Higher-order functions in XSLT -- implementation of template references

Higher order functions can be implemented in XSLT by way of the template reference datatype.

Explanation through an example

Templates in XSLT correspond to functions in FP languages. Named templates are always called by a corresponding xsl:call-template instruction. Templates with a match attribute are usually selected for instantiation in a less direct way -- from all templates matching the node-set specified in an xsl:apply-templates instruction.

Parameters can be declared for templates using xsl:param children of xsl:template and actual values for the parameters can be specified using xsl:with-param children of either xsl:call-template or xsl:apply-templates.

The result of calling/applying a template is always a particular output. Therefore, an XSLT template fits precisely the definition of a function.

As noted before, it is believed that XSLT is not a full functional programming language, because functions cannot be passed as parameters to other functions -- not that XSLT lacks functions at all. We accept that XSLT templates serve the role of functions, and want to show that functions (templates) can be passed as parameters to other functions (templates).

Unfortunately, it is not possible to specify through a variable the name of a template to be called, e.g.:

<xsl:call-template name="$aTemplate"/>

because according to the W3 XSLT Spec. [8] the value of the name attribute can only be a Q-Name. A Q-Name is static and must be completely specified  -- it cannot be dynamically produced by the contents of a variable.

Another way to instantiate a template dynamically has been known for quite some time [9], but there's no evidence until now of using it in a systematic manner. Let's have a template, which matches only a single node belonging to a unique namespace. In the rest of the text we'll call such nodes "nodes having a unique type":

File: example1.xsl

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version = "1.0 " >
 <xsl:template match="*[namespace-uri()='8B9C63F4-F4AB5D11-994A0001-B4CD626F'] ">
     <xsl:param name = "pX " />

     <xsl:value-of select = "2 * $pX " />
 </xsl:template>

 <xsl:template match="*[namespace-uri()='AB02AC1C-1C65B3FF-77C5FFFE-4B329DA1'] ">
     <xsl:param name = "pX " />

     <xsl:value-of select = "3 * $pX " />
 </xsl:template>
</xsl:stylesheet>

We have defined two templates, each matching only a node of a unique type. The first template produces the value of its input parameter pX multiplied by 2. The second template produces the value of its input parameter pX multiplied by 3.

Now we'll define in another stylesheet a template that accepts as parameters references to two other templates (template references), instantiates the two templates that are referenced by its template-reference parameters, passing as parameter to each instantiation its pX parameter, then as result it produces the sum of the outputs of these instantiated templates.

<xsl:stylesheet  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:f1="8B9C63F4-F4AB5D11-994A0001-B4CD626F"
  xmlns:f2="AB02AC1C-1C65B3FF-77C5FFFE-4B329DA1"
>

         <xsl:import href = "example1.xsl" />
         <xsl:output method = "text" />

         <f1:f1/>
         <f2:f2/>

         <xsl:template match = "/" >
             <xsl:variable name = "vFun1" select = "document('')/*/f1:*[1]" />
             <xsl:variable name = "vFun2" select = "document('')/*/f2:*[1]" />

             <xsl:call-template name = "mySum" >
                 <xsl:with-param name = "pX" select = "3" />
                 <xsl:with-param name = "pFun1" select = "$vFun1" />
                 <xsl:with-param name = "pFun2" select = "$vFun2" />
             </xsl:call-template>
         </xsl:template>

         <xsl:template name = "mySum" >
             <xsl:param name = "pX" />
             <xsl:param name = "pFun1" select = "/.." />
             <xsl:param name = "pFun2" select = "/.." />

             <xsl:variable name = "vFx_1" >
                 <xsl:apply-templates select = "$pFun1" >
                     <xsl:with-param name = "pX" select = "$pX" />
                 </xsl:apply-templates>
             </xsl:variable>

             <xsl:variable name = "vFx_2" >
                 <xsl:apply-templates select = "$pFun2" >
                     <xsl:with-param name = "pX" select = "$pX" />
                 </xsl:apply-templates>
             </xsl:variable>

             <xsl:value-of select = "$vFx_1 + $vFx_2" />
         </xsl:template>

     </xsl:stylesheet>

The result produced when this last stylesheet is applied on any (dummy) xml source document, is:

15

What we have effectively done is we called the template named "mySum", passing to it two references to templates, that accept a pX parameter and produce something out of it. The "mySum" template successfully instantiates (applies/calls) the templates that are uniquely identified by the template reference parameters, then produces the sum of their results. What guarantees that exactly the necessary templates will be selected by the XSLT processor is the unique namespace-uri of the nodes they are matching. The most important property of a template reference is that it guarantees the unique matching of the template that it is referencing.

The next two sections demonstrate that by using the template reference datatype just as described above we can implement even the most powerful FP design patterns/functions. 

 

Page 2 of 11

 

Previous Page Table Of ContentsNext Page

SourceForge.net Logo