This is the mail archive of the
xsl-list@mulberrytech.com
mailing list .
Re: Re: getting all nodes from a certain level in the xml hierarchy
- From: Jeni Tennison <jeni at jenitennison dot com>
- To: "Andrew Welch" <awelch at piper-group dot com>
- Cc: xsl-list at lists dot mulberrytech dot com
- Date: Fri, 27 Sep 2002 12:46:52 +0100
- Subject: Re: [xsl] Re: getting all nodes from a certain level in the xml hierarchy
- Organization: Jeni Tennison Consulting Ltd
- References: <63C4AD0365821F4291ACF76C0672FA3506EF5C@piper6.piper-group.int>
- Reply-to: xsl-list at lists dot mulberrytech dot com
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