This is the mail archive of the
xsl-list@mulberrytech.com
mailing list .
Re: Counting siblings...
- To: xsl-list at mulberrytech dot com, Giles Smith <Giles dot Smith at oyster dot co dot uk>
- Subject: Re: Counting siblings...
- From: Nick Browne <NickBrowne at slipstone dot co dot uk>
- Date: Fri, 16 Jun 2000 12:47:09 +0100
- Organization: Slipstone Ltd
- References: <1DBF2E3701DFD211A65300902728A91B0190DA59@baby.kbw.co.uk>
- Reply-To: xsl-list at mulberrytech dot com
Here is a solution to your problem of counting siblings up to a certain point. I
have put a slightly enhanced version of your XML document at the end. I hope my
use of the word 'context' in the comments is correct !
The Style sheet :
<?xml version="1.0" ?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" >
<xsl:template match="root">
<xsl:for-each select="item">
Item : <xsl:value-of select="position()"/> has :
<xsl:call-template name="levelchk">
<xsl:with-param name="lvl" select="@level"/>
<xsl:with-param name="cnt" select="number(0)"/>
<xsl:with-param name="pos" select="position()"/>
</xsl:call-template>
</xsl:for-each>
</xsl:template>
<!-- Using the (single) item initially passed from the for-each as
the context, work forward via recursion until an item is found
that has the same or lower level attribute value -->
<xsl:template name="levelchk">
<xsl:param name="lvl"/>
<xsl:param name="cnt"/>
<xsl:param name="pos"/>
<!-- Decide whether we need to keep searching .. -->
<xsl:choose>
<!-- If there is still another following item with a level
attribute value higher than the context value, call
the template again and repeat the check for the next
item -->
<xsl:when test="../item[$pos+1]/@level > $lvl">
<xsl:call-template name="levelchk">
<xsl:with-param name="lvl" select="$lvl"/>
<xsl:with-param name="cnt" select="$cnt+1"/>
<xsl:with-param name="pos" select="$pos+1"/>
</xsl:call-template>
</xsl:when>
<!-- Stop the search. If here then we have found an item
where the level attribute value is less than the level
value from the context item (or $pos points to the
last item) -->
<xsl:otherwise>
<xsl:value-of select="$cnt"/> 'descendants' <BR />
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
Notes :
1. The variable $lvl is not necessary. 'param' references to it can be removed
and the 'when' test can refer to @level (since there is only one item in
the templates context)
2. Tested on Oracle v2.0.2.8
The XML document :
(the text of item is the items position in the document followed by the result
you were after, i.e. for each item, how many siblings does it have which have a
level attribute value that is greater than that of the item itself, stop
counting once the first sibling is found with a level value less than or equal
to that of the item itself.) :
<?xml version="1.0" encoding="ISO-8859-1" ?>
<root>
<item level="0">1-4</item>
<item level="1">2-1</item>
<item level="2">3-0</item>
<item level="1">4-1</item>
<item level="2">5-0</item>
<item level="0">6-3</item>
<item level="1">7-2</item>
<item level="2">8-1</item>
<item level="3">9-0</item>
</root>
I had tried to use the 'Muenchian' technique but your data does not have a
natural key. May be someone else would know if this is a better approach ?
Hope this helps.
Nick Browne
Slipstone Ltd
Giles Smith wrote:
> Hi,
>
> I have an interesting problem, and wondered if your clever people might be
> able to offer some possible solutions:
etc.
XSL-List info and archive: http://www.mulberrytech.com/xsl/xsl-list