Discussion:
How to use generate-id() inside an xsl:function without a node available?
Abel Braaksma
2007-02-27 20:04:51 UTC
Permalink
Hi List,

This seems an obvious question to ask, but I couldn't find anything on
the net (but more often than not, it is a matter of wrong keywords, I am
sure). The issue is this: I have a function that generates some nodes
based on some strings and these nodes must receive a unique ID/IDREF
value. Normally, one would use generate-id(), but inside a function (or
inside anything that does not have a context node), generate-id() will fail.

My question: how can I create unique identifiers without a node in sight?

Example function (which will err):

<xsl:function name="my:dupSVGText">
<xsl:variable name="new-id" select="generate-id()" />
<svg:text id="{$new-id}">some text</svg:text>
<svg:use xlink:href="#{$new-id}" y="10" />
</xsl:function>

My original function is a bit larger (ahum, counted > 100 lines today,
time for refactoring...) and creates some SVG objects that reference one
another, which is why I must make sure the ID for referencing the
xlink:href attributes are unique within the document. Don't let the SVG
and XLink upset or distract you, I just mention it to explain my use-case.

And no, there's no way that there will be a node in sight (it is really
disconnected from the source document). Yes, I can use different
techniques than xsl:function if needed (of course). Oh, and before I
forget: I can do so with extension functions or assignable variables
(saxon), but I'd rather not to.

Any ideas? It seems easy enough, but I couldn't find any (quick)
resolutions.

TIA,

Cheers,
-- Abel

--~------------------------------------------------------------------
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-***@lists.mulberrytech.com>
--~--
Andrew Welch
2007-02-27 20:20:48 UTC
Permalink
Post by Abel Braaksma
Hi List,
This seems an obvious question to ask, but I couldn't find anything on
the net (but more often than not, it is a matter of wrong keywords, I am
sure). The issue is this: I have a function that generates some nodes
based on some strings and these nodes must receive a unique ID/IDREF
value. Normally, one would use generate-id(), but inside a function (or
inside anything that does not have a context node), generate-id() will fail.
My question: how can I create unique identifiers without a node in sight?
<xsl:function name="my:dupSVGText">
<xsl:variable name="new-id" select="generate-id()" />
<svg:text id="{$new-id}">some text</svg:text>
<svg:use xlink:href="#{$new-id}" y="10" />
</xsl:function>
My original function is a bit larger (ahum, counted > 100 lines today,
time for refactoring...) and creates some SVG objects that reference one
another, which is why I must make sure the ID for referencing the
xlink:href attributes are unique within the document. Don't let the SVG
and XLink upset or distract you, I just mention it to explain my use-case.
And no, there's no way that there will be a node in sight (it is really
disconnected from the source document). Yes, I can use different
techniques than xsl:function if needed (of course). Oh, and before I
forget: I can do so with extension functions or assignable variables
(saxon), but I'd rather not to.
As generate-id() provides node identity and "there's no node in sight"
then I would say generate-id() is the wrong function to use here.

I guess you'll have to add a param to the function and supply the id -
whatever's calling the function should be able to come up with a
suitable value...

--~------------------------------------------------------------------
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-***@lists.mulberrytech.com>
--~--
Abel Braaksma
2007-02-27 20:32:34 UTC
Permalink
Post by Andrew Welch
I guess you'll have to add a param to the function and supply the id -
whatever's calling the function should be able to come up with a
suitable value...
Hi Andrew,

That wouldn't help me here, because the element is the same element for
a long time in the process chain... and I need *many* id's of which I
don't know in advance what the amount will be... :S

-- Abel

--~------------------------------------------------------------------
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-***@lists.mulberrytech.com>
--~--
David Carlisle
2007-02-27 20:44:02 UTC
Permalink
You can always generate a new node, then generate-id() will generate a
new id,

<xsl:variable name="x">x</xsl:variable>
...generate-id($x)...
but generating new nodes just to discard may be a bit expensive

David

--~------------------------------------------------------------------
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-***@lists.mulberrytech.com>
--~--
Florent Georges
2007-02-27 20:22:11 UTC
Permalink
Abel Braaksma wrote:

