Piet Blok <p@b> wrote in news:40**********************@news.wanadoo.nl:
Victor Engmark <vi************@cern.ch> wrote in news:c6b8bv$suu$1
@sunnews.cern.ch:
When looking for a method to fetch unique elements and counting the
number of occurences of each of them, I found quite a lot of gross
examples of complex XSL. But after realizing the subtle difference
between "." and "current()", I found a neat way of doing the same
without keys or generate-id():
<xsl:template match="/">
<!-- Selects all "new" elements -->
<xsl:for-each select="//Name[not(.=preceding::Name)]">
<!-- Display the element -->
<xsl:value-of select="."/>
<!-- Count the number of occurences of the element -->
<xsl:value-of select="count(//Name[.=current()])"/>
</xsl:for-each>
</xsl:template>
The clue to why the last "value-of" works is that "." refers
dynamically to each of the "Name" elements in the file, while
"current()" refers to the "Name" element in the sorrounding
"for-each" element.
If YOU have found a "neat" way of doing something with XSL, it would
be great if you could post it here as well, preferably as a separate
thread with something like "Tip:" in the beginning of the subject.
Thanks Victor, a very neat solution. Easier to apply than the keys and
generate-id() approach.
Victor, I tried to enhance one of my XSL stylesheets that I made awhile
ago to create a birthday calendar. To my own surprise I found that I
already abandoned the use of keys and generate-id() (however not so nice
and clean as you did). My problem was that I had to check on only a part
of some value (the month number that was embedded between year and day
in the same tag). Therefore I had to do some string manipulation.
I changed that implementation today and now I use the preceding:: axes.
So it looks already better now.
However, I just cannot get rid of an ugly xsl:if. In my solution I
select all elements and then I decide if the current element is a "new"
element. See below:
<xsl:template match="/">
<!-- select all Name elements -->
<xsl:for-each select="//Name">
<!-- test if this Name element is new, based on the first character -->
<xsl:if test="not(substring(current(),1,1) = substring
(preceding::Name[substring(.,1,1)=substring(current(),1,1)],1,1))">
<!-- Display the first character -->
<xsl:value-of select="substring(.,1,1)"/>
<!-- Count occurences of element with the same starting character -->
<xsl:value-of select="count(//Name[substring(.,1,1)
=substring(current(),1,1)])"/>
</xsl:if>
</xsl:for-each>
</xsl:template>
Can you think of any way to move the if structure into the select
clause?
In a way the problem seems to be that there are three contexts to deal
with: the context node (in this case the root node), the node that is
currently under investigation for selection and the node that is
compared to (between the square brackets).
Any thoughts would be welcome.
Piet