[xsl] Grouping problem. 2.0

Subject: [xsl] Grouping problem. 2.0
From: Dave Pawson <davep@xxxxxxxxxxxxx>
Date: Fri, 04 Jul 2008 15:46:34 +0100
source and stylesheet below

Problem.

I want to number the 'blocks' as in 'legal' format
1.1
1.1.1 etc.

Something is wrong with the named template 'number'
I'm looking for the set of preceding-siblings
between '.' and the preceding-sibling::title with
one higher level (@role).

The theory is that recursing on that will
enumerate the the 'block' appropriately.

Any suggestions please.

TIA DaveP


source <book > <title role="1">L1</title>

   <title role="2">L1.1</title>
   <para>This document defines an XML schema for  ....</para>
   <title role="2">L1.2</title>
   <para>The normative XML Schema for the OpenDoc ....</para>
   <title role="1">L2</title>
   <para>This chapter introduces the structure of ....</para>
   <para>In the OpenDocument format, each structu ....</para>

   <title role="2">L2.1</title>
   <para>A document root element is the primary e ....</para>


<title role="3">L2.1.1</title> <para>The content models of the five root elem ....</para>

   <title role="4">L4 test</title>
   <para>The content models of the five root elem ....</para>
   <para>The &lt;office:document&gt; root contains a co ....</para>

  <title role="4">L4 test 2.1.1.2</title>
   <para>The content models of the five root elem ....</para>
   <para>The &lt;office:document&gt; root contains a co ....</para>

  <title role="2">L2.1</title>
   <para>A document root element is the primary e ....</para>

</book>


xslt of interest.


  <xsl:template match="title" >
    <xsl:variable name='this' select='.'/>
    <block  role="{@role}">
         <xsl:attribute name='sect'>
           <xsl:call-template name="number">
           <xsl:with-param name='lvl' select='@role'/>
         </xsl:call-template>
       </xsl:attribute>
      <title><xsl:value-of select="."/></title>
        <xsl:apply-templates
          select="following-sibling::para[preceding::title[1]=$this]"
          mode='group'/>
      </block>
  </xsl:template>


<xsl:template match="para" mode="group"> <xsl:copy> <xsl:copy-of select="@*"/> <xsl:copy-of select="*|text()"/> </xsl:copy> </xsl:template>


<!-- Work out the numbering for $lvl n --> <xsl:template name="number"> <xsl:param name='lvl' as="xs:integer"/> <!-- h1..h6 --> <xsl:param name='n' select='0.0' as='xs:decimal'/> <!-- hdg # -->

    <xsl:choose>
<!-- Higher levels -->
    <xsl:when test="$lvl > 1">
      <xsl:variable name='higher'
     select="preceding-sibling::title[@role > $lvl][1]" />
        <xsl:if test="not($higher/@role)">
          <xsl:message terminate='yes'>
            Higher is empty
            Level is <xsl:value-of select="$lvl"/>
            <xsl:text>, content [ </xsl:text>
            <xsl:value-of select="."/>
          </xsl:message>
        </xsl:if>
      <xsl:variable name='prev'
        select="count(preceding-sibling::title[@role = $lvl]
                [ $higher &lt;&lt; .])"/>
      <xsl:variable name='res' select="dp:dec($lvl, $prev) + $n"/>

    <!-- Process higher levels -->
      <xsl:for-each select="$higher">
        <xsl:call-template name="number">
          <xsl:with-param name='lvl' select='$lvl - 1'/>
          <xsl:with-param name="n" select='$res'/>
        </xsl:call-template>
      </xsl:for-each>
    </xsl:when>
<!-- Level 1 -->
    <xsl:when test="$lvl = 1">
        <xsl:variable name='prev'
        select="count(preceding-sibling::title[@role='1'])"/>
       <xsl:variable name='res' select="dp:dec($lvl, $prev) + $n"/>
        <xsl:call-template name="number">
          <xsl:with-param name='lvl' select='$lvl - 1'/>
          <xsl:with-param name="n" select='$res'/>
        </xsl:call-template>
    </xsl:when>
<!-- Terminating Condition -->
    <xsl:otherwise>
      <xsl:value-of select="$n"/>
    </xsl:otherwise>
  </xsl:choose>

</xsl:template>



<!-- calculate decimal value from level -->
<!--
Inputs: level (from heading level, 1..4)
count : # of preceding items at this level
@return:  decimal, representing a value to be used for this
Note. Since levels are 0 based, 1 is added each time.
heading. Mappings:
     lvl   count   @return
     1     0       1.0
     2     0       0.1
     3     1       0.02
     4     2       0.003
     5     ?       error, fails
 -->
<xsl:function name="dp:dec" as='xs:decimal'>
  <xsl:param name='lvl' />
  <xsl:param name='count' as='xs:integer'/>
  <xsl:if test='$lvl &lt; 1 or $lvl > 4'>
    <xsl:message terminate='yes'>
      Invalid input to dp:dec, <xsl:value-of select='$lvl'/>
    </xsl:message>
  </xsl:if>
  <xsl:variable name='dcount' as ='xs:decimal'
    select='($count + 1) cast as xs:decimal'/>
    <xsl:variable name='n'>
    <xsl:choose>
      <xsl:when test="$lvl = 4">
        <xsl:value-of select="$dcount * 0.001"/>
      </xsl:when>
      <xsl:when test="$lvl = 3">
        <xsl:value-of select="$dcount * 0.01"/>
      </xsl:when>
      <xsl:when test="$lvl = 2">
        <xsl:value-of select="$dcount * 0.1"/>
      </xsl:when>
      <xsl:otherwise>
        <xsl:value-of select="$dcount * 1.0"/>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:variable>
  <xsl:value-of select="$n"/>
</xsl:function>



regards

--
Dave Pawson
XSLT XSL-FO FAQ.
http://www.dpawson.co.uk

Current Thread