Hi
Post by Abel Braaksma
The issue is this: I have a function that generates some
nodes based on some strings and these nodes must receive a
unique ID/IDREF value. Normally, one would use
generate-id(), but inside a function (or inside anything
that does not have a context node), generate-id() will
fail.
The point is that generate-id() is not a random string
generator. It generates an ID based on a node, always the
same ID for the same node. If you call it without argument,
the context item is used (which is indeed not possible in a
function definition).

If you can't use extension functions nor pass a reference
node to the function, I'm afraid you are out of luck here.

Regards,

--drkm

























___________________________________________________________________________
Découvrez une nouvelle façon d'obtenir des réponses à toutes vos questions !
Profitez des connaissances, des opinions et des expériences des internautes sur Yahoo! Questions/Réponses
http://fr.answers.yahoo.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-***@lists.mulberrytech.com>
--~--
Abel Braaksma
2007-02-27 20:35:36 UTC
Permalink
Post by Florent Georges
If you can't use extension functions nor pass a reference
node to the function, I'm afraid you are out of luck here
Well, I *can* use extension functions, I just don't want to resort to
using them (for any number of reasons, amongst which: portability).

I just hoped you'd have some better news for me... :S

-- Abel

--~------------------------------------------------------------------
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-***@lists.mulberrytech.com>
--~--
Florent Georges
2007-02-27 20:54:44 UTC
Permalink
Post by Abel Braaksma
Post by Florent Georges
If you can't use extension functions nor pass a
reference node to the function, I'm afraid you are out
of luck here
Well, I *can* use extension functions, I just don't want
to resort to using them (for any number of reasons,
amongst which: portability).
I just hoped you'd have some better news for me... :S
Mmh, sorry for the false alert. I didn't think to
generate a new node each time within the function, as
suggested by David and Dimitre.

I definitively need a break (and a lunch :-p).

Sorry,

--drkm


























___________________________________________________________________________
Découvrez une nouvelle façon d'obtenir des réponses à toutes vos questions !
Profitez des connaissances, des opinions et des expériences des internautes sur Yahoo! Questions/Réponses
http://fr.answers.yahoo.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-***@lists.mulberrytech.com>
--~--
Abel Braaksma
2007-02-27 20:46:18 UTC
Permalink
Post by Florent Georges
The point is that generate-id() is not a random string
generator. It generates an ID based on a node, always the
same ID for the same node. If you call it without argument,
the context item is used (which is indeed not possible in a
function definition).
Found it!
You nevertheless brought something up: why not simply *create* the node
each time again?. Here's a simple enough (but process intensive) solution:

<xsl:for-each select="(1 to 20)" >
<xsl:variable name="id-node"><some-node /></xsl:variable>
<some-elem id="{generate-id($id-node)}" />
</xsl:for-each>

this generates unique ids, even on recursive calling of the function (if
the for-each is wrapped inside a function). Not sure this is "REC
behavior", but it sure does what I want. Maybe someone can confirm that
this is indeed the expected behavior and that I can rely on the method
to return a unique id value within the same process.

This may also suit requirements where a random, unique value is needed,
though "random" is not really what is being generated. I get: d28, d29,
d30 etc.

Thanks for looking into it,

Cheers,
-- Abel Braaksma

--~------------------------------------------------------------------
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-***@lists.mulberrytech.com>
--~--
Colin Adams
2007-02-27 21:12:12 UTC
Permalink
Post by Abel Braaksma
You nevertheless brought something up: why not simply *create* the node
<xsl:for-each select="(1 to 20)" >
<xsl:variable name="id-node"><some-node /></xsl:variable>
<some-elem id="{generate-id($id-node)}" />
</xsl:for-each>
this generates unique ids, even on recursive calling of the function (if
the for-each is wrapped inside a function). Not sure this is "REC
behavior", but it sure does what I want. Maybe someone can confirm that
this is indeed the expected behavior and that I can rely on the method to
return a unique id value within the same process.
Yes and yes.
Post by Abel Braaksma
This may also suit requirements where a random, unique value is needed,
though "random" is not really what is being generated. I get: d28, d29, d30
etc.
It is only random in the sense that it depends which processor you run it
upon.

