RE: [xsl] managing side-effects in XSLT

Subject: RE: [xsl] managing side-effects in XSLT
From: "Michael Kay" <michael.h.kay@xxxxxxxxxxxx>
Date: Wed, 11 Dec 2002 10:04:00 -0000
> Dimitre's warning about the sequential occurrence of code in 
> XSLT templates not implying sequential execution of 
> side-effects (if any) is still spinning in my mind. I am 
> doing quite a bit of interaction with the real world in my 
> XSLT work and one of those is JDBC access. I am assuming XSLT 
> v2.0 and XPath v2.0 as implemented in Saxon 7.
> 
> Here is some use cases and I simplify the JDBC API a lot to 
> avoid cluttering the point. I will use the following 
> namespace prefixes:
> 
> DriverManager
> Connection
> PreparedStatement
> ResultSet
> 
> and now here is in imperative java code what needs to happen:
> 
> void DriverManager.registerDriver('my.Driver');
> Connection conn = DriverManager.getConnection('jdbc:my:address');
> PreparedStatement stmt =
>     conn.prepareStatement('SELECT * FROM ANSWERS WHERE 
> QUESTION=?'); void stmt.setString(1,'HOWSITGOING') // returns 
> value that set before ResultSet rset = stmt.executeQuery();
> 
> This is a nice overview of the cases:
> 
> - static functions returning void
> - static functions returning an object
> - method functions returning an object
> - method functions returning irrelevant stuff
> 
> As I noted earlier, to make sure that thing happen in this 
> order, I want to define variables for most of these steps and 
> link them together. For the very little that I comprehend of 
> the very little that I had taken the time to read about 
> monads, this notion of a variable representing an action 
> (once it is being evaluated) is somewhat related to monads.

Basically, there's no mechanism in standard XSLT to ensure that things
happen in a particular order, or to declare that extension functions
have side-effects. In Saxon, I provide the saxon:assignable attribute
for this purpose: if you set this in an xsl:variable, the variable will
be evaluated at the point it is declared.

The other technique that's available is to pretend that you are using
the result of the function. For example, write:

<xsl:variable name="stmt"
              select="conn:prepareStatement($conn, '....')"/>
<xsl:variable name="stmt1"
              select="stmt:setString($stmt, 1, 'HOWSITGOING')"/>
<xsl:variable name="result"
              select="($stmt1, stmt:executeQuery())"/>

The fact that $stmt1 is referenced in the third variable declaration
forces the system to evaluate the variable. The actual value is void,
which maps to an empty sequence, and therefore doesn't actually affect
the value of $result. 

This isn't completely optimizer-proof, of course, because the processor
might examine the Java signature of stmt:setString, decide that the
result is void, and that therefore it doesn't need to be evaluated. At
this stage, I think your only defence is to write a Java wrapper method
that declares the result to be (say) a List, but that actually returns
an empty list. It would take a very smart optimizer to see through that
little ruse.

> 
> and here is how I can imagine practically doing it:
> 
>       if(empty($drivers-registered))
>         then DriverManager.getConnection(...)
>         else false()
> 
> this is because Saxon returns an empty sequence when a 
> function returns void. But this looks silly, so at least I 
> could define a function aliasing empty as "ensured"
> 
>       if(ensured($drivers-registered))
>         then DriverManager.getConnection(...)
>         else false()

If you don't like writing if(empty()) you could just write if(not()).

And I would suggest writing "else ()" rather than "else false()" if you
don't care what the result is: it gives the expression a cleaner static
type.
> 
> but what's ugly here is that I need this "else" part, which 
> really doesn't make sense, instead of "else" I'd need to fail.

XPath 2.0 defines an error() method to cause a failure. This isn't yet
implemented in Saxon.
> 
> Another way of doing it would be to construct a sequence and 
> then pick the last value. This is sort of reminescent of the 
> LISP PROG form:
> 
>       last($drivers-registered, DriverManager.getConnection(...))
> 
> but there is no last function for sequences standard in 
> XPath,

Just use $sequence[last()]

> 
> Wouldn't it be nice if something like that was part of 
> XSLT/XPath? 

Unfortunately the WG got its fingers badly burnt trying to specify in
detail how extension functions should behave in the XSLT 1.1 working
draft. The instinct is now to steer well clear of the area and leave it
all to implementors.

Michael Kay
Software AG
home: Michael.H.Kay@xxxxxxxxxxxx
work: Michael.Kay@xxxxxxxxxxxxxx 


 XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list


Current Thread