Reputation: 473407
I have a bunch of DocBook XML files that all get merged into a single DocBook file for conversion into HTML. Each individual document is a reference page (for a function or similar construct). I use chunked HTML generation, so that each reference page becomes its own HTML page.
The problem is this: I want a table of contents on each page. But I don't want the table of contents for that page. I want the full TOC for the entire reference manual.
That is, from any page, I want to be able to jump to any other page by using the TOC. I can use CSS styling to stick the TOC on the left side (and even hide it for mobile viewing or whatever).
There's an obvious way to handle this. I could extract the main TOC via a post-process script and have the script copy this into each of the output HTML documents. What I'm looking for is a way to do it that works within DocBook XSL.
I want the results to look rather like DocBook XSL's newer webhelp, but with less overt JavaScript involvement.
Upvotes: 1
Views: 742
Reputation: 849
As of 2019-07-06 with docbook-xsl-1.79.2 the currently accepted answer isn't sufficient to make each table of contents complete.
The following XSL template does, however. The key insight was stepping through with the Oxygen XML editor's debugger and noticing that while the toc-context
was correctly set to the root element, the nodes
variable was still the local subset.
I undid the toc-context
change. Instead I created a new variable root-nodes
selecting /
, and edited the make.toc
template to use root-nodes
instead of nodes.
Putting this in my customisation layer now makes every table of contents a complete table of contents.
<xsl:template name="make.toc">
<xsl:param name="toc-context" select="."/>
<xsl:param name="toc.title.p" select="true()"/>
<xsl:param name="nodes" select="/NOT-AN-ELEMENT"/>
<xsl:variable name="root-nodes" select="/"/>
<xsl:variable name="nodes.plus" select="$root-nodes | d:qandaset"/>
<xsl:variable name="toc.title">
<xsl:if test="$toc.title.p">
<xsl:choose>
<xsl:when test="$make.clean.html != 0">
<div class="toc-title">
<xsl:call-template name="gentext">
<xsl:with-param name="key">TableofContents</xsl:with-param>
</xsl:call-template>
</div>
</xsl:when>
<xsl:otherwise>
<p>
<strong>
<xsl:call-template name="gentext">
<xsl:with-param name="key">TableofContents</xsl:with-param>
</xsl:call-template>
</strong>
</p>
</xsl:otherwise>
</xsl:choose>
</xsl:if>
</xsl:variable>
<xsl:choose>
<xsl:when test="$manual.toc != ''">
<xsl:variable name="id">
<xsl:call-template name="object.id"/>
</xsl:variable>
<xsl:variable name="toc" select="document($manual.toc, .)"/>
<xsl:variable name="tocentry" select="$toc//d:tocentry[@linkend=$id]"/>
<xsl:if test="$tocentry and $tocentry/*">
<div class="toc">
<xsl:copy-of select="$toc.title"/>
<xsl:element name="{$toc.list.type}" namespace="http://www.w3.org/1999/xhtml">
<xsl:call-template name="toc.list.attributes">
<xsl:with-param name="toc-context" select="$toc-context"/>
<xsl:with-param name="toc.title.p" select="$toc.title.p"/>
<xsl:with-param name="nodes" select="$root-nodes"/>
</xsl:call-template>
<xsl:call-template name="manual-toc">
<xsl:with-param name="tocentry" select="$tocentry/*[1]"/>
</xsl:call-template>
</xsl:element>
</div>
</xsl:if>
</xsl:when>
<xsl:otherwise>
<xsl:choose>
<xsl:when test="$qanda.in.toc != 0">
<xsl:if test="$nodes.plus">
<div class="toc">
<xsl:copy-of select="$toc.title"/>
<xsl:element name="{$toc.list.type}" namespace="http://www.w3.org/1999/xhtml">
<xsl:call-template name="toc.list.attributes">
<xsl:with-param name="toc-context" select="$toc-context"/>
<xsl:with-param name="toc.title.p" select="$toc.title.p"/>
<xsl:with-param name="nodes" select="$root-nodes"/>
</xsl:call-template>
<xsl:apply-templates select="$nodes.plus" mode="toc">
<xsl:with-param name="toc-context" select="$toc-context"/>
</xsl:apply-templates>
</xsl:element>
</div>
</xsl:if>
</xsl:when>
<xsl:otherwise>
<xsl:if test="$root-nodes">
<div class="toc">
<xsl:copy-of select="$toc.title"/>
<xsl:element name="{$toc.list.type}" namespace="http://www.w3.org/1999/xhtml">
<xsl:call-template name="toc.list.attributes">
<xsl:with-param name="toc-context" select="$toc-context"/>
<xsl:with-param name="toc.title.p" select="$toc.title.p"/>
<xsl:with-param name="nodes" select="$root-nodes"/>
</xsl:call-template>
<xsl:apply-templates select="$root-nodes" mode="toc">
<xsl:with-param name="toc-context" select="$toc-context"/>
</xsl:apply-templates>
</xsl:element>
</div>
</xsl:if>
</xsl:otherwise>
</xsl:choose>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
Note: there is a remaining issue where not every chunked page gets its own ToC, but that is unrelated to this specific. If I sort it, I'll add a comment on how I did that.
Upvotes: 2
Reputation: 88066
There’s a relatively easy way to get that, though I’m pretty sure you can’t without either creating a DocBook XSL customization layer or just directly modifying the installed (system) stylesheets.
Either way, I think the actual docbook-xsl template you need to modify or override is named make.toc
, located in the stylesheets distribution in the file html/autotoc.xsl
.
It’s a big template—nearly a hundred lines—but you only need to make a one-line change to it:
--- /usr/share/xml/docbook/stylesheet/docbook-xsl/html/autotoc.xsl 2012-12-16 11:35:12.000000000 +0900
+++ /opt/workspace/autotoc.xsl 2015-12-26 09:19:36.000000000 +0900
@@ -28,7 +28,7 @@
</xsl:variable>
<xsl:template name="make.toc">
- <xsl:param name="toc-context" select="."/>
+ <xsl:param name="toc-context" select="/"/>
<xsl:param name="toc.title.p" select="true()"/>
<xsl:param name="nodes" select="/NOT-AN-ELEMENT"/>
That is, you need to call that template with the toc-context
param set to "/
" (instead of ".
").
The default ".
" value tells the template that, when creating a TOC for a chunk, it should only look at the (child) content of whatever element it’s currently processing (that is, the root of that particular chunk); for example, if it’s processing a section
it looks only at the children of that section
.
But if you instead change that value to "/
", you’re telling the template to (re)look at the entire content of the source document each time. So if your document is a book
, it’ll give you the entire TOC for the whole book each time, or if your document is an article
, the entire article, etc.
So I think that should give you what you’re wanting.
If you decide to just modify the installed stylesheets and you’ve installed them from any OS-specific package manager you use, you need to find where the html/autotoc.xsl
file is installed.
On my Debian Linux system the html/autotoc.xsl
file is here:
/usr/share/xml/docbook/stylesheet/docbook-xsl/html/autotoc.xsl
And on my OS X system, installed from a homebrew package, it’s here:
/usr/local/opt/docbook-xsl/docbook-xsl/html/autotoc.xsl
If you decide to instead create a customization layer, you’ll need to copy that entire make.toc
template into your customization layer (but with that toc-context
param changed to "/
").
Upvotes: 1