Hi Andrew,
Here Demitre uses the function count(ancestor::*|.) three times
within the same template - can anyone tell me if this gets
re-evaluated each time, therefore using a variable would be better,
or if it gets stored (as some kind of optimisation maybe), so using
a variable is unecessary?
It will most probably get re-evaluated each time, unless the processor
is very very smart. ancestor::* isn't likely to give you a *huge* node
set (unlike descendant::*, for example), so this probably isn't a
problem, but if it is, you could use a variable as follows:
<xsl:key name="kDepth" match="Folder"
use="count(ancestor::*)" />
<xsl:template match="/">
<xsl:for-each select="//Folder">
<xsl:variable name="depth" select="count(ancestor::*)" />
<xsl:if test="generate-id() =
generate-id(key('kDepth', $depth)[1])">
<xsl:value-of select="concat('Level ', $depth, ': ')" />
<xsl:for-each select="key('kDepth', $depth)">
<xsl:value-of select="concat(@NAME, '; ')" />
</xsl:for-each>
</xsl:if>
</xsl:for-each>
</xsl:template>
There are two potential issues with this method that arise because
you're for-eaching over *all* the Folder elements. One is that it
might prove less efficient than only for-eaching over the *unique*
Folder elements -- for-eaching might be less efficient than using a
predicate to do the filtering. The second is that if you wanted to use
position() anywhere within the outer xsl:for-each, you'd get the
"wrong" value, because the position would be based on the location of
the Folder amongst *all* the Folders rather than amongst the unique
ones.
A compromise, if either of those is a problem, would be to use:
<xsl:key name="kDepth" match="Folder"
use="count(ancestor::*)" />
<xsl:template match="/">
<xsl:for-each
select="//Folder[generate-id() =
generate-id(key('kDepth',
count(ancestor::*))[1])">
<xsl:variable name="depth" select="count(ancestor::*)" />
<xsl:value-of select="concat('Level ', $depth, ': ')" />
<xsl:for-each select="key('kDepth', $depth)">
<xsl:value-of select="concat(@NAME, '; ')" />
</xsl:for-each>
</xsl:if>
</xsl:for-each>
</xsl:template>
where the calculation gets carried out twice per Folder element,
rather than three times or once.
I should point out, though, that I gather that some processors (Saxon,
I think, but there might be others) attempt to save memory by only
actually storing the value of a variable if it's used more than twice,
so using a variable might make no difference whatsoever (aside from
arguably making the code easier to read). As with all performance
questions, the best advice is "try it and see".
Cheers,
Jeni
---
Jeni Tennison
http://www.jenitennison.com/
XSL-List info and archive: http://www.mulberrytech.com/xsl/xsl-list