Search code examples
xsltxsl-fotableofcontents

Table of Contents XSL-FO XSLT 1.0


XML:

<levelledPara><title>Tools List and Tool Illustrations</title>
<levelledPara><title>General</title>
<levelledPara><para>The special tools, fixtures, and equipment needed.</para></levelledPara></levelledPara>

XSLT:

<xsl:template match="levelledPara" name="levelledPara" mode="tocdm">
    <xsl:if test="*[self::title] and not(parent::*[self::levelledPara])">
        <xsl:variable name="id">
            <xsl:call-template name="para.id"/>
        </xsl:variable>
    <fo:table-row>
        <fo:table-cell xsl:use-attribute-sets="table.cell.padding1" number-columns-spanned="2">
            <fo:block  text-transform="capitalize" text-align-last="justify" text-indent="21mm">
                            <xsl:number count="levelledPara" from="content" level="multiple" format="1.1.1.1.1"/>
                            <xsl:text>&#160;&#160; </xsl:text>
                <xsl:value-of select="title" /><fo:leader leader-pattern="dots"/><fo:basic-link internal-destination="{$id}"><fo:page-number-citation ref-id="{$id}"/></fo:basic-link>

            </fo:block> 
        </fo:table-cell>
    </fo:table-row>
    </xsl:if>   
</xsl:template>

<xsl:template match="levelledPara">
        <fo:list-block 
            provisional-distance-between-starts="21mm"
            provisional-label-separation="4pt">
            <fo:list-item space-after="8pt" space-before="13pt" start-indent="0pt">             
                    <xsl:variable name="id">
                        <xsl:if test="*[self::title] and not(parent::*[self::levelledPara])">
<xsl:call-template name="para.id"/>
                        </xsl:if>
                    </xsl:variable>
                <fo:list-item-label
                    end-indent="label-end()"
                    text-align="start">

                    <fo:block font-weight="bold" id="{$id}">                
                        <xsl:if test="not(./table)">
                                    <xsl:number count="levelledPara" from="content" level="multiple" format="1.1.1.1.1"/>
                                </xsl:if>
                    </fo:block>
                </fo:list-item-label>
                <fo:list-item-body
                    start-indent="body-start()">
                    <xsl:apply-templates/>  
                </fo:list-item-body>
            </fo:list-item>
        </fo:list-block>
    </xsl:template>

<xsl:template name="para.id">
  <xsl:param name="object" select="."/>
  <xsl:apply-templates select="ancestor::dmodule/identAndStatusSection/dmAddress/dmIdent/dmCode"/>
  <xsl:choose>
    <xsl:when test="$object/@id">
           <xsl:value-of select="$object/@id"/>
    </xsl:when>
    <xsl:otherwise>
      <xsl:value-of select="concat(count(ancestor::node()),'00000000',count(preceding::node()))"/>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

The first titled levelledPara should be included in the Table of Contents. In my sample markup none have IDs. The page number wasn't resolving because I forgot to assign an id to the fo:block for levelledPara.


Solution

  • You've shown the XSLT for the table of contents. The ID in the TOC should match an ID in the main text of your document.

    So the template match="levelledPara" should contain a block that sets the ID:

    <xsl:variable name="lpcode"><xsl:value-of select="$dmcode" /><xsl:value-of select="generate-id(.)" /></xsl:variable>
    <fo:block id="{$lpcode}">