Project

Profile

Help

xslt2 user-defined function called only once

Added by Anonymous almost 17 years ago

Legacy ID: #4558028 Legacy Poster: R. (roadrunner2)

I defined a function in an xslt2 stylesheet to generated a UUID (currently by calling out to Java's UUID class). However, it doesn't always get called, but instead sometimes is only called once and the result reused, which isn't quite the intention. Here's a sample that demonstrates this: <?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:my="my:foo" > <xsl:template match="/" xml:space="preserve"> <xsl:message>first loop</xsl:message> <xsl:for-each select="(1, 2, 3)"> <foo about="{concat('uuid:', my:gen-uuid())}"/> </xsl:for-each> <xsl:message>second loop</xsl:message> <xsl:for-each select="(1, 2, 3)"> <foo about="{my:gen-uuid()}"/> </xsl:for-each> </xsl:template> <xsl:function name="my:gen-uuid"> <xsl:message>gen-uuid called</xsl:message> <xsl:value-of xmlns:uuid="java:java.util.UUID" select="uuid:randomUUID()"/> </xsl:function> </xsl:stylesheet> In the first loop my:gen-uuid is only called only once, resulting in 3 identical foo elements; in the second loop, however, my:gen-uuid is called in each iteration, as desired. I also noticed that if I pass a dummy parameter to my:gen-uuid that differs each time (e.g. position()) then it works correctly. I tried this on both saxon 8.7 and 8.9, btw. So my question is: is this a bug, or is this intended? And if the latter, what's the most reliable way of ensuring the function gets called every time? A dummy parameter? I also tried specifying saxon:memo-function="no" on the function, but that didn't help. I'm somewhat aware of the fact that xslt is supposed to be functional, and that functions therefore aren't supposed to have side-effects. But I could not find anything in the xslt 2.0 specs that actually said this (though if I missed it, a pointer would be appreciated). How then does one define functions such as uuid() or rand() that return differing results each time?


Replies (2)

RE: xslt2 user-defined function called only o - Added by Anonymous almost 17 years ago

Legacy ID: #4559133 Legacy Poster: Michael Kay (mhkay)

It's not a bug: the behaviour of functions with side-effects is explicitly undefined, and this is to allow exactly the kind of optimizations that you are observing. See the note in 18.1.2: There is no prohibition on calling extension functions that have side-effects (for example, an extension function that writes data to a file). However, the order of execution of XSLT instructions is not defined in this specification, so the effects of such functions are unpredictable. Sometimes the problem is to ensure that the function is actually called. You can ensure this (in Saxon) by making the call in a position where the result would be used if there is a result - Saxon carefully refrains from noticing that the result type is actually void and that the return value therefore has no effect. Sometimes, as here, the problem is ensuring that the function is called the right number of times. That's harder. The design of exslt:random() does this by having a single call on the function return a sequence of random numbers. That's a clean design, but it can be difficult to select the number you want to use from the list. However, to get UUIDs you could try that approach. Giving the function a dummy argument that depends on the context (position() or ".") is enough to stop the call being moved outside a for-each loop or an XPath predicate. At least until the optimizer gets even cleverer.

RE: xslt2 user-defined function called only o - Added by Anonymous almost 17 years ago

Legacy ID: #4559608 Legacy Poster: R. (roadrunner2)

Thank you for your time and answer. I saw 18.1.2, but I guess I didn't fully appreciate what it was saying, namely that an implementation is free to reorder things, even if it changes the final results? Hmm. The idea of generating a sequence of uuid's in one call and then selecting a different one in each place you need a uuid is interesting. Except that, as you say, it can be difficult (I would say fairly horrendous, actually). Oh well. Thanks for the clarifications.

    (1-2/2)

    Please register to reply