Hi Dimitre, hi all,
first of all, sorry for not being able to make the subject of this post nicer, but SourceForge restricts the length.
Yesterday I wasted several hours on rewriting some of my code in functional style, only to realize that certain things are simply not possible. I wanted to write a curried function that takes a node as an argument, and then I wanted that function to traverse the parent or ancestor axes. Examining the implementation of f:curry I realized that this obviously doesn't work, as arguments to a curried function are reparented into an f-curry data structure.
I'm afraid there is no way of making this work, is there? Maybe it would be nice to push the XSLT developers to either add a data type for "pointers" to nodes, or, of course, to build functional programming into the language ;-) But I'm not sure if that works.
For now, Dimitre, may I suggest that you add a warning to the documentation? Maybe in a section titled "known limitations".
Thanks in advance,
A very nice post, thank you.
Yes, this is a limitation of XSLT. We have a generate-id() function, but not its reverse.
For now, a general solution is to pass not the node itself, but a function (and its parameters) that returns the node.
This function can do something as simple as:
The document() function is guaranteed by the Spec to always return the same document-node(). Therefore, the above function will always return exactly the same node.
This is a temporary solution and I will be looking for something better.
I will also notify the other guys on the team and ask for their opinion.
thanks for your notification. I selected "monitor this forum" and will now automatically be notified by mail.
So how would identify-the-node-uniquely(other params) be implemented? I have one idea, which is not really nice, but may work: While we still have the original node, how about a function that computes a string containing an XPath that uniquely points to this node? I did a quick hack in the style of "/*/*" XPaths below, just without the XPath syntax. But maybe there is a shorter solution.
<xsl:function name="f:xpath-step" as="element()*">
<xsl:template match="f:xpath-step" mode="f:FXSL">
<xsl:param name="arg1" as="node()"/>
<xsl:param name="node" as="node()"/>
<xsl:sequence select="f:foldl(f:xpath-step(), document($document-uri), $xpath)"/>
<xsl:function name="f:get-path" as="xs:integer*">
<xsl:sequence select="for $p in $node/ancestor-or-self::* return count($p/preceding-sibling::*) + 1"/>
<xsl:variable name="xpath" select="f:get-path(.)"/>
<xsl:value-of select="$xpath" separator="/"/>
<xsl:message select="f:get-node('', $xpath)"/>
Yes, one general solution is to pass the root node of the document (I think then when it is curried the whole document will be copied), and an identifying XPath expression. I have a code snippet for producing such an expression for every type of node; here:
I still think that the efficient way to do node identification would be to have two extension functions:
bookmark = xx:bookmarkNode(node)
node = xx:getNode(bookmark)
and a possible implementation is to use an URI-Resolver.
the standard generate-id() may be used to generate the bookmark, however we still need something to remember the association (bookmark, node).
Could try implementing this in the .NET environment when I have free time.
I guess Michael Kay could implement such extension functions in Saxon; we only need to convince him they are needed :)
That's a very interesting subject (thanks Dimitre for the reminder
on the mailing list, I thought I should receive a notification, as I
actually monitor the forum, but I didn't; weird...)
I have another way in mind, though, to solve that problem, that
would also be effecient and even more general: the ability to have
nested sequences. That reminds me to ask about this for XSLT 2.1;
Because we already have a way to refer to nodes: as an item in a
sequence. The reason it is not usable for currying is because we want
to create a single one item to identify the curried function. If we
return a sequence, we wouldn't be able to use it in another sequence,
as it would then be atomized.
So we are stuck: either we put the node in an XML structure (as it
is done for now) and then it is copied (or at least that is as if it
was) or we return just the node but then, we can't return currying
information... So as you said, we have to rely on extensions here.
With nested sequences, we could simply return such a sequence (like
a regular sequence, but that would never been automatically atomized,)
with the currying info and then the curried items. I had such an
implementation for Saxon for years, but it was on the laptop that one
stole to me :-( But the idea was more or less to have a tiny proxy
object in Java that stands for a whole sequence, and an XSLT module
that encapsulate the creation of this object from a sequence and to
get the sequence back from this object.
I think this kind of sequences would help in currying implementation
(and help solving the problem currently discussed,) as well as being
more general and usable in other contexts.
What do you think? I could try to write again a PoC for this...
Thanks to MarkMail, I've eventually found a first implementation I wrote two years ago:
Oops, the forum destroyed my indentation :-( Anyway, the code works.
> With nested sequences, we could simply return such a
> sequence (like
> a regular sequence, but that would never been
> automatically atomized,)
> with the currying info and then the curried items. I
> had such an
> implementation for Saxon for years
Funny thing, I thought just a couple of days that my implementation of Finger Tree could be used.
Of course, it doesn't limit the types of its items so any item can itself be a finger tree ... :)
Interesting. I didn't know Finger Trees. If I am right,
this is a particular kind of sequences, implemented by the
help of a tree, and allowing an efficient implementation for
But maybe in this case this is too much specialized and a
simple nestable sequences API would be simpler? (Finger Trees
being one possible implementation of the API) If I am right,
Finger Trees could be used in the processor implementation
itself, helping in the string operations...
Actually, there is a problem I didn't think about earlier.
The goal is not to get a sequence that behaves as a single
item (that is not atomized) but more precisely as a single
*node*, because the FXSL dispatching mechanism is based on
The only solution I can see would be to change the f:apply()
implementation, to handle such a sequence as a special case in
which applying templates to its first item...
I've written a blog entry about some points discussed here and a few tests:
I thought that could interest you. Critics welcome!
Log in to post a comment.