Re: [xsl] Creating a hierarchical table of contents using xsl:number

Subject: Re: [xsl] Creating a hierarchical table of contents using xsl:number
From: Charles Muller <cmuller-lst@xxxxxxxxxxxxxxx>
Date: Wed, 17 Feb 2010 10:25:23 +0900
Martin Jackson wrote:

I'm trying to create a table of content that looks like this:

1. Fruit
1.1. Citrus
1.1.1. Orange
1.1.2. Lemon
1.1.3. Lime
1.2. Apple
2. Vegetables
2.1. Tomato
2.2. Carrot

If it is of any help, the below sheet takes the information from the document, and makes at linked TOC at the top, in a table, (but only makes the TOC for <div1> -- this could be modified)


<div1><head>Heading One<head>
  <div2><head>Heading Two</head>
     <div3><head>Heading Two</head>

...etc., up to <div7>

If the <divs> have numbers attached (such as <div1 n="I">, <div2 n="1">, etc., it uses those numbers. If there are no div numbers assigned, it automatically generates them, like 1.2.4, etc.

The part of this code that builds the linked table was written by Michael Beddow (who, as always, includes helpful commentary). The rest is mine (developed from Googling xsl:number).

Chuck

---------------------

<?xml version='1.0'?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
xpath-default-namespace="http://www.tei-c.org/ns/1.0"; version="2.0">


<!-- MB 2009-06-16 Use generated target and anchor values for hyperlinks to div1 <head> elements -->
<!-- CM 2003-03-22 Start Div handler, part 1-->
<!-- Get the div number into a variable -->
<xsl:template match="head">



<xsl:if test="parent::div1">
<!-- This is the <head> of a <div1> We need to make it a named target for hyperlinks -->


<hr/>

<p style="margin-left:0;font-size:115%; margin-bottom:0.5em; font-weight:bold; font-family:'Times Ext Roman', 'Times New Roman'">


<!-- This is the old static div1 n-value variable. No longer needed, but harmless... -->
<xsl:variable name="divnum" select="ancestor::div1[1]/@n"/>



<!-- MB 090616 Use the current div1 count to construct the hyperlink target and anchor values -->
<xsl:variable name="divcount" select="count(ancestor::div1[1]/preceding-sibling::div1)+1"/>



<!-- Now to write the anchor and hyperlink -->


<a>
<xsl:attribute name="name">div-<xsl:value-of select="$divcount"/></xsl:attribute>



<!-- MB 200906018 If the containing div has an n attribute value, use it
** Otherwise use a dynamically calculated value
** NB this means that hard-coded n values will override dynamic ones if the former are present
** This is presumably desirable (e.g. where numbering in the original is erroneous, but needs
** to be preserved to ensure compatible references with a print edition.)
-->


<xsl:choose>

        <xsl:when test="../@n">
            <xsl:value-of select="../@n"/><xsl:text>. </xsl:text>
        </xsl:when>

        <xsl:otherwise>
          <xsl:value-of select="$divcount"/><xsl:text>. </xsl:text>
        </xsl:otherwise>

</xsl:choose>
          <xsl:apply-templates/>
        </a>
</p>
</xsl:if>


<xsl:if test="parent::div2"> <p style=" margin-left:2%; font-size:110%; margin-bottom:0.5em; font-style: italic"> <xsl:choose> <xsl:when test="../@n"> <xsl:value-of select="../@n"/><xsl:text>. </xsl:text> </xsl:when> <xsl:otherwise> <xsl:number level="multiple" count="div1 | div2 | div3 | div4 | div5 | div6 | div7" format="1.1 "/><xsl:text>. </xsl:text> </xsl:otherwise> </xsl:choose> <xsl:apply-templates/> </p> </xsl:if>

<xsl:if test="parent::div3">
<p style="text-align:left; margin-left:4%; font-size:105%; font-weight:bold">
<xsl:variable name="divnum3" select="ancestor::div3[1]/@n"/>
<xsl:choose>
<xsl:when test="../@n">
<xsl:value-of select="../@n"/><xsl:text>. </xsl:text>
</xsl:when>
<xsl:otherwise>
<xsl:number level="multiple"
count="div1 | div2 | div3 | div4 | div5 | div6 | div7"
format="1.1 "/><xsl:text>. </xsl:text>
</xsl:otherwise>
</xsl:choose>
<xsl:apply-templates/>
</p>
</xsl:if>


<xsl:if test="parent::div4">
<p style="text-align:left; margin-left:6%; font-size: 100%; font-weight:bold"> <xsl:variable name="divnum4" select="ancestor::div4[1]/@n"/>
<xsl:if test="../@n">
<xsl:value-of select="../@n"/><xsl:text>. </xsl:text>
</xsl:if>
<xsl:apply-templates/>
</p>
</xsl:if>
<xsl:if test="parent::div5">
<p style="text-align:left; margin-left:8%; font-size: 100%; font-style:italic">
<xsl:variable name="divnum5" select="ancestor::div5[1]/@n"/>
<xsl:if test="../@n">
<xsl:value-of select="../@n"/><xsl:text>. </xsl:text>
</xsl:if>
<xsl:apply-templates/>
</p>
</xsl:if>


<xsl:if test="parent::div6">
<p style="text-align:left; margin-left:10%; font-size:100%; font-decoration:underline">
<xsl:variable name="divnum6" select="ancestor::div6[1]/@n"/>
<xsl:if test="../@n">
<xsl:value-of select="../@n"/><xsl:text>. </xsl:text>
</xsl:if>
<xsl:apply-templates/>
</p>
</xsl:if>


    <xsl:if test="parent::div7">
      <p style="text-align:left; font-size:100%t">
        <xsl:variable name="divnum7" select="ancestor::div7[1]/@n"/>
        <xsl:if test="../@n">
          <xsl:value-of select="../@n"/><xsl:text>. </xsl:text>
        </xsl:if>
        <xsl:apply-templates/>
      </p>
    </xsl:if>

</xsl:template>

<xsl:template match="head" mode="showheads">

<!-- This is the old static div1 n-value variable. No longer needed, but harmless... -->
<xsl:variable name="divnum" select="ancestor::div1[1]/@n"/>


<!-- MB 090616 Use the current div1 count to construct the hyperlink target and anchor values -->
<xsl:variable name="divcount" select="count(ancestor::div1[1]/preceding-sibling::div1)+1"/>



<tr>
<!-- MB 2003-03-22
* Output the reference no in a right-aligned table cell. This ensures correct
* vertical alignment of the numbers, no matter how many places they have
* The valign value of "top" ensures that that number will remain in the correct
* horizontal alignment against the first line ot the title even if the title itself wraps
* on to a second or even third line
-->
<td align="right" valign="top">
<!-- Leave the cell empty if we don't have a number (preventing an orphaned period)
-->


<!-- MB 200906018 If the containing div has an n attribute value, use it
** Otherwise use a dynamically calculated value
** NB this means that hard-coded n values will override dynamic ones if the former are present
** This is presumably desirable (e.g. where numbering in the original is erroneous, but needs
** to be preserved to ensure compatible references with a print edition.)
-->




<xsl:choose>

        <xsl:when test="../@n">
          <xsl:value-of select="../@n"/><xsl:text>. </xsl:text>
        </xsl:when>
        <xsl:otherwise>
          <xsl:value-of select="$divcount"/><xsl:text>. </xsl:text>
        </xsl:otherwise>

</xsl:choose>

<!--
<xsl:if test="$divcount">
<xsl:value-of select="$divcount"/><xsl:text>. </xsl:text>
</xsl:if>
-->
</td>
<!-- write the <a>element target for the link reference. Use AVT notation to
* insert the attribute value. Putting the title into a table cell ensures
* all titles left-align correctly, no matter what the size of the numeral
* (if any) that precedes them
-->
<td><a href="#div-{$divcount}"><xsl:apply-templates/></a></td>
</tr>


<!-- Finish Div handler, part 2 -->

</xsl:template>

</xsl:stylesheet>

--
-------------------

A. Charles Muller

University of Tokyo
Graduate School of Humanities and Sociology, Faculty of Letters
Center for Evolving Humanities
Akamon kenkyE+ tE
#722
7-3-1 HongE
, BunkyE
-ku
Tokyo 113-0033, Japan

Web Site: Resources for East Asian Language and Thought
http://www.acmuller.net

<acmuller[at]jj.em-net.ne.jp>

Mobile Phone: 090-9310-1787

Current Thread