<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">

<!-- www.matthewwest.co.uk                                              -->
<!-- Layout $LastChangedDate:: 2007-05-12 08:36:32 -0700 (Sat, 12 May#$ -->
<!-- Layout $Revision:: 134                                           $ -->
<!-- Copyright (C) 2005-2007 Matthew West                               -->
  
  <head profile="http://gmpg.org/xfn/11">
    <meta name="title" content="Blog - XSL Contents" />
    <meta name="author" content="Matthew West" />
    <title>
      Blog - XSL Contents
    </title>
        
    <link href="/stylesheets/site.css?1184434403" media="all" rel="Stylesheet" type="text/css" />
    
    <link href="/stylesheets/print.css?1184459558" media="print" rel="Stylesheet" type="text/css" />
    <link href="/stylesheets/syntax.css?1184434403" media="all" rel="Stylesheet" type="text/css" />
    <link href="/favicon.ico?1167527172" rel="shortcut icon" />
    <style type="text/css">
      
    </style>
          <link href="/blog/2002/8/20/2-xml-to-xhtml-transformation" rel="prev" title="Blog - XML to XHTML transformation" />
      <link href="/blog/2002/8/1/4-photo-album" rel="first" title="Blog - Photo Album" />
              <link href="/blog/2007/4/14/7-patching-the-pearl-expert" rel="next" title="Blog - Patching the Pearl Expert" />
      <link href="/blog/2007/9/16/12-find-fixtures-without-thinking" rel="last" title="Blog - Find Fixtures Without Thinking" />
        <link href="http://www.matthewwest.co.uk/" rel="home" title="Index" />
    <link href="#&lt;#&lt;Class:0xb787fe50&gt;:0xb72aaec4&gt;" rel="up" title="Blog" />
    <link href="http://www.matthewwest.co.uk/blog/feeds" rel="alternate" title="ATOM" type="application/atom+xml" />
    <link href="http://www.matthewwest.co.uk/blog/feeds/rss2" rel="alternate" title="RSS" type="application/rss+xml" />
  </head>

  <body>
    <div id="bannerhead" >
      <span class="right">www.matthewwest.co.uk</span>
    </div>
     
    <div id="crumbs">
              <a href="/blog">Blog</a>
                  &#160;&gt;&#160;
                      <a href="/blog/2005/2/21/9-xsl-contents">XSL Contents</a>
                        </div>
    <h1>
      Blog - XSL Contents
    </h1>
        
      <div class="floatr">
    <a href="/blog/2007/4/14/7-patching-the-pearl-expert">Patching the Pearl Expert&raquo;</a>
  </div>
  <div>
    <a href="/blog/2002/8/20/2-xml-to-xhtml-transformation">&laquo;XML to XHTML transformation</a>
  </div>
<div style="width:100%;clear:both;">
</div>

<div class="sidebarr tag-cloud">
  Tags:<br />
  <a href="http://www.matthewwest.co.uk/tags/Lucky+Soul" style="font-size: 58%;">Lucky Soul</a> <a href="http://www.matthewwest.co.uk/tags/avolites" style="font-size: 48%;">avolites</a> <a href="http://www.matthewwest.co.uk/tags/chamsys" style="font-size: 58%;">chamsys</a> <a href="http://www.matthewwest.co.uk/tags/computing" style="font-size: 77%;">computing</a> <a href="http://www.matthewwest.co.uk/tags/echelon" style="font-size: 82%;">echelon</a> <a href="http://www.matthewwest.co.uk/tags/hog+1000" style="font-size: 48%;">hog 1000</a> <a href="http://www.matthewwest.co.uk/tags/hog+2" style="font-size: 48%;">hog 2</a> <a href="http://www.matthewwest.co.uk/tags/hog+3" style="font-size: 110%;">hog 3</a> <a href="http://www.matthewwest.co.uk/tags/hog+iPc" style="font-size: 110%;">hog iPc</a> <a href="http://www.matthewwest.co.uk/tags/java" style="font-size: 58%;">java</a> <a href="http://www.matthewwest.co.uk/tags/lighting" style="font-size: 150%;">lighting</a> <a href="http://www.matthewwest.co.uk/tags/magicq" style="font-size: 58%;">magicq</a> <a href="http://www.matthewwest.co.uk/tags/music" style="font-size: 48%;">music</a> <a href="http://www.matthewwest.co.uk/tags/pearl+2004" style="font-size: 48%;">pearl 2004</a> <a href="http://www.matthewwest.co.uk/tags/pearl+expert" style="font-size: 48%;">pearl expert</a> <a href="http://www.matthewwest.co.uk/tags/rails" style="font-size: 48%;">rails</a> <a href="http://www.matthewwest.co.uk/tags/ruby" style="font-size: 48%;">ruby</a> <a href="http://www.matthewwest.co.uk/tags/sailing" style="font-size: 133%;">sailing</a> <a href="http://www.matthewwest.co.uk/tags/website" style="font-size: 77%;">website</a> <a href="http://www.matthewwest.co.uk/tags/xhtml" style="font-size: 72%;">xhtml</a> <a href="http://www.matthewwest.co.uk/tags/xml" style="font-size: 58%;">xml</a> <a href="http://www.matthewwest.co.uk/tags/xsl" style="font-size: 65%;">xsl</a> 
</div>

<dl class="sidebarr frame">
  <dt class="header">Recent Updates</dt>
      <dd><a href="http://www.matthewwest.co.uk/blog/2007/9/16/12-find-fixtures-without-thinking" rel="bookmark">Find Fixtures Without Thinking</a></dd>
      <dd><a href="http://www.matthewwest.co.uk/blog/2007/6/3/11-bush-hall-reviews" rel="bookmark">Bush Hall Reviews</a></dd>
      <dd><a href="http://www.matthewwest.co.uk/blog/2007/5/25/10-lucky-soul-at-bush-hall" rel="bookmark">Lucky Soul at Bush Hall</a></dd>
      <dd><a href="http://www.matthewwest.co.uk/blog/2005/2/21/9-xsl-contents" rel="bookmark">XSL Contents</a></dd>
      <dd><a href="http://www.matthewwest.co.uk/blog/2007/4/15/8-new-website" rel="bookmark">New Website</a></dd>
  </dl>

<div class="post hentry">
  <h2 class="entry-title"><a href="http://www.matthewwest.co.uk/blog/2005/2/21/9-xsl-contents" rel="bookmark">XSL Contents</a></h2>
  <h4 class="tags floatr">
    Tags: <a href="http://www.matthewwest.co.uk/tags/xsl" rel="tag">xsl</a>, <a href="http://www.matthewwest.co.uk/tags/xhtml" rel="tag">xhtml</a>, <a href="http://www.matthewwest.co.uk/tags/website" rel="tag">website</a>, <a href="http://www.matthewwest.co.uk/tags/computing" rel="tag">computing</a>
  </h4>
  <h4 class="datetime">
          Posted
      <abbr class="published" title="2005-02-21T19:06:00Z">
        at February 21, 2005 19:06
      </abbr>
      | Updated
      <abbr class="modified" title="2007-04-16T02:35:24Z">
        at April 16, 2007 02:35
      </abbr>
      </h4>
  <div class="entry-content">
    
    <p>While I was building this website, I thought it would be nice to put a contents page on pages that have multiple sections, such as this one.  This would allow people to jump directly to the section that they were interested in, as well as providing a summary of the page.  Updating the contents page manually soon became a chore, and I would often forget, or make spelling mistakes that stopped it from working.  What was needed was a way of creating contents pages automatically.  As I was already using <span class="caps">XSLT</span> to create the pages to a standard template it seemed the best way to create the contents list would be to use <span class="caps">XSLT</span>.</p>


	<h3>The Problem</h3>


	<p>What I wanted to do was to take a document that was structured like this&#8230;</p>


<pre class="xml">
<span class="punct">&lt;</span><span class="tag">h3</span><span class="punct">&gt;</span>Heading 1<span class="punct">&lt;/</span><span class="tag">h3</span><span class="punct">&gt;</span>
<span class="punct">&lt;</span><span class="tag">p</span><span class="punct">&gt;</span>Text<span class="punct">&lt;/</span><span class="tag">p</span><span class="punct">&gt;</span>
<span class="punct">&lt;</span><span class="tag">p</span><span class="punct">&gt;</span>More text<span class="punct">&lt;/</span><span class="tag">p</span><span class="punct">&gt;</span>
<span class="punct">&lt;</span><span class="tag">h3</span><span class="punct">&gt;</span>Heading 2<span class="punct">&lt;/</span><span class="tag">h3</span><span class="punct">&gt;</span>
<span class="punct">&lt;</span><span class="tag">p</span><span class="punct">&gt;</span>Text<span class="punct">&lt;/</span><span class="tag">p</span><span class="punct">&gt;</span>
<span class="punct">&lt;</span><span class="tag">p</span><span class="punct">&gt;</span>More text<span class="punct">&lt;/</span><span class="tag">p</span><span class="punct">&gt;</span></pre>

	<p>...and transform it into something like this&#8230;</p>


<pre class="xml">
 <span class="punct">&lt;</span><span class="tag">ul</span><span class="punct">&gt;</span>
  <span class="punct">&lt;</span><span class="tag">li</span><span class="punct">&gt;</span>
   <span class="punct">&lt;</span><span class="tag">a</span> <span class="attribute">href</span><span class="punct">=&quot;</span><span class="string">#Heading_1</span><span class="punct">&quot;&gt;</span>Heading 1<span class="punct">&lt;/</span><span class="tag">a</span><span class="punct">&gt;</span>
  <span class="punct">&lt;/</span><span class="tag">li</span><span class="punct">&gt;</span>
  <span class="punct">&lt;</span><span class="tag">li</span><span class="punct">&gt;</span>
    <span class="punct">&lt;</span><span class="tag">a</span> <span class="attribute">href</span><span class="punct">=&quot;</span><span class="string">#Heading_2</span><span class="punct">&quot;&gt;</span>Heading 2<span class="punct">&lt;/</span><span class="tag">a</span><span class="punct">&gt;</span>
  <span class="punct">&lt;/</span><span class="tag">li</span><span class="punct">&gt;</span>
 <span class="punct">&lt;/</span><span class="tag">ul</span><span class="punct">&gt;</span>
 <span class="punct">&lt;</span><span class="tag">h3</span> <span class="attribute">id</span><span class="punct">=&quot;</span><span class="string">Heading_1</span><span class="punct">&quot;&gt;</span>Heading 1<span class="punct">&lt;/</span><span class="tag">h3</span><span class="punct">&gt;</span>
 <span class="punct">&lt;</span><span class="tag">p</span><span class="punct">&gt;</span>Text<span class="punct">&lt;/</span><span class="tag">p</span><span class="punct">&gt;</span>
 <span class="punct">&lt;</span><span class="tag">p</span><span class="punct">&gt;</span>More text<span class="punct">&lt;/</span><span class="tag">p</span><span class="punct">&gt;</span>
 <span class="punct">&lt;</span><span class="tag">h3</span> <span class="attribute">id</span><span class="punct">=&quot;</span><span class="string">Heading_2</span><span class="punct">&quot;&gt;</span>Heading 2<span class="punct">&lt;/</span><span class="tag">h3</span><span class="punct">&gt;</span>
 <span class="punct">&lt;</span><span class="tag">p</span><span class="punct">&gt;</span>Text<span class="punct">&lt;/</span><span class="tag">p</span><span class="punct">&gt;</span>
 <span class="punct">&lt;</span><span class="tag">p</span><span class="punct">&gt;</span>More text<span class="punct">&lt;/</span><span class="tag">p</span><span class="punct">&gt;</span></pre>

	<p>As you can see the contents list is contained in an unordered list, and each list item contains a link to the heading, using id tags.  The headings have had their id tags automatically inserted.  The id tag names are taken from the headings, so that it is easy to link to them from other pages.  However it should also be possible to specify an id tag.</p>


	<h3>First Attempt</h3>


	<p>For the initial attempt I&#8217;m going to assume that the headers already have id tags, and look like this&#8230;</p>


<pre class="xml">
 <span class="punct">&lt;</span><span class="tag">h3</span> <span class="attribute">id</span><span class="punct">=&quot;</span><span class="string">Heading_1</span><span class="punct">&quot;&gt;</span>Heading 1<span class="punct">&lt;/</span><span class="tag">h3</span><span class="punct">&gt;</span>
 <span class="punct">&lt;</span><span class="tag">p</span><span class="punct">&gt;</span>Text<span class="punct">&lt;/</span><span class="tag">p</span><span class="punct">&gt;</span>
 <span class="punct">&lt;</span><span class="tag">p</span><span class="punct">&gt;</span>More text<span class="punct">&lt;/</span><span class="tag">p</span><span class="punct">&gt;</span>
 <span class="punct">&lt;</span><span class="tag">h3</span> <span class="attribute">id</span><span class="punct">=&quot;</span><span class="string">Heading_2</span><span class="punct">&quot;&gt;</span>Heading 2<span class="punct">&lt;/</span><span class="tag">h3</span><span class="punct">&gt;</span>
 <span class="punct">&lt;</span><span class="tag">p</span><span class="punct">&gt;</span>Text<span class="punct">&lt;/</span><span class="tag">p</span><span class="punct">&gt;</span>
 <span class="punct">&lt;</span><span class="tag">p</span><span class="punct">&gt;</span>More text<span class="punct">&lt;/</span><span class="tag">p</span><span class="punct">&gt;</span></pre>

	<p>I&#8217;m also going to assume that the <span class="caps">XSL</span> template copies the body of the document across &#8216;as is&#8217;...</p>


<pre class="xml">
 <span class="punct">&lt;</span><span class="namespace">xsl</span><span class="punct">:</span><span class="tag">template</span> <span class="attribute">match</span><span class="punct">=&quot;</span><span class="string">html</span><span class="punct">&quot;&gt;</span>
   <span class="punct">&lt;</span><span class="namespace">xsl</span><span class="punct">:</span><span class="tag">copy</span><span class="punct">&gt;</span>
     <span class="punct">&lt;</span><span class="namespace">xsl</span><span class="punct">:</span><span class="tag">apply-templates</span> <span class="attribute">select</span><span class="punct">=&quot;</span><span class="string">*</span><span class="punct">&quot;</span> <span class="attribute">mode</span><span class="punct">=&quot;</span><span class="string">BodyCopy</span><span class="punct">&quot;</span> <span class="punct">/&gt;</span>
   <span class="punct">&lt;/</span><span class="namespace">xsl</span><span class="punct">:</span><span class="tag">copy</span><span class="punct">&gt;</span>
 <span class="punct">&lt;/</span><span class="namespace">xsl</span><span class="punct">:</span><span class="tag">template</span><span class="punct">&gt;</span>

 <span class="punct">&lt;</span><span class="namespace">xsl</span><span class="punct">:</span><span class="tag">template</span> <span class="attribute">match</span><span class="punct">=&quot;</span><span class="string">*</span><span class="punct">&quot;</span> <span class="attribute">mode</span><span class="punct">=&quot;</span><span class="string">BodyCopy</span><span class="punct">&quot;&gt;</span>
   <span class="punct">&lt;</span><span class="namespace">xsl</span><span class="punct">:</span><span class="tag">copy</span><span class="punct">&gt;</span>
     <span class="punct">&lt;</span><span class="namespace">xsl</span><span class="punct">:</span><span class="tag">apply-templates</span> <span class="attribute">select</span><span class="punct">=&quot;</span><span class="string">*</span><span class="punct">&quot;</span> <span class="attribute">mode</span><span class="punct">=&quot;</span><span class="string">BodyCopy</span><span class="punct">&quot;</span> <span class="punct">/&gt;</span>
   <span class="punct">&lt;/</span><span class="namespace">xsl</span><span class="punct">:</span><span class="tag">copy</span><span class="punct">&gt;</span>
 <span class="punct">&lt;/</span><span class="namespace">xsl</span><span class="punct">:</span><span class="tag">template</span><span class="punct">&gt;</span></pre>

	<p>The <code>mode</code> attribute allows different templates to match the same elements at different times. Thus the above template ensures that all elements are copied when in &#8216;BodyCopy&#8217; mode.  In order to insert the contents somewhere useful we&#8217;re going to define a new element type.  This will not be copied into the final document, instead it will be replaced with the contents table.</p>


<pre class="xml">
 <span class="punct">&lt;</span><span class="namespace">xsl</span><span class="punct">:</span><span class="tag">template</span> <span class="attribute">match</span><span class="punct">=&quot;</span><span class="string">contents</span><span class="punct">&quot;</span> <span class="attribute">mode</span><span class="punct">=&quot;</span><span class="string">BodyCopy</span><span class="punct">&quot;&gt;</span>
   <span class="punct">&lt;</span><span class="tag">ul</span><span class="punct">&gt;</span>
     <span class="punct">&lt;</span><span class="namespace">xsl</span><span class="punct">:</span><span class="tag">apply-templates</span> <span class="attribute">select</span><span class="punct">=&quot;</span><span class="string">html/body/*</span><span class="punct">&quot;</span> <span class="attribute">mode</span><span class="punct">=&quot;</span><span class="string">ContentsList</span><span class="punct">&quot;</span> <span class="punct">/&gt;</span>
   <span class="punct">&lt;/</span><span class="tag">ul</span><span class="punct">&gt;</span>
 <span class="punct">&lt;/</span><span class="namespace">xsl</span><span class="punct">:</span><span class="tag">template</span><span class="punct">&gt;</span>

 <span class="punct">&lt;</span><span class="namespace">xsl</span><span class="punct">:</span><span class="tag">template</span> <span class="attribute">match</span><span class="punct">=&quot;</span><span class="string">*</span><span class="punct">&quot;</span> <span class="attribute">mode</span><span class="punct">=&quot;</span><span class="string">ContentsList</span><span class="punct">&quot;&gt;</span>
   <span class="punct">&lt;</span><span class="namespace">xsl</span><span class="punct">:</span><span class="tag">apply-templates</span> <span class="attribute">select</span><span class="punct">=&quot;</span><span class="string">*</span><span class="punct">&quot;</span> <span class="attribute">mode</span><span class="punct">=&quot;</span><span class="string">ContentsList</span><span class="punct">&quot;</span> <span class="punct">/&gt;</span>
 <span class="punct">&lt;/</span><span class="namespace">xsl</span><span class="punct">:</span><span class="tag">template</span><span class="punct">&gt;</span>

 <span class="punct">&lt;</span><span class="namespace">xsl</span><span class="punct">:</span><span class="tag">template</span> <span class="attribute">match</span><span class="punct">=&quot;</span><span class="string">h3</span><span class="punct">&quot;</span> <span class="attribute">mode</span><span class="punct">=&quot;</span><span class="string">ContentsList</span><span class="punct">&quot;&gt;</span>
   <span class="punct">&lt;</span><span class="tag">li</span><span class="punct">&gt;</span>
     <span class="punct">&lt;</span><span class="tag">a</span> <span class="attribute">href</span><span class="punct">=&quot;</span><span class="string">{concat('#', @id)}</span><span class="punct">&quot;</span> <span class="attribute">title</span><span class="punct">=&quot;</span><span class="string">normalize-space(.)</span><span class="punct">&quot;&gt;</span>
       <span class="punct">&lt;</span><span class="namespace">xsl</span><span class="punct">:</span><span class="tag">value-of</span> <span class="attribute">select</span><span class="punct">=&quot;</span><span class="string">normalize-space(.)</span><span class="punct">&quot;</span> <span class="punct">/&gt;</span>
     <span class="punct">&lt;/</span><span class="tag">a</span><span class="punct">&gt;</span>
   <span class="punct">&lt;/</span><span class="tag">li</span><span class="punct">&gt;</span>
 <span class="punct">&lt;/</span><span class="namespace">xsl</span><span class="punct">:</span><span class="tag">template</span><span class="punct">&gt;</span></pre>

	<p>This creates the <code>&lt;ul&gt;</code> tags, and selects the top of the source document to start the search for <code>&lt;h3&gt;</code> tags.  This search is done in &#8216;ContentsList&#8217; mode, and nothing is copied by default.  When it comes across an <code>&lt;h3&gt;</code> it creates a list item that links to an element in the document with the <code>id</code> tag.  The text and title of the link are taken from the contents of the header tags.</p>


	<h3>A More Sophisticated Solution</h3>


	<p>The problem with the previous example is that all the <code>&lt;h3&gt;</code> tags need to have their <code>id</code> attributes set, which is the kind of tedious task the computer should do for itself.  Inserting the attributes can not happen as part of the &#8216;ContentsList&#8217; mode, as it is only reading elements, and can not edit them.  Instead we will change the elements during the main copying routine.  A small template is used to create the <code>id</code>, so that it is the same in both places.</p>


<pre class="xml">
 <span class="punct">&lt;</span><span class="namespace">xsl</span><span class="punct">:</span><span class="tag">template</span> <span class="attribute">name</span><span class="punct">=&quot;</span><span class="string">getId</span><span class="punct">&quot;&gt;</span>
   <span class="punct">&lt;</span><span class="namespace">xsl</span><span class="punct">:</span><span class="tag">value-of</span> <span class="attribute">select</span><span class="punct">=&quot;</span><span class="string">normalize-space(@id)</span><span class="punct">&quot;</span> <span class="punct">/&gt;</span>
   <span class="punct">&lt;</span><span class="namespace">xsl</span><span class="punct">:</span><span class="tag">if</span> <span class="attribute">test</span><span class="punct">=&quot;</span><span class="string">not(@id)</span><span class="punct">&quot;&gt;</span>
     <span class="punct">&lt;</span><span class="namespace">xsl</span><span class="punct">:</span><span class="tag">value-of</span> <span class="attribute">select</span><span class="punct">=&quot;</span><span class="string">translate(normalize-space(.), ' ', '_')</span><span class="punct">&quot;</span> <span class="punct">/&gt;</span>
   <span class="punct">&lt;/</span><span class="namespace">xsl</span><span class="punct">:</span><span class="tag">if</span><span class="punct">&gt;</span>
 <span class="punct">&lt;/</span><span class="namespace">xsl</span><span class="punct">:</span><span class="tag">template</span><span class="punct">&gt;</span>
 <span class="punct">&lt;</span><span class="namespace">xsl</span><span class="punct">:</span><span class="tag">template</span> <span class="attribute">match</span><span class="punct">=&quot;</span><span class="string">h3</span><span class="punct">&quot;</span> <span class="attribute">mode</span><span class="punct">=&quot;</span><span class="string">ContentsList</span><span class="punct">&quot;&gt;</span>
   <span class="punct">&lt;</span><span class="tag">li</span><span class="punct">&gt;</span>
     <span class="punct">&lt;</span><span class="namespace">xsl</span><span class="punct">:</span><span class="tag">variable</span> <span class="attribute">name</span><span class="punct">=&quot;</span><span class="string">id</span><span class="punct">&quot;&gt;</span>
       <span class="punct">&lt;</span><span class="namespace">xsl</span><span class="punct">:</span><span class="tag">call-template</span> <span class="attribute">name</span><span class="punct">=&quot;</span><span class="string">getId</span><span class="punct">&quot;</span> <span class="punct">/&gt;</span>
     <span class="punct">&lt;/</span><span class="namespace">xsl</span><span class="punct">:</span><span class="tag">variable</span><span class="punct">&gt;</span>
     <span class="punct">&lt;</span><span class="tag">a</span> <span class="attribute">href</span><span class="punct">=&quot;</span><span class="string">{concat('#', $id)}</span><span class="punct">&quot;</span> <span class="attribute">title</span><span class="punct">=&quot;</span><span class="string">normalize-space(.)</span><span class="punct">&quot;&gt;</span>
       <span class="punct">&lt;</span><span class="namespace">xsl</span><span class="punct">:</span><span class="tag">value-of</span> <span class="attribute">select</span><span class="punct">=&quot;</span><span class="string">normalize-space(.)</span><span class="punct">&quot;</span> <span class="punct">/&gt;</span>
     <span class="punct">&lt;/</span><span class="tag">a</span><span class="punct">&gt;</span>
   <span class="punct">&lt;/</span><span class="tag">li</span><span class="punct">&gt;</span>
 <span class="punct">&lt;/</span><span class="namespace">xsl</span><span class="punct">:</span><span class="tag">template</span><span class="punct">&gt;</span>

 <span class="punct">&lt;</span><span class="namespace">xsl</span><span class="punct">:</span><span class="tag">template</span> <span class="attribute">match</span><span class="punct">=&quot;</span><span class="string">h3</span><span class="punct">&quot;</span> <span class="attribute">mode</span><span class="punct">=&quot;</span><span class="string">BodyCopy</span><span class="punct">&quot;&gt;</span>
   <span class="punct">&lt;</span><span class="namespace">xsl</span><span class="punct">:</span><span class="tag">copy</span><span class="punct">&gt;</span>
     <span class="punct">&lt;</span><span class="namespace">xsl</span><span class="punct">:</span><span class="tag">attribute</span> <span class="attribute">name</span><span class="punct">=&quot;</span><span class="string">id</span><span class="punct">&quot;&gt;</span>
       <span class="punct">&lt;</span><span class="namespace">xsl</span><span class="punct">:</span><span class="tag">call-template</span> <span class="attribute">name</span><span class="punct">=&quot;</span><span class="string">getId</span><span class="punct">&quot;</span> <span class="punct">/&gt;</span>
     <span class="punct">&lt;/</span><span class="namespace">xsl</span><span class="punct">:</span><span class="tag">attribute</span><span class="punct">&gt;</span> 
     <span class="punct">&lt;</span><span class="namespace">xsl</span><span class="punct">:</span><span class="tag">apply-templates</span> <span class="attribute">select</span><span class="punct">=&quot;</span><span class="string">@* | node()</span><span class="punct">&quot;</span> <span class="attribute">mode</span><span class="punct">=&quot;</span><span class="string">BodyCopy</span><span class="punct">&quot;</span> <span class="punct">/&gt;</span>
   <span class="punct">&lt;/</span><span class="namespace">xsl</span><span class="punct">:</span><span class="tag">copy</span><span class="punct">&gt;</span>
 <span class="punct">&lt;/</span><span class="namespace">xsl</span><span class="punct">:</span><span class="tag">template</span><span class="punct">&gt;</span></pre>

	<p>The <span class="caps">XHTML</span> specification does not allow spaces in id names, so the <code>translate()</code> is used to turn them into underscores.  If there is already an <code>id</code> specified then that is used.</p>


	<h3>Conclusion</h3>


	<p>The template presented is roughly what this site uses, although I have made some improvements.  One was to allow some <code>&lt;h3&gt;</code> tags to be excluded from the contents list by adding a <code>list="no"</code> attribute.  Another was to allow different a title to be used in the contents than the header text, however I haven&#8217;t actually used this on the site.</p>


	<h3>2007 Update</h3>


	<p>I no longer use <span class="caps">XSL</span> to generate pages for this site, Ruby on Rails handles everything instead.  This has meant the loss of the contents boxes, as I haven&#8217;t got around to replacing them.  I guess a solution would be to add an <code>after_filter</code> to the Posts controller that used regular expressions to search for <code>&lt;h3&gt;</code> tags, add in an <code>id</code> and save them to an array, before creating the contents box.</p>
      </div>
</div>


    <div id="footer">
             <span class="left">
          Last modified : 16 Apr 2007
        </span>
        
      <span class="right vcard">
       <a href="http://www.matthewwest.co.uk/website-information">Copyright &#169; 2002-2007</a>
       <a href="/email/send_email" class="fn" id="mehcardname" title="E-mail me">Matthew West</a>
      </span>
    </div>
    
    
<!-- Menu                                                            -->
<!-- $Rev:: 10#$ $Date:: 2006-12-11 03:28:11 +0000 (Mon, 11 Dec 20#$ -->  
    <div id="menu">
    <ul class="main">
      <li class="page vcard">
        <a href="#mehcardname" class="include"></a>
        <a href="http://www.matthewwest.co.uk/" class="url" rel="me">Index</a>
      </li>
      <li class="menu"><a href="/professional-experience">Professional</a>  <ul class="sub"><li class="page"><a href="/docs/cv.pdf">Resumé</a></li><li class="page"><a href="/professional-experience/earlier-lighting-work">Earlier Work</a></li><li class="page"><a href="/professional-experience/lighting-photos">Portfolio</a></li>  </ul></li><li class="menu"><a href="/lightingdb">Lighting Database</a>  <ul class="sub"><li class="menu"><a href="/lightingdb/showmanufacturer/Clay Paky">Clay Paky</a>  <ul class="sub"><li class="section"><a href="/lightingdb/showlantern/Clay Paky/Golden Scan HPE">Golden Scan HPE</a></li><li class="section"><a href="/lightingdb/showlantern/Clay Paky/MiniScan">MiniScan</a></li>  </ul></li><li class="menu"><a href="/lightingdb/showmanufacturer/High End">High End</a>  <ul class="sub"><li class="section"><a href="/lightingdb/showlantern/High End/Studio Spot 575">Studio Spot 575</a></li>  </ul></li><li class="menu"><a href="/lightingdb/showmanufacturer/Martin">Martin</a>  <ul class="sub"><li class="section"><a href="/lightingdb/showlantern/Martin/Mac 600E">Mac 600E</a></li><li class="section"><a href="/lightingdb/showlantern/Martin/Mac 2000 Wash">Mac 2000 Wash</a></li><li class="section"><a href="/lightingdb/showlantern/Martin/Mac 500">Mac 500</a></li><li class="section"><a href="/lightingdb/showlantern/Martin/Mac 250">Mac 250</a></li><li class="section"><a href="/lightingdb/showlantern/Martin/Mac 2000 Profile">Mac 2000 Profile</a></li><li class="section"><a href="/lightingdb/showlantern/Martin/Mac 500E">Mac 500E</a></li><li class="section"><a href="/lightingdb/showlantern/Martin/Mac 550">Mac 550</a></li><li class="page">...</li>  </ul></li>  </ul></li><li class="menu"><a href="/photos">Photos</a>  <ul class="sub"><li class="page"><a href="/photos/all">See them all</a></li><li class="menu"><a href="/photos/holidays">Holidays</a>  <ul class="sub"><li class="page"><a href="/photos/holidays/lofoten-islands">Lofoten</a></li><li class="section"><a href="/photos/holidays/eastern-europe">Eastern Europe</a></li><li class="page"><a href="/photos/holidays/cornwall-break">Cornwall Break</a></li><li class="page"><a href="/photos/holidays/cornish-sailing">Cornish Sailing</a></li>  </ul></li><li class="menu"><a href="/photos/lighting-photos">Lighting Photos</a>  <ul class="sub"><li class="page"><a href="/photos/lighting-photos/hampton-court">Hampton Court</a></li><li class="page"><a href="/photos/lighting-photos/dreamgirls">Dreamgirls</a></li>  </ul></li><li class="menu"><a href="/photos/misc">Other photos</a>  <ul class="sub"><li class="page"><a href="/photos/misc/bristol">Bristol</a></li><li class="page"><a href="/photos/misc/portsmouth">Portsmouth</a></li><li class="page"><a href="/photos/misc/oakley">Oakley</a></li><li class="page"><a href="/photos/misc/kingston">Kingston</a></li><li class="page"><a href="/photos/misc/cats-in-portugal">Cats</a></li>  </ul></li>  </ul></li><li class="page"><a href="/blog">Blog</a></li><li class="page"><a href="/links">Links</a></li><li class="page"><a href="/site-info">Site Info</a></li><li class="page"><a href="/email">Contact Me</a></li>
      <li class="google">
        <form action="http://www.google.com/custom" method="get">
     	  <div>
	        <a href="http://www.google.com/search">
  	          <img alt="Google" width="128" height="53" src="/images/google40.png" />
	        </a>
	        <input class="text" value="" maxlength="255" size="12" name="q" type="text" /><br />
	        <div>
	          <input value="" name="sitesearch" type="radio" />
	          All WWW<br />
	          <input checked="checked" value="www.matthewwest.co.uk" name="sitesearch" type="radio" />
	          This site only<br />
	        </div>
	        <input type="hidden" name="cof"
		           value="S:http://www.matthewwest.co.uk;GL:0;VLC:#3333ff;AH:left;LH:80;LC:#3333ff;L:http://www.matthewwest.co.uk/images/h80google.png;ALC:#3333ff;BIMG:http://www.matthewwest.co.uk/images/beams.png;LW:1165;AWFID:ab0c1f8918996ca6;"
		           />
	        <input value="www.matthewwest.co.uk" name="domains" type="hidden" />
	        <input value="Search" name="sa" type="submit" />
	      </div>
        </form>
      </li>
    </ul>
        <script type="text/javascript" src="http://embed.technorati.com/embed/hi6ybdyt32.js"> </script>
  </div>

  </body>
</html>