_________________________________________________________________
MSN Hotmail is evolving – check out the new Windows Live Mail
http://ideas.live.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-***@lists.mulberrytech.com>
--~--
Michael Kay
2007-02-27 21:16:33 UTC
Permalink
Post by Abel Braaksma
<xsl:variable name="id-node"><some-node /></xsl:variable>
<some-elem id="{generate-id($id-node)}" /> </xsl:for-each>
this generates unique ids, even on recursive calling of the
function (if the for-each is wrapped inside a function). Not
sure this is "REC behavior", but it sure does what I want.
Maybe someone can confirm that this is indeed the expected
behavior and that I can rely on the method to return a unique
id value within the same process.
Yes, you can rely on this behaviour. It's one of the messier aspects of the
XSLT/XQuery processing model that there is this slight side-effect of
calling functions - it means that some of the optimizations done in other
functional programming languages can't safely by done in XSLT or XQuery.

Michael Kay
http://www.saxonica.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-***@lists.mulberrytech.com>
--~--
Andrew Welch
2007-02-27 22:27:59 UTC
Permalink
Post by Abel Braaksma
<xsl:for-each select="(1 to 20)" >
<xsl:variable name="id-node"><some-node /></xsl:variable>
<some-elem id="{generate-id($id-node)}" />
</xsl:for-each>
Out of interest, how can you call a function multiple times and not be
able to create an ID in the code in the code that makes the call?

For example, in the above code snippet you have (1 to 20) to use. If
you were iterating over nodes you could use them. In a recursive
named template you could use the value you're recursing with etc...

My point is - in what situation would you need to create a node to
call generate-id() on?

--~------------------------------------------------------------------
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-***@lists.mulberrytech.com>
--~--
Abel Braaksma
2007-02-27 23:00:19 UTC
Permalink
Post by Andrew Welch
Out of interest, how can you call a function multiple times and not be
able to create an ID in the code in the code that makes the call?
For example, in the above code snippet you have (1 to 20) to use. If
you were iterating over nodes you could use them. In a recursive
named template you could use the value you're recursing with etc...
My point is - in what situation would you need to create a node to
call generate-id() on?
Well, you asked for it ;)

The story started like this: transform some tabulated data (inside XML)
into some nicely formatted PDF table using XSL-FO. Simple enough. But
there came the requirement: please make it look "professional" and add
skewed and bottom-up texts as the headers. I'm not sure of your
understanding of XSL-FO, but I quickly found out that bottom-up texts,
skewing (and rotating), along with skewed lines were not amongst the
default possibilities of XSL-FO.

In came: SVG. Never done a thing in SVG, but after a couple of hours I
found a nice-enough solution using <svg:defs>, <svg:filters>, <svg:use>
and many others. SVG is hard without the use of ID and IDREF values (and
XLink for that matter). The headers I was talking of earlier on are
repeated on several occasions in the same XSL-FO file, and the IDs of
all these elements must be unique.

The number of captions was variable, so I chose a simple approach (I
though) for creating them (Michael, I added the type definition this time!):

<xsl:function name="my:caption" as="element()">
<xsl:param name="caption-list" as="xs:string+" />
<xsl:param name="style-list" as="xs:string+" />
.... create SVG and FO parts
</xsl:function>

Now, this design has some flaws, but (oh irony) because I didn't want to
create intermediate nodes, I chose sequences of strings. The reason
being: quick implementation and easy match to my current input, and no
extra XML structure to remember.

Well, by now you may already understand where the problem came in: yes,
indeed, while inside the above function, it is not possible to use, in
any way, generate-id, without first generating a node. If I new this
beforehand, I might have chosen a different approach. But still, using
nodes, it would not be enough, because these nodes are referenced
several times and generate-id() would then create the same ID each time
and I don't want that (SVG won't even work then).

To make the long story short: yes, there are workarounds, and no, I
cannot use nodes alone (I'd have to add some way of numbering, which is,
I may add, a very cruel way of making something unique).

