Re: Counting siblings...

Subject: Re: Counting siblings...
From: Nick Browne <NickBrowne@xxxxxxxxxxxxxxx>
Date: Fri, 16 Jun 2000 12:47:09 +0100
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 &gt; $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


Current Thread