| The XML Site | XSL templates for processing the titles of recursive web page sections |
| XML Site | Articles |
ArticlesBeyond HTML | Processing sections titlesWe've left the sections, titles and paragraphs in the XML Schema and XSL templates for web articles article in a simple, flat view. However, the whole reason we permitted recursive sections was to be able to show them as such in the generated HTML page. Let's see how. Headings corresponding to the title levelFor each title, we currently use the H1 tag. Instead, we should output headings that correspond to the imbrication level of that section. The first section should use the H1 tag for its title, the second the H2 tag, etc. Let's see how we can do that. The section templateWe will compute the level of the section starting with 1 for the outermost one and incrementing it with each sub-section. The level is passed from one section to its subsections in a tunneled parameter. <xsl:template match="section">
<xsl:param name="level" tunnel="yes">0</xsl:param>
<xsl:variable name="nextLevel" select="$level + 1"/>
<xsl:apply-templates>
<xsl:with-param name="level" select="$nextLevel" tunnel="yes"/>
</xsl:apply-templates>
</xsl:template>
The title templatesNow all we have to do in the title template is to retrieve the level and use it when outputting the H tag. <xsl:template match="title">
<xsl:param name="level" tunnel="yes">1</xsl:param>
<xsl:element name="h{$level}">
<xsl:apply-templates/>
</xsl:element>
</xsl:template>
The generated HTMLWe are now using Hn tags, where n is the imbrication level of the section. <h1>Section 1</h1>
<p>Paragraph</p>
<h2>Sub-Section 1.1</h2>
<h3>Sub-Section 1.1.1</h3>
<p>Text</p>
<p>Untitled Section 2 Paragraph</p>
Limit headings at 6 levels deepThe trouble is that the HTML specification allows only six H tags: from H1 to H6. So we need to limit our output accordingly, by changing the title template. ...
<xsl:param name="level" tunnel="yes">1</xsl:param>
<xsl:variable name="heading" select="if ($level < 6) then $level else 6"/>
<xsl:element name="h{$heading}">
<xsl:apply-templates/>
</xsl:element>
...
Adding a little more XML test content, <section>
<title>Sub-Section 1.1.1.1 (level 4)</title>
<section>
<title>Sub-Section 1.1.1.1.1 (level 5)</title>
<section>
<title>Sub-Section 1.1.1.1.1.1 (level 6)</title>
<section>
<title>Sub-Section 1.1.1.1.1.1.1 (level 7)</title>
</section>
</section>
</section>
</section>shows that the title for the sections more than 6 levels deep are all using the H6 tag: <h4>Sub-Section 1.1.1.1 (level 4)</h4>
<h5>Sub-Section 1.1.1.1.1 (level 5)</h5>
<h6>Sub-Section 1.1.1.1.1.1 (level 6)</h6>
<h6>Sub-Section 1.1.1.1.1.1.1 (level 7)</h6>
Numbered titlesA nice-to-have feature is the ability to automatically number the section titles according to the section level and section count. Luckily, XSLT provides a very powerful command just for that, called xsl:number. The trick now is to keep this feature optional and to offer the ability to not number the title of the outer-most section, as that could be seen as a page title. To control the two behaviors we will use two sheet parameters. <xsl:param name="numbered-sections"/> <xsl:param name="numbered-first-section"/> And we will change the title template like this: ...
<xsl:element name="h{$heading}">
<xsl:if test="$numbered-sections">
<xsl:choose>
<xsl:when test="$numbered-first-section">
<xsl:number level="multiple" count="section" format="1.1 "/>
</xsl:when>
<xsl:otherwise>
<xsl:number level="multiple" count="section/section" format="1.1 "/>
</xsl:otherwise>
</xsl:choose>
</xsl:if>
<xsl:apply-templates/>
</xsl:element>
...
When the two parameters are set to true, the output of the transform becomes: <h1>1 Section 1</h1>
<p>Paragraph</p>
<h2>1.1 Sub-Section 1.1</h2>
<h3>1.1.1 Sub-Section 1.1.1</h3>
<p>Text</p>
DIVs around sectionsThere are many ways other to show embedded subsections. A couple that come to mind are:
They can both be easily implemented by outputting DIV tags for each section and having CSS display rules for on the tags. Styled DIVs around sectionsUsing a sheet parameter to condition this behavior, <xsl:param name="section-divs"/> we externalize the actual section processing in a template named "do-section" <xsl:template name="do-section">
<xsl:param name="level" tunnel="yes">0</xsl:param>
<xsl:variable name="nextLevel" select="$level + 1"/>
<xsl:apply-templates>
<xsl:with-param name="level" select="$nextLevel" tunnel="yes"/>
</xsl:apply-templates>
</xsl:template>
which is called in the section template, while conditionally outputting the styled DIV tag: <xsl:template match="section">
<xsl:choose>
<xsl:when test="$section-divs">
<div class="section">
<xsl:call-template name="do-section"/>
</div>
</xsl:when>
<xsl:otherwise>
<xsl:call-template name="do-section"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
The HTML outputWith the parameter set to true, the HTML looks like this: <body>
<div class="section">
<h1>Section 1</h1>
<p>Paragraph</p>
<div class="section">
<h2>Sub-Section 1.1</h2>
<div class="section">
<h3>Sub-Section 1.1.1</h3>
<p>Text</p>
...
All that's left to do now is to apply some styles on for the section class and make the sub sections look the way we want. WishesWhat I would really like is to be able to turn on and off the optional behavior per page. With the sheet parameters I can only control per whole site or sections of the site. But it can work OK if the parts of the site that need the optional features are grouped and processed together in a separate section and transform. Download: article files. Read on: Generating Tables of Contents for web articles. First Posted: December 15th, 2005 - Thursday. |