Newer
Older
XML / modules / sectioning.xml
<?xml version="1.0" encoding="utf-8"?>

<!--
	Generate appropriately numbered and labelled section titles.
-->

<stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform">


	<!--
		Sections, subsections, subsubsections, ...
		
		@label: A label that can be used for cross referencing. Any value can be used, as long as it's a legal identifier in both LaTeX and HTML.
		
		@number: Whether or not to generate a section number. It makes the most logical sense for this attribute to be associated with the section element, but the section numbers are actually generated in the "section-title" template (see below). Consequently, this attribute isn't even mentioned in this template.
			'yes'	[default]
			'no'
	-->
	<template name="section" match="section">
		<common formats="/latex/xelatex/">
			<xsl:apply-templates>
				<xsl:with-param name="label">
					<xsl:value-of select="@label" />
					<xsl:if test="not( @label )">THERE_IS_NO_LABEL</xsl:if>
				</xsl:with-param>
			</xsl:apply-templates>
		</common>
		<common formats="/html/xhtml/">
			<xsl:if test="@label"><a id="{@label}"></a></xsl:if>
			<xsl:apply-templates />
		</common>
	</template>
	

	<!--
		Utility template to generate some number of "sub"s so we can produce, e.g., "subsubsection" for LaTeX.
		
		$depth: the number of repetitions (0 to 2). If zero, then the loop never executes.
	-->
	<template name="generate-subs">
		<common formats="/latex/xelatex/">
			<xsl:param name="depth">0</xsl:param>
			<xsl:for-each select="1 to $depth">
				<xsl:text>sub</xsl:text>
			</xsl:for-each>
		</common>
	</template>
	
	
	<!--
		Generate a section title with correctly nested numbering, e.g., 1.1.3. If we were being pedantic, this should probably go in titling.xml, but I think it makes more sense here.
	-->
	<template name="section-title" match="section/title">
		<common formats="/latex/xelatex/">
			<xsl:param name="label" />
			<!--
				Calculate the nesting depth up front, so that we can limit it to 2 for LaTeX. Note that we have to skip counting the parent <section> element, as that's the section currently being processed. Including it would produce a minimum depth of 1, but the minimum depth in LaTeX is actually 0.
			-->
			<xsl:variable name="depth">
				<xsl:number value="min( ( count( ../ancestor::section ), 2 ) )" />
			</xsl:variable>
			<xsl:text>\</xsl:text>
			<!-- Generate the correct number of "sub"s for LaTeX. -->
			<xsl:call-template name="generate-subs">
				<xsl:with-param name="depth" select="$depth" />
			</xsl:call-template>
			<xsl:text>section</xsl:text>
			<!--
				Unnumbered section. We reference the @number attribute of the parent <section> element. (We are guaranteed that the parent is a <section> element by the match context for this template.)
			-->
			<xsl:if test="../@number = ('no', 'n', 'false', 'f', '0')">
				<xsl:text>*</xsl:text>
			</xsl:if>
			<xsl:text>{</xsl:text>
			<xsl:apply-templates /><xsl:text>}</xsl:text>
			<xsl:if test="$label ne 'THERE_IS_NO_LABEL'">
				\label{<xsl:value-of select="$label" />}
			</xsl:if>
		</common>
		<common formats="/html/xhtml/">
			<!--
				Calculate the nesting depth up front, so that we can limit it to 6 for HTML. Add 1 because <h1> is reserved for the main document title; section headings start at <h2>.
			-->
			<xsl:variable name="depth">
				<xsl:number value="min( ( 1 + count( ancestor::section ), 6 ) )" />
			</xsl:variable>
			<!--
				Generate the correct level of <Hn> element based on the value of $depth. Note the use of an attribute value template to force XSLT to interpret the contents of the name attribute as a function call rather than as the element name.
			-->
			<xsl:element name="{concat( 'h', $depth )}">
				<!--
					Unnumbered section, as per above. Note that the sense of the test is reversed: with LaTeX we output _additional_ text to get an unnumbered section, where as with HTML, we _suppress_ the additional text (i.e., the section number, which is generated here). We also only count sections that _are_ numbered.
				-->
				<xsl:if test="not(../@number) or (../@number ne 'no')">
					<xsl:number count="section[not(@number) or (@number ne 'no')]" level="multiple" format="1.1.1.1.1.1" />
					<xsl:text> </xsl:text>
				</xsl:if>
				<xsl:apply-templates />
			</xsl:element>
		</common>
	</template>
	
	
</stylesheet>