You may want to ask why I need to reference the same node several times.
Well, the answer would be: svg:use to create some filter effects, some
additional paths and some lines, all for one caption.

Last but not least: in general, when you have a function that returns a
node with an ID value (according to xml:id must be unique in the
document), and you want this function to be "safe" (i.e.: always return
a unique id), you cannot rely on a node that is passed in: it is
next-to-impossible to test for the uniqueness of the node itself, and
when the function would be called twice with the same node, you want it
to return two nodes with different ID values (consider <a name="id" />
or the SVG situation above).

I know, this seems to be strongly against the "no-side-effects" rule and
against the principle that when a function is called twice with the same
arguments it should return the same results. Well, this is the exception
to the rule (as Michael explained).

Cheers,
-- Abel Braaksma

--~------------------------------------------------------------------
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-***@lists.mulberrytech.com>
--~--
Dimitre Novatchev
2007-02-27 20:44:53 UTC
Permalink
Hve an auxiliary function, which creates a new node every time t is
evaluated, for example using:

<xsl:function name="pref:GetNode" as="element()">
<xsl:variable name="myNode" as="element()">
<someNode/>
</xsl:variable>

<xsl:copy-of select="$myNode"/>
<xsl:function


Then in your code use:

generate-id(pref:GetNode() )
--
Cheers,
Dimitre Novatchev
---------------------------------------
Truly great madness cannot be achieved without significant intelligence.
---------------------------------------
To invent, you need a good imagination and a pile of junk
-------------------------------------
You've achieved success in your field when you don't know whether what
you're doing is work or play
Post by Abel Braaksma
Hi List,
This seems an obvious question to ask, but I couldn't find anything on
the net (but more often than not, it is a matter of wrong keywords, I am
sure). The issue is this: I have a function that generates some nodes
based on some strings and these nodes must receive a unique ID/IDREF
value. Normally, one would use generate-id(), but inside a function (or
inside anything that does not have a context node), generate-id() will fail.
My question: how can I create unique identifiers without a node in sight?
<xsl:function name="my:dupSVGText">
<xsl:variable name="new-id" select="generate-id()" />
<svg:text id="{$new-id}">some text</svg:text>
<svg:use xlink:href="#{$new-id}" y="10" />
</xsl:function>
My original function is a bit larger (ahum, counted > 100 lines today,
time for refactoring...) and creates some SVG objects that reference one
another, which is why I must make sure the ID for referencing the
xlink:href attributes are unique within the document. Don't let the SVG
and XLink upset or distract you, I just mention it to explain my use-case.
And no, there's no way that there will be a node in sight (it is really
disconnected from the source document). Yes, I can use different
techniques than xsl:function if needed (of course). Oh, and before I
forget: I can do so with extension functions or assignable variables
(saxon), but I'd rather not to.
Any ideas? It seems easy enough, but I couldn't find any (quick)
resolutions.
TIA,
Cheers,
-- Abel
--~------------------------------------------------------------------
XSL-List info and archive: http://www.mulberrytech.com/xsl/xsl-list
To unsubscribe, go to: http://lists.mulberrytech.com/xsl-list/
--~--
--~------------------------------------------------------------------
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-***@lists.mulberrytech.com>
--~--
Abel Braaksma
2007-02-27 20:51:22 UTC
Permalink
Post by Dimitre Novatchev
Hve an auxiliary function, which creates a new node every time t is
generate-id(pref:GetNode() )
<xsl:variable name="x">x</xsl:variable>
...generate-id($x)...
but generating new nodes just to discard may be a bit expensive
thanks to you both, yes, that is indeed what I was looking for. About
expensiveness: I just did some test and my main process goes from 1.2
seconds to 1.2 seconds and generates about 100 of these throw-away
nodes, so for the not too demanding environments, the performance hit is
negliciable (?word?)

-- Abel

--~------------------------------------------------------------------
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-***@lists.mulberrytech.com>
--~--
Dimitre Novatchev
2007-02-27 21:30:03 UTC
Permalink
Cheap impementation.
=================

