xsl-list
[Top] [All Lists]

RE: managing side-effects in XSLT

2002-12-11 03:04:00
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(_dot_)H(_dot_)Kay(_at_)ntlworld(_dot_)com
work: Michael(_dot_)Kay(_at_)softwareag(_dot_)com 


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



<Prev in Thread] Current Thread [Next in Thread>