[xsl] XHTML table of contents with XSLT

Subject: [xsl] XHTML table of contents with XSLT
From: "Daniel K. Schneider" <Daniel.Schneider@xxxxxxxxxxxxxx>
Date: Fri, 23 Feb 2007 17:44:34 +0100
Hi, I am trying to do a table of contents for XHTML input/output.

XHTML: Is valid transitional (has a name space declaration) and NO identity
attributes or div's etc. would make the task easier. I really would like to work
it with just ANY valid XHTML w/o hand-editing.

Desired RESULT: TOC with 2 or more levels, must work CLIENT side in a XHTML
capable browser (e.g. Firefox).

But I am a bit stuck. Tried to find something on the Internet but couldn't. Sorry if this is FAQ ... but I did make an effort and didn't find anything.

Here is what I have so far. Problem are:
* This solution ONLY works for h1,h2,etc. that have different content. E.g. you
couldn't have two h2 with "example" content.
* I also tried to hack something with position, but apparently position() does
not return position in the global tree in the following rule.

<xsl:template match="*[local-name()='h1']" mode="toc">
  <xsl:text></xsl:text><a href="#{position()}"><xsl:value-of select="."/></a><br/>
</xsl:template>

Question: Do I have to copy the whole tree and insert id attibutes ?
(I can learn this guess, but not sure that this is the easiest solution)

My clumsy attempt (should work with ANY xhtml file)
----- XSL -----

<?xml version="1.0"?>
<xsl:stylesheet version="1.0"
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
                xmlns="http://www.w3.org/1999/xhtml";>

  <xsl:output
    method="xml"
    doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd";
    doctype-public="-//W3C//DTD XHTML 1.0 Transitional//EN"
    indent="yes"
    encoding="iso-8859-1"
    />

  <xsl:template match="/*[local-name()='html']">
  <html xmlns="http://www.w3.org/1999/xhtml";>
    <head>
      <title>Nice title</title>
    </head>
    <body bgcolor="#FFFFFF">
      <xsl:apply-templates select="*[local-name()='body']"/>
    </body>
  </html>
</xsl:template>

<xsl:template match="*[local-name()='body']">
  <h1>Contenu</h1>
  <xsl:apply-templates select="*[local-name()='h1']|*[local-name()='h2']"
mode="toc"/>
  <!-- <xsl:apply-templates
select="*[local-name()='h1']|*[local-name()='h2']|*[local-name()='h3']"
mode="toc"/> -->
  <xsl:apply-templates />
</xsl:template>

<xsl:template match="*[local-name()='h1']" mode="toc">
  <xsl:text></xsl:text><a href="#h1_{.}"><xsl:value-of select="."/></a><br/>
</xsl:template>

<xsl:template match="*[local-name()='h2']" mode="toc">
  <xsl:text>-- </xsl:text><a href="#h2_{.}"><xsl:value-of select="."/></a><br/>
</xsl:template>

<!--
<xsl:template match="*[local-name()='h3']" mode="toc">
  <a href="#h3_{.}"><xsl:value-of select="."/></a> -
</xsl:template>
-->

<xsl:template match="*[local-name()='h1']">
  <h1><a name="h1_{.}"><xsl:value-of select="."/></a></h1>
</xsl:template>

<xsl:template match="*[local-name()='h2']">
  <h2><a name="h2_{.}"><xsl:value-of select="."/></a></h2>
</xsl:template>

<!--
<xsl:template match="*[local-name()='h3']">
  <h3><a name="h3_{.}"><xsl:value-of select="."/></a></h3>
</xsl:template>
-->

<!-- A default rule will just copy all the rest -->

<xsl:template match="*">
    <xsl:element name="{name(.)}">
      <xsl:for-each select="@*">
        <xsl:attribute name="{name(.)}">
          <xsl:value-of select="."/>
        </xsl:attribute>
      </xsl:for-each>
      <xsl:apply-templates/>
    </xsl:element>
  </xsl:template>

</xsl:stylesheet>

-----

disclaimer: sorry I am not a programmer nor an XML expert


-- Dr Daniel K.Schneider, TECFA (Educational Technologies and Learning)

TECFA    (TEchnologies de Formation et Apprentissage)
FPSE     (Faculti de Psychologie et des Sciences de l'Education)
Universiti de Genhve
54 Route des Acacias, CH-1227 Carouge

email: Daniel.Schneider@xxxxxxxxxxxxxx
www:   http://tecfa.unige.ch/tecfa-people/schneider.html

Tel: 41 22 379 9377 - Fax: 41 22 379 9379

Current Thread