It may even be possible to only use one node (and then immediately
delete it as part of the closing of the scope of the function. Looking
at the spec I am not sure, however if re-using the generated ID for a
node (which is no longer alive) is allowed or not. If it is not
allowed, then we have the following *cheap* implementation:



<xsl:function name="pref:myId" as="xs:string">
<xsl:variable name="myNode" as="element()">
<someNode/>
</xsl:variable>

<xsl:variable name="vdynNode" as="element()">
<xsl:copy-of select="$myNode"/>
</xsl:variable>

<xsl:sequence select="generate-id($vdynNode)"/>

<xsl:function
--
Cheers,
Dimitre Novatchev
---------------------------------------
Truly great madness cannot be achieved without significant intelligence.
---------------------------------------
To invent, you need a good imagination and a pile of junk
-------------------------------------
You've achieved success in your field when you don't know whether what
you're doing is work or play
Post by Dimitre Novatchev
Hve an auxiliary function, which creates a new node every time t is
<xsl:function name="pref:GetNode" as="element()">
<xsl:variable name="myNode" as="element()">
<someNode/>
</xsl:variable>
<xsl:copy-of select="$myNode"/>
<xsl:function
generate-id(pref:GetNode() )
--
Cheers,
Dimitre Novatchev
---------------------------------------
Truly great madness cannot be achieved without significant intelligence.
---------------------------------------
To invent, you need a good imagination and a pile of junk
-------------------------------------
You've achieved success in your field when you don't know whether what
you're doing is work or play
Post by Abel Braaksma
Hi List,
This seems an obvious question to ask, but I couldn't find anything on
the net (but more often than not, it is a matter of wrong keywords, I am
sure). The issue is this: I have a function that generates some nodes
based on some strings and these nodes must receive a unique ID/IDREF
value. Normally, one would use generate-id(), but inside a function (or
inside anything that does not have a context node), generate-id() will fail.
My question: how can I create unique identifiers without a node in sight?
<xsl:function name="my:dupSVGText">
<xsl:variable name="new-id" select="generate-id()" />
<svg:text id="{$new-id}">some text</svg:text>
<svg:use xlink:href="#{$new-id}" y="10" />
</xsl:function>
My original function is a bit larger (ahum, counted > 100 lines today,
time for refactoring...) and creates some SVG objects that reference one
another, which is why I must make sure the ID for referencing the
xlink:href attributes are unique within the document. Don't let the SVG
and XLink upset or distract you, I just mention it to explain my use-case.
And no, there's no way that there will be a node in sight (it is really
disconnected from the source document). Yes, I can use different
techniques than xsl:function if needed (of course). Oh, and before I
forget: I can do so with extension functions or assignable variables
(saxon), but I'd rather not to.
Any ideas? It seems easy enough, but I couldn't find any (quick)
resolutions.
TIA,
Cheers,
-- Abel
--~------------------------------------------------------------------
XSL-List info and archive: http://www.mulberrytech.com/xsl/xsl-list
To unsubscribe, go to: http://lists.mulberrytech.com/xsl-list/
--~--
--~------------------------------------------------------------------
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-***@lists.mulberrytech.com>
--~--
David Carlisle
2007-02-27 21:39:25 UTC
Permalink
<xsl:function name="pref:myId" as="xs:string">
<xsl:variable name="myNode" as="element()">
<someNode/>
</xsl:variable>

<xsl:variable name="vdynNode" as="element()">
<xsl:copy-of select="$myNode"/>
</xsl:variable>

<xsl:sequence select="generate-id($vdynNode)"/>

<xsl:function


surely you can lose the first variable and write that as

<xsl:function name="pref:myId" as="xs:string">
<xsl:variable name="myNode" as="element()">
<someNode/>
</xsl:variable>

<xsl:sequence select="generate-id($myNode)"/>

<xsl:function

or in xquery,no variables at all, just generate-id(<somenode/>)

David

