xsl-list
[Top] [All Lists]

Re: [xsl] Here's how to create a function that has context, without passing it context

2012-11-16 18:07:44

Your example can actually be achieved rather more simply, because functions have always had access to global variables. You could have done this using only 2.0 features:

<xsl:variable name="root" select="/"/>

<xsl:function name="f:author">
  <xsl:param name="arg" as="xs:string"/>
  <xsl:sequence select="$root//author[name=$arg]"/>
</xsl:function>

But what you're starting to discover, I think, is the fact that a dynamically-created function can hold data as well as algorithm. The data (which you call "context") usually goes by the name of a "closure": basically, at the time the function is created, it can "capture" the values of all local variables that are in scope at the time it was created, and use these values when it is subsequently invoked. The joys of functional programming!

Michael Kay
Saxonica


On 16/11/2012 23:28, Costello, Roger L. wrote:
Hi Folks,

Suppose that you would like to create a function that, given the title of a 
book, it returns the author.

For example, this function call:

     author('The Society of Mind')

returns this author:

      Marvin Minsky

Notice that the function, author(), was just provided a string and no context.

How can the function obtain the author without being given any context? Recall 
that functions supposedly have no context and you must give it (through 
parameters) all the context it needs.

In this message I show how to create functions that have context, but you don't 
have to give it the context.

This technique is so cool.

Here is the XML document that the function will operate on:

<Books>
     <Book>
           <Title>Six Great Ideas</Title>
           <Author>Mortimer J. Adler</Author>
     </Book>
     <Book>
           <Title>The Society of Mind</Title>
           <Author>Marvin Minsky</Author>
     </Book>
</Books>

I create a variable, author, that is defined to be an XPath 3.0 anonymous 
function:

<xsl:variable name="author" select="... define author as an anonymous function ... 
" />

Then I invoke the "author function" with a string representing the title of a 
book:

<xsl:value-of select="$author('The Society of Mind')" />

Here is the output:

        Marvin Minsky

This is the key to the technique:

       Create a variable that is defined to be a function that returns a 
function.

Wow!

We need to step through this very carefully.

I create a variable, root, to which I pass the root element of the XML document 
(Books):

     <xsl:variable name="root" select="function(
                                                                                
        $root_ as element(Books)
                                                                                
    )


The function returns a function:

     <xsl:variable name="root" select="function(
                                                                                
        $root_ as element(Books)
                                                                                
    )
                                                                                
   as function(xs:string) as item()


The function that is returned takes an argument that is a string representing 
the title of a book and it returns the author of the book:

     <xsl:variable name="root" select="function(
                                                                                
        $root_ as element(Books)
                                                                                
    )
                                                                                
   as function(xs:string) as item()
                                         {function($title as xs:string) as item() 
{$root_/Book[Title eq $title]/Author}}" />


Remember the author variable? It gets the returned function:

     <xsl:variable name="author" select="$root(/Books)" />


Okay, let's put it all together:
--------------------------------------------------------
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet  xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
                                xmlns:xs="http://www.w3.org/2001/XMLSchema";
                                version="3.0">
<xsl:output method="text"/> <xsl:variable name="root" select="function(
                                                                        $root_ 
as element(Books)
                                                                           )
                                                                          as 
function(xs:string) as item()
                                         {function($title as xs:string) as item() 
{$root_/Book[Title eq $title]/Author}}" />

     <xsl:variable name="author" select="$root(/Books)" />
<xsl:template match="Books">
         <xsl:value-of select="$author('The Society of Mind')" />
     </xsl:template>
</xsl:stylesheet>
--------------------------------------------------------

Pretty cool, aye?

/Roger

--~------------------------------------------------------------------
XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list
To unsubscribe, go to: http://lists.mulberrytech.com/xsl-list/
or e-mail: <mailto:xsl-list-unsubscribe(_at_)lists(_dot_)mulberrytech(_dot_)com>
--~--




--~------------------------------------------------------------------
XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list
To unsubscribe, go to: http://lists.mulberrytech.com/xsl-list/
or e-mail: <mailto:xsl-list-unsubscribe(_at_)lists(_dot_)mulberrytech(_dot_)com>
--~--