Edit online

How to Display Footnotes Below Tables

In your PDF output, you may want to group all the footnotes contained in a table just below it instead of having them displayed at the bottom of the page.

To add this functionality, use an Oxygen Publishing Template and follow these steps:
  1. If you have not already created a Publishing Template, you need to create one. For details, see How to Create a Publishing Template.
  2. Link the folder associated with the publishing template to your current project in the Project view.
  3. Using the view, create an xslt folder inside the project root folder.
  4. In the newly created folder, create an XSL file (for example, named merged2mergedExtension.xsl) with the following content:
    <?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"
      xmlns:opentopic-func="http://www.idiominc.com/opentopic/exsl/function"
      exclude-result-prefixes="xs opentopic-func" 
      version="2.0">
      
      <!--
        Match only top level tables (i.e tables that are not nested in other tables),
        that contains some footnotes.
      -->
      <xsl:template match="*[contains(@class, 'topic/table')]
        [not(ancestor::*[contains(@class, 'topic/table')])]
        [//*[contains(@class, 'topic/fn')]]">
        <xsl:next-match>
          <xsl:with-param name="top-level-table" select="." tunnel="yes"/>
        </xsl:next-match>
        <!-- Create a list with all the footnotes from the current table. -->
        <ol class="- topic/ol " outputclass="table-fn-container">
          <xsl:for-each select=".//*[contains(@class, 'topic/fn')]">
            <!--
              Try to preserve the footnote ID, if available, so that the xrefs will have a target.
            -->
            <li class="- topic/li " id="{if(@id) then @id else generate-id(.)}"
              outputclass="table-fn">
              <xsl:copy-of select="@callout"/>
              <xsl:apply-templates select="node()"/>
            </li>
          </xsl:for-each>
        </ol>
      </xsl:template>
      
      <!-- 
        The footnotes that have an ID must be ignored, they are accessible only 
        through existing xrefs (already present in the merged.xml file).
        
        The above template already made a copy of these footnotes in the OL element
        so it is not a problem if markup is not generated for them in the cell.
      -->
      <xsl:template
        match="*[contains(@class, 'topic/entry')]//*[contains(@class, 'topic/fn')][@id]"/>
      
      <!--
        The xrefs to footnotes with IDs inside table-cells. We need to recalculate
        their indexes if their referenced footnote is also in the table.
      -->
      <xsl:template match="*[contains(@class, 'topic/xref')][@type='fn']
        [ancestor::*[contains(@class, 'topic/entry')]]">
        <xsl:param name="top-level-table" tunnel="yes"/>
        <xsl:variable name="destination" select="opentopic-func:getDestinationId(@href)"/>
        <xsl:variable name="fn" select="
          $top-level-table//*[contains(@class, 'topic/fn')][@id = $destination]"/>
        <xsl:choose>
          <xsl:when test="$fn">
            <!-- There is a reference in the table, recalculate index. -->
            <xsl:variable name="fn-number" select="
              index-of($top-level-table//*[contains(@class, 'topic/fn')], $fn)"/>
            <xsl:copy>
              <xsl:apply-templates select="@*"/>
              <xsl:apply-templates select="$fn/@callout"/>
              <xsl:apply-templates select="node()
                except (text(), *[contains(@class, 'hi-d/sup')])"/>
              <sup class="+ topic/ph hi-d/sup ">
                <xsl:apply-templates select="child::*[contains(@class, 'hi-d/sup')]/@*"/>
                <xsl:value-of select="$fn-number"/>
              </sup>
            </xsl:copy>
          </xsl:when>
          <xsl:otherwise>
            <!-- There is no reference in the table, keep original index. -->
            <xsl:next-match/>
          </xsl:otherwise>
        </xsl:choose>
      </xsl:template>
      
      <!-- 
        The footnotes without ID inside table-cells. They are copied in the OL element, but have 
        no xrefs pointing to them (because they have no ID), so xrefs are generated. 
      -->
      <xsl:template
        match="*[contains(@class, 'topic/entry')]//*[contains(@class, 'topic/fn')][not(@id)]">
        <!-- Determine the footnote index in the document order. -->
        <xsl:param name="top-level-table" tunnel="yes"/>
        <xsl:variable name="fn-number" select="
          index-of($top-level-table//*[contains(@class, 'topic/fn')], .)"/>
        <xref type="fn" class="- topic/xref "
          href="#{generate-id(.)}" outputclass="table-fn-call">
          <xsl:copy-of select="@callout"/>
          <!-- Generate an extra <sup>, identical to what DITA-OT generates for other xrefs. -->
          <sup class="+ topic/ph hi-d/sup ">
            <xsl:value-of select="$fn-number"/>
          </sup>
        </xref>
      </xsl:template>
      
    </xsl:stylesheet>
  5. Open the template descriptor file associated with your publishing template (the .opt file) and set the XSLT stylesheet created in the previous step with the com.oxygenxml.pdf.css.xsl.merged2merged XSLT extension point:
    <publishing-template>
     ...
     <pdf>
      ...        
      <xslt>
        <extension
          id="com.oxygenxml.pdf.css.xsl.merged2merged"
          file="xslt/merged2mergedExtension.xsl"/>
       </xslt>
  6. Create a css folder in the publishing template directory. In this directory, save a custom CSS file with rules that style the glossary structure. For example:
    /* Customize footnote calls, inside the table. */
    *[outputclass ~= 'table-fn-call'] {
      line-height: none;
    }
    *[class ~= "topic/table"] *[class ~= "topic/xref"][type = 'fn'][callout] *[class ~= "hi-d/sup"] {
      content: oxy_xpath("ancestor::*[contains(@class, 'topic/xref')]/@callout");
    }
    
    /* Customize the list containing all the table footnotes. */
    *[outputclass ~= 'table-fn-container'] {
      border-top: 1pt solid black;
      counter-reset: table-footnote;
    }
    
    /* Customize footnotes display, below the table. */
    *[outputclass ~= 'table-fn'] {
      font-size: smaller;
      counter-increment: table-footnote;
    }
    *[outputclass ~= 'table-fn']::marker {
      font-size: smaller;
      content: "(" counter(table-footnote) ")";
    }
    *[outputclass ~= 'table-fn'][callout]::marker {
      content: "(" attr(callout) ")";
    }
    
    /* Customize xrefs pointing to footnotes, inside the table. */
    *[class ~= "topic/table"] *[class ~= "topic/xref"][type = 'fn'] {
      color: unset;
      text-decoration: none;
    }
    *[class ~= "topic/table"] *[class ~= "topic/xref"][type = 'fn']:after {
      content: none;
    }
    *[class ~= "topic/table"] *[class ~= "topic/xref"][type = 'fn'] *[class ~= "hi-d/sup"]:before {
      content: "(";
    }
    *[class ~= "topic/table"] *[class ~= "topic/xref"][type = 'fn'] *[class ~= "hi-d/sup"]:after {
      content: ")";
    }
  7. Open the template descriptor file associated with your publishing template (the .opt file) and reference your custom CSS file in the resources element:
    <publishing-template>
      ...
      <pdf>
        ...                
        <resources>            
          <css file="css/custom.css"/>
        </resources> 
  8. Edit the DITA Map PDF - based on HTML5 & CSS transformation scenario.
  9. In the Templates tab, click the Choose Custom Publishing Template link and select your template.
  10. Click OK to save the changes and run the transformation scenario.