--~------------------------------------------------------------------
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-***@lists.mulberrytech.com>
--~--
Dimitre Novatchev
2007-02-27 21:42:07 UTC
Permalink
Post by Dimitre Novatchev
<xsl:function name="pref:myId" as="xs:string">
<xsl:variable name="myNode" as="element()">
<someNode/>
</xsl:variable>
<xsl:variable name="vdynNode" as="element()">
<xsl:copy-of select="$myNode"/>
</xsl:variable>
<xsl:sequence select="generate-id($vdynNode)"/>
<xsl:function
surely you can lose the first variable and write that as
<xsl:function name="pref:myId" as="xs:string">
<xsl:variable name="myNode" as="element()">
<someNode/>
</xsl:variable>
<xsl:sequence select="generate-id($myNode)"/>
<xsl:function
I think in this case generate-id() will be applied on the same node
again and again and will return the same string -- this is why I want
always to have a new copy of it -- or am I wrong?
--
Cheers,
Dimitre Novatchev
---------------------------------------
Truly great madness cannot be achieved without significant intelligence.
---------------------------------------
To invent, you need a good imagination and a pile of junk
-------------------------------------
You've achieved success in your field when you don't know whether what
you're doing is work or play

--~------------------------------------------------------------------
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-***@lists.mulberrytech.com>
--~--
David Carlisle
2007-02-27 21:52:10 UTC
Permalink
Post by Dimitre Novatchev
I think in this case generate-id() will be applied on the same node
again and again and will return the same string -- this is why I want
always to have a new copy of it -- or am I wrong?
no a literal result element like <x/> is (more or less) the same as using
<xsl:element name="x"/> it's a single node in the stylesheet but it
generates a new node each time it's executed, and generate-id() is being
applied to that result. You don't need an element at all of course, a
text node will do

<xsl:function name="pref:myId" as="xs:string">
<xsl:variable name="myNode">x</xsl:variable>

<xsl:sequence select="generate-id($myNode)"/>

<xsl:function



(you can't use
<xsl:variable name="myNode"/> as that generates a zero length string
not a node at all, for reasons of xslt1 cmpatibility)

David

--~------------------------------------------------------------------
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-***@lists.mulberrytech.com>
--~--
David Carlisle
2007-02-27 21:57:35 UTC
Permalink
slight correction...
Post by David Carlisle
You don't need an element at all of course, a
text node will do
wih is true, but I gave the example

<xsl:variable name="myNode">x</xsl:variable>

which returns a document node not a text node (not taht it matters much
for the intended use)

David

--~------------------------------------------------------------------
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-***@lists.mulberrytech.com>
--~--
Dimitre Novatchev
2007-02-27 23:06:16 UTC
Permalink
Post by David Carlisle
Post by Dimitre Novatchev
I think in this case generate-id() will be applied on the same node
again and again and will return the same string -- this is why I want
always to have a new copy of it -- or am I wrong?
no a literal result element like <x/> is (more or less) the same as using
<xsl:element name="x"/> it's a single node in the stylesheet but it
generates a new node each time it's executed, and generate-id() is being
applied to that result.
Unless the XSLT processor decides to "optimize" this and makes the
node global(static) -- moves it outside the scope of the function....
--
Cheers,
Dimitre Novatchev
---------------------------------------
Truly great madness cannot be achieved without significant intelligence.
---------------------------------------
To invent, you need a good imagination and a pile of junk
-------------------------------------
You've achieved success in your field when you don't know whether what
you're doing is work or play

--~------------------------------------------------------------------
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-***@lists.mulberrytech.com>
--~--
David Carlisle
2007-02-27 23:10:48 UTC
Permalink
Post by Dimitre Novatchev
Unless the XSLT processor decides to "optimize" this and makes the
node global(static) -- moves it outside the scope of the function....
if an implementation does the wrong thing, then you get the wrong result
true, but not much can be done about that, apart from reporting bugs as
they occur.

David

--~------------------------------------------------------------------
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-***@lists.mulberrytech.com>
--~--
Michael Kay
2007-02-27 23:28:18 UTC
Permalink
Post by Dimitre Novatchev
Unless the XSLT processor decides to "optimize" this and
makes the node global(static) -- moves it outside the scope
of the function....
It's not allowed to. In that respect, XSLT and XQuery are not purely
functional: node creation has a limited side-effect. This comes out most
strongly in XQuery, where you will see plenty of tests in the test suite
like

count(for $i in 1 to 10 return <a/>)

