Create a list of numbered footnotes using XSLT
|Debian (Lenny, Squeeze)|
|Ubuntu (Lucid, Precise, Trusty)|
To create a list of automatically numbered footnotes using XSLT, with matching footnote markers in the text and next to each footnote.
Suppose that you want to add support for automatically-numbered footnotes to an XSLT stylesheet.
In the input document, each footnote is represented by a
footnote element that contains the text of the footnote
and is placed at the point in the document to which it refers, for example:
<p>Three is the number to which you will count.<footnote>Armaments 2:9-21</footnote></p>
In the output document, the footnotes should be moved to a list at the end of the page. Each footnote should leave behind a superscripted footnote marker of the form [n] at the location on the page to which it refers. There should be a matching footnote marker next to the relevant footnote, for example:
Three is the number to which you will count.
 Armaments 2:9-21
Matching footnote markers should be hyperlinked to each other. The list of footnotes should be represented by an
element of class
footnote, and each member of that list should be an
li element of class
(The element types
li have been chosen because they are semantically correct.
Their default style is unlikely to be appropriate, but this can easily be changed using a suitable CSS stylesheet.)
The method described here has three steps:
- When they are first encountered, transform each footnote element into a numbered footnote marker.
- At the end of the page body, perform a second pass through the input document searching for footnote elements.
- During the second pass, transform each footnote element into a footnote marker and the corresponding text.
Transform each footnote element into a numbered footnote marker
At the point in the text where the footnote appears in the input document, it should appear only as a footnote marker in the output document.
The template for a
footnote element should not therefore include an
instruction, but instead contain the markup needed to construct a footnote marker.
Numbering is performed using the
xsl:number instruction to count the number of footnote elements in the input document
up to and including the current one:
<xsl:number level="any" count="footnote" format=""/>
level attribute specifies that the elements counted need not be siblings of the current
footnote element, but rather, can occur at any level of the input document (higher or lower).
count attribute specifies that only
footnote elements are to be counted.
format attribute specifies that the value should be written to the output document as a decimal
number in square brackets. (The brackets could have been added later, but it is slightly neater to generate them here.)
To perform the hyperlinking it is necessary to choose an anchor names for each footnote marker. Every anchor name in the document
must be unique, and the easiest way to achieve this is by incorporating the footnote number into the name. The scheme that will be
used here is as follows, where
N is the footnote number:
- Footnote markers that refer to a footnote elsewhere have anchor names of the form
- Footnote markers that label an adjacent footnote have anchor names of the form
The numbers are generated using the same method as before, except that instead of being written to the output document as text
it must become part of the value of either a
name or an
This is done using an
xsl:attribute instruction, which converts its content into an attribute value.
The resulting template as as follows:
<xsl:template match="footnote"> <a> <xsl:attribute name="name"> <xsl:text>footnoteref</xsl:text><xsl:number level="any" count="footnote" format="1"/> </xsl:attribute> <xsl:attribute name="href"> <xsl:text>#footnote</xsl:text><xsl:number level="any" count="footnote" format="1"/> </xsl:attribute> <sup><xsl:number level="any" count="footnote" format=""/></sup> </a> </xsl:template>
Perform a second pass through the input document searching for footnote elements
By default the
xsl:apply-templates instruction acts on the content of the current node from the input document,
however it can be instructed to act on the result of any XPath expression. This can select any subset of the input document,
including parts that have already been processed.
In this case the requirement is to select all
footnote elements wherever they occur.
This can be done using the XPath expression ‘
//footnote’, meaning elements of type
footnote that are descended from the root node.
Here is an example of how the relevant instructions could be incorporated into a template for an HTML-style
<xsl:template match="body"> <body> <xsl:apply-templates/> <ol class="footnotes"> <xsl:apply-templates select="//footnote" mode="footnote"/> </ol> </body> </xsl:template>
Alternatively, it may be preferable for the source document to explicitly indicate where the list of footnotes should be inserted.
mode attribute of the
apply-templates instruction is explained below.
Transform each footnote element into a footnote marker and the corresponding text
During the second pass the
footnote elements will be transformed again, but the result must be different from that
obtained during the first pass. Instead of just a footnote marker, the entire footnote must be generated as the content of a list item.
XSLT allows this to be done by passing a
mode argument to the relevant
apply-templates instructions. In this example the mode has been named
<xsl:template match="footnote" mode="footnote"> <li> <a> <xsl:attribute name="name"> <xsl:text>footnote</xsl:text><xsl:number level="any" count="footnote" format="1"/> </xsl:attribute> <xsl:attribute name="href"> <xsl:text>#footnoteref</xsl:text><xsl:number level="any" count="footnote" format="1"/> </xsl:attribute> <xsl:number level="any" count="footnote" format=""/> </a> <xsl:text> </xsl:text> <xsl:apply-templates/> </li> </xsl:template>
As previously, the
xsl:number instruction has been used to number both the footnote marker and the hyperlink anchors.
The footnote body is output using an ordinary
xsl:apply-templates instruction so that any stylistic markup within it
is appropriately transformed.