Reputation: 301
I have a bunch of content containing calstables where the footnoting has been done using typesetting techniques, with each of the indices set using <sup/>
elements and each of the footnotes included in its own straddle row at the end of the table.
I want to convert these to use Docbook footnote markup like this and this
The sample data is as follows (I have added <from/>
and <to/>
elements to show where it is coming from and where it needs to go to)
<testdata>
<from>
<table>
<tgroup cols="3">
<colspec colname="1" colnum="1" colwidth="39pt" align="left"/>
<colspec colname="2" colnum="2" colwidth="39pt" align="center"/>
<colspec colname="3" colnum="3" colwidth="39pt" align="center"/>
<thead>
<row valign="bottom">
<entry>Item</entry>
<entry>ItemA</entry>
<entry>ItemB<sup>1</sup></entry>
</row>
</thead>
<tbody>
<row valign="top">
<entry>Entry 1</entry>
<entry>60</entry>
<entry>3.2</entry>
</row>
<row>
<entry>Entry A</entry>
<entry>150</entry>
<entry>3.55<sup>2</sup></entry>
</row>
<row>
<entry>This entry</entry>
<entry>260<sup>3</sup></entry>
<entry>3.55<sup>2</sup></entry>
</row>
<row>
<entry align="left" namest="1" nameend="3"><sup>1</sup> LAT</entry>
</row>
<row>
<entry align="left" namest="1" nameend="3"><sup>2</sup> Itemvalue <24.5 m. Also see note below.</entry>
</row>
<row>
<entry align="left" namest="1" nameend="3"><sup>3</sup> Ramp up 19.8 m.</entry>
</row>
</tbody>
</tgroup>
</table>
</from>
<to>
<table>
<tgroup cols="3">
<colspec colname="1" colnum="1" colwidth="39pt" align="left"/>
<colspec colname="2" colnum="2" colwidth="39pt" align="center"/>
<colspec colname="3" colnum="3" colwidth="39pt" align="center"/>
<thead>
<row valign="bottom">
<entry>Item</entry>
<entry>ItemA</entry>
<entry>ItemB<footnote id="1">LAT</footnote></entry>
</row>
</thead>
<tbody>
<row valign="top">
<entry>Entry 1</entry>
<entry>60</entry>
<entry>3.2</entry>
</row>
<row>
<entry>Entry A</entry>
<entry>150</entry>
<entry>3.55<footnote id="2">Itemvalue <24.5 m. Also see note below.</footnote></entry>
</row>
<row>
<entry>This entry</entry>
<entry>260<footnote id="3">Ramp up 19.8 m.</footnote></entry>
<entry>3.55<footnoteref linkend="2"/></entry>
</row>
</tbody>
</tgroup>
</table>
</to>
</testdata>
The logic is reasonably straightforward to articulate:
1. Copy everthing to output, unless ...
2. it contains a `<sup/>` element, in which case either
1. if it has a `@nameend` attribute, do nothing, or
2. if it is the first instance of this index, create a footnote element with an `@id` attribute, grabbing the content from the matching straddle row, or
3. if it's not the first instance, create a footnoteref element, with a matching `@linkend` attribute
Of course there is a bunch of error checking too, but I'm not too worried about that now.
I can address each of #2 above, using a bunch of individual match patterns like
<xsl:template match="sup[text() = '1'][1]">
<xsl:template match="sup[text() = '2'][1]">
<xsl:template match="sup[text() = '3'][1]">
but I figure there must be a more elegant match pattern (perhaps using keys?) to match the first instance of each index used, but for the life of me I can't think what it might be.
I have defined 2 keys so far
<xsl:key name="fn-indices" match="sup" use="number(.)"/>
<xsl:key name="fn-text" match="entry[sup][@nameend > @namest]" use="number(sup)"/>
But I'm not sure how best to use them?
Any suggestions for an elegant match pattern for the 1st instance of each index?
Upvotes: 0
Views: 44
Reputation: 301
So I've come up with this template which seems to do what I want
Note: I have shortened footnote
to fn
and footnoteref
to fnref
to avoid conflicts with other processes for the moment.
Also instead of using is
I have used generate-id()
which is 1.0 compliant but I will probably change this in due course
<xsl:template match="sup" mode="sup2fn" priority="10">
<xsl:variable name="index" select="number(normalize-space(.))"/>
<xsl:variable name="this-table" select="ancestor::*[local-name() = 'table']"/>
<xsl:variable name="fn-text-nodes" select="key('fn-text',$index)[generate-id(ancestor::*[local-name() = 'table']) = generate-id($this-table)][1]"/>
<xsl:variable name="idref-here" select="generate-id(.)"/>
<xsl:variable name="instance-1" select="key('fn-indices',$index)[generate-id(ancestor::*[local-name() = 'table']) = generate-id($this-table)][1]"/>
<xsl:variable name="idref-target" select="generate-id($instance-1)"/>
<xsl:variable name="fn-text">
<xsl:apply-templates select="$fn-text-nodes/node()" mode="make-footnote-text"/>
</xsl:variable>
<xsl:choose>
<xsl:when test="generate-id(.) = generate-id($instance-1) ">
<fn id="{$idref-here}">
<xsl:if test="$debug = 'yes'">
<xsl:attribute name="index"><xsl:value-of select="$index"/></xsl:attribute>
</xsl:if><xsl:value-of select="normalize-space($fn-text)"/></fn>
</xsl:when>
<xsl:otherwise>
<fnref linkend="{$idref-target}">
<xsl:if test="$debug = 'yes'">
<xsl:attribute name="index"><xsl:value-of select="$index"/></xsl:attribute>
</xsl:if>
</fnref>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
I have had to account for the possibility of multiple tables too, so I am testing that that the sup nodes have the same parent. I wonder if that might be more efficient in the key definition?
Also I have maintatined the original index for debug purposes, as well as creating new id
attributes
Lastly, instead of using seperate match patterns, I have a single sup
template and have used an <xsl:choose>
branch in there to test if this is the first or a subsequent instance of <sup>
Upvotes: 0
Reputation: 167781
sup[. is key('fn-indices', number())[1]]
should match the first item in each "group" so you should be able to replace
<xsl:template match="sup[text() = '1'][1]">
<xsl:template match="sup[text() = '2'][1]">
<xsl:template match="sup[text() = '3'][1]">
with
<xsl:template match="sup[. is key('fn-indices', number())[1]]">
The is
operator checks node identity.
Upvotes: 1