Michael Kay
http://www.saxonica.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-***@lists.mulberrytech.com>
--~--
Abel Braaksma
2007-02-27 23:40:43 UTC
Permalink
Post by Michael Kay
count(for $i in 1 to 10 return <a/>)
Michael,

I found that when using generate-id() with LREs, it creates increasing
numbers, preceded by 'd'. When using source nodes, something else
happens. I know from the specs, that an implementation can choose its
own way of creating the ID. But a (longer) while ago, I remember to have
seen an explanation of the algorithm used, but today I can't find it
anymore (searched the Net, saxonica.com, the faq and both of your
reference books).

Just out of interest: do you happen to know where this is explained? Or
is the explanation removed?

-- Abel

--~------------------------------------------------------------------
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-***@lists.mulberrytech.com>
--~--
Michael Kay
2007-02-28 00:11:15 UTC
Permalink
Post by Abel Braaksma
I found that when using generate-id() with LREs, it creates
increasing numbers, preceded by 'd'. When using source nodes,
something else happens. I know from the specs, that an
implementation can choose its own way of creating the ID. But
a (longer) while ago, I remember to have seen an explanation
of the algorithm used, but today I can't find it anymore
(searched the Net, saxonica.com, the faq and both of your
reference books).
You're referring of course to the Saxon algorithm - each processor can do
this its own way.

I don't think the Saxon algorithms are documented anywhere. There's
potentially a different algorithm for each of the supported tree models
(tinytree, linked tree, DOM, JDOM, DOM4J, XOM) and third-party tree models
can do their own thing. For the TinyTree the algorithm is:

buffer.append("d");
buffer.append(Integer.toString(tree.getDocumentNumber()));
buffer.append(NODE_LETTER[getNodeKind()]);
buffer.append(Integer.toString(nodeNr));

Note that the "tree" is really a forest - a sequence of trees, often only
one but not always - and the "document number" is actually a "forest
number". The node letter identifies the node kind, e.g. "e" for element, and
it's really redundant but you need some kind of separator between the
document number and the node number and this is as good as anything.

At one time in the distant past I used an identifier that doubled as a sort
key for sorting nodes into document order. This was just a monotonic
sequence number mapped to ascii using a mapping such as

0-9 a0-a9
10-99 b10-b99
100-999 c100-c999
etc

Michael Kay
http://www.saxonica.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-***@lists.mulberrytech.com>
--~--
Andrew Welch
2007-02-28 09:45:13 UTC
Permalink
Post by Michael Kay
Post by Abel Braaksma
I found that when using generate-id() with LREs, it creates
increasing numbers, preceded by 'd'. When using source nodes,
something else happens. I know from the specs, that an
implementation can choose its own way of creating the ID. But
a (longer) while ago, I remember to have seen an explanation
of the algorithm used, but today I can't find it anymore
(searched the Net, saxonica.com, the faq and both of your
reference books).
You're referring of course to the Saxon algorithm - each processor can do
this its own way.
I don't think the Saxon algorithms are documented anywhere.
I'm sure Saxon used to generate consistent id's across transformation
runs along the lines of "d01e01" where d roughly meant document and e
meant element - I'm sure I used to rely (wrongly) on the consistency
and then had to create my own count after the algorithm changed -
somewhere around early version 7. There were also (iirc) some
conversations about how "d" couldn't be consistent if the document
came from a Stream... Maybe Abel's read those posts somewhere?

--~------------------------------------------------------------------
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-***@lists.mulberrytech.com>
--~--
Abel Braaksma
2007-02-28 15:40:48 UTC
Permalink
Post by Andrew Welch
I'm sure Saxon used to generate consistent id's across transformation
runs along the lines of "d01e01" where d roughly meant document and e
meant element - I'm sure I used to rely (wrongly) on the consistency
and then had to create my own count after the algorithm changed -
somewhere around early version 7. There were also (iirc) some
conversations about how "d" couldn't be consistent if the document
came from a Stream... Maybe Abel's read those posts somewhere?
Perhaps I did, perhaps it was about the IS operator, I can't recall. But
thanks to you and Michael I have a clear picture now ;)

