Search code examples
xsltxsl-fosaxonfootnotesantenna-house

How can Antennahouse Formatter handle referenced footnotes?


I am developing a pdf print publication with xsl-fo (Saxon XSL 2.0, AHF V6.2).

My goal is to have auto-numbered footnotes (excluding duplicates on a single page) with inserted text from referenced static text elements.

So basically inline footnotes (fn) do reference a static footnote text element, create an inline number and print the according footnote text at the bottom of the page.

<?xml version="1.0" encoding="UTF-8"?>
<document>
<chapter>
    <paragraph>some description...</paragraph>
    <paragraph>some description with a footnote <fn id="fn2"/></paragraph>
    <paragraph>some description with a footnote <fn id="fn2"/></paragraph>
    <paragraph>some description...</paragraph>
    <paragraph>some description with a footnote <fn id="fn1"/></paragraph>
</chapter>
<!-- this is a wrapper element that will not be displayed in the rendered pdf but only contains the needed information for different footnote texts -->
<chapter class="footnoteWrapper">
    <footnote id="fn1">
        This is the text body of footnote #1.
    </footnote>
    <footnote id="fn2">
        This is the text body of footnote #2.
    </footnote>
    <footnote id="fn3">
        This is the text body of footnote #3.
    </footnote>
</chapter>
</document>

Duplicate inline footnotes in a chapter have to show the same number according to the footnote they are pointing to.

This is what the result should look like...

Possible output

Is it possible to achieve these goals with the AHF footnote extensions and the fo:footnote elements?

The AntennaHouse Formatter extentions do deliver strange behaviour if I´m using them for fn counting. They do continue counting (1, 2, 3) instead of refereing to the correct and current number of the referenced footnote.

This is the XSL so far (just the relevant snippet):

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    exclude-result-prefixes="xs"
    version="2.0">

<xsl:template match="fn[@id = //footnote/@nodeid]"
    mode="content"
    priority="7">
    <!--+ fn link
        |
        | basic fn (inline) link template.
        |
        +-->
    <xsl:apply-templates select="//footnote[@id = current()/@id]"
        mode="content"/>
</xsl:template>

<xsl:template match="footnote"
    mode="content"
    priority="5">
    <!--+ footnote
        |
        | basic footnote template.
        |
        +-->
    <fo:footnote xsl:use-attribute-sets="fnt.footnote">
        <fo:inline baseline-shift="super">
            <axf:footnote-number id="fn_{@id}"/>
        </fo:inline>
        <fo:footnote-body space-after="1mm">
            <fo:list-block provisional-distance-between-starts="5mm"
                provisional-label-separation="2mm">
                <fo:list-item>
                    <fo:list-item-label end-indent="label-end()">
                        <fo:block>
                            <fo:inline baseline-shift="super">
                                <axf:footnote-number-citation ref-id="fn_{@id}"/>
                            </fo:inline>
                        </fo:block>
                    </fo:list-item-label>
                    <fo:list-item-body start-indent="body-start()">
                        <fo:block>
                            <xsl:apply-templates mode="content"/>
                        </fo:block>
                    </fo:list-item-body>
                </fo:list-item>
            </fo:list-block>
        </fo:footnote-body>
    </fo:footnote>
</xsl:template>
</xsl:stylesheet>

Solution

  • These changes generate the footnote the first time that the footnote is used and just generate the number for subsequent times:

    <xsl:key name="fn" match="fn[exists(key('footnote', @id))]" use="@id" />
    <xsl:key name="fn-first" match="fn[. is key('fn', @id)[1]]" use="@id" />
    <xsl:key name="footnote" match="footnote" use="@id" />
    
    <xsl:template match="fn[exists(key('footnote', @id))][. is key('fn-first', @id)]"
        mode="content"
        priority="7">
        <xsl:apply-templates select="key('footnote', @id)"
            mode="content">
            <xsl:with-param name="number" select="count(preceding::fn[. is key('fn-first', @id)]) + 1"></xsl:with-param>
        </xsl:apply-templates>
    </xsl:template>
    
    <xsl:template match="fn[exists(key('footnote', @id))][not(. is key('fn-first', @id))]"
        mode="content"
        priority="7">
        <fo:inline baseline-shift="super">
            <xsl:value-of select="count(key('fn-first', @id)/preceding::fn[. is key('fn-first', @id)]) + 1"/>
        </fo:inline>
    </xsl:template>
    
    <xsl:template match="footnote" mode="content" priority="5">
        <xsl:param name="number" select="count(preceding-sibling::footnote) + 1" as="xs:integer" />
        <fo:footnote xsl:use-attribute-sets="fnt.footnote">
            <fo:inline baseline-shift="super">
                <xsl:value-of select="$number" />
            </fo:inline>
            <fo:footnote-body space-after="1mm">
                <fo:list-block provisional-distance-between-starts="5mm"
                    provisional-label-separation="2mm">
                    <fo:list-item>
                        <fo:list-item-label end-indent="label-end()">
                            <fo:block>
                                <fo:inline baseline-shift="super">
                                    <xsl:value-of select="$number" />
                                </fo:inline>
                            </fo:block>
                        </fo:list-item-label>
                        <fo:list-item-body start-indent="body-start()">
                            <fo:block>
                                <xsl:apply-templates mode="content" />
                            </fo:block>
                        </fo:list-item-body>
                    </fo:list-item>
                </fo:list-block>
            </fo:footnote-body>
        </fo:footnote>
    </xsl:template>
    

    You could tidy it up a bit more by, e.g., making a function that returns the count() value for a fn, but this should get you going.

    See my other answer for how you can use both axf:suppress-duplicate-footnote and axf:footnote-number so duplicates are suppressed only when the duplicates are on the same page.