Cheers,
-- Abel

--~------------------------------------------------------------------
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-***@lists.mulberrytech.com>
--~--

Michael Kay
2007-02-27 23:58:45 UTC
Permalink
Post by Michael Kay
It's not allowed to. In that respect, XSLT and XQuery are not purely
functional: node creation has a limited side-effect. This
comes out most strongly in XQuery, where you will see plenty
of tests in the test suite like
count(for $i in 1 to 10 return <a/>)
I meant of course to include an operator that eliminates duplicates, for
example

count(./(for $i in 1 to 10 return <a/>))
Post by Michael Kay
Michael Kay
http://www.saxonica.com/
--~------------------------------------------------------------------
XSL-List info and archive: http://www.mulberrytech.com/xsl/xsl-list
To unsubscribe, go to: http://lists.mulberrytech.com/xsl-list/
--~--
--~------------------------------------------------------------------
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-***@lists.mulberrytech.com>
--~--
Abel Braaksma
2007-02-27 21:58:14 UTC
Permalink
Post by Dimitre Novatchev
I think in this case generate-id() will be applied on the same node
again and again and will return the same string -- this is why I want
always to have a new copy of it -- or am I wrong?
I am honoured with so much attention for such a seemingly simple question ;)

Inside a function, apparently, the node is recreated on each function
call. Whether it is this:

<xsl:function name="my:getNode"><node /></xsl:function>
<xsl:function name="my:getId"><xsl:value-of
select="generate-id(my:getNode())" /></xsl:function>

or whether you use variables to achieve the same result. Apparently, the
node need not be part of the result tree to achieve this effect (maybe
it is, I don't know, but it is never output at least).

The variable-inside-one-function (like David's solution) is the one I
currently employ, but any variant is likely to succeed if I understand
Michael Kay correctly.

-- Abel Braaksma

--~------------------------------------------------------------------
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-***@lists.mulberrytech.com>
--~--
Michael Kay
2007-02-27 22:25:46 UTC
Permalink
Post by Abel Braaksma
<xsl:function name="my:getNode"><node /></xsl:function>
<xsl:function name="my:getId">
<xsl:value-of select="generate-id(my:getNode())" />
</xsl:function>

Yes, this is fine. But please get out of the habit of using xsl:value-of
when you mean xsl:sequence, and please get into the habit of declaring the
types of your functions! This should be

<xsl:function name="my:getId as="xs:string">
<xsl:sequence select="generate-id(my:getNode())" />
</xsl:function>

xsl:value-of is creating a text node, and because of the very identity
issues we're discussing, it's very hard to optimize this away: if the return
type is declared as xs:string the processor has some chance of recognizing
that the text node is going to be atomized as soon as it's created, but
really it's better not to create it in the first place.

The cheapest solution is probably a text or comment node rather than an
element, something like:

<xsl:function name="my:getNode"><xsl:comment/></xsl:function>

<xsl:function name="my:getId">
<xsl:value-of select="generate-id(my:getNode())" />
</xsl:function>

Remember that an LRE like <node/> might be creating a lot of namespaces...

Michael Kay
http://www.saxonica.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-***@lists.mulberrytech.com>
--~--
Abel Braaksma
2007-02-27 23:04:04 UTC
Permalink
Post by Michael Kay
But please get out of the habit of using xsl:value-of
when you mean xsl:sequence, and please get into the habit of declaring the
types of your functions! This should be
For your comfort: that is precisely the way it is in my XSLT, I just
left it out for brevity ;)

And indeed, I still often use xsl:value-of, I partially blame XSLT 1 for
that: I use both on a daily basis and get confused....
Post by Michael Kay
The cheapest solution is probably a text or comment node rather than an
<xsl:function name="my:getNode"><xsl:comment/></xsl:function>
<xsl:function name="my:getId">
<xsl:value-of select="generate-id(my:getNode())" />
</xsl:function>
Remember that an LRE like <node/> might be creating a lot of namespaces...
That is a great tip. Thanks!

-- Abel

--~------------------------------------------------------------------
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-***@lists.mulberrytech.com>
--~--
Loading...