- Shifted list processing elements into a separate module.
1 parent a05cd32 commit 5f9e7d0f50319316aad78b794b40e3e78dc99ad3
nstanger authored on 26 Sep 2011
Showing 2 changed files
View
500
format-master.xml
<!-- Quoted text. -->
<include href="modules/quotations.xml" />
 
 
<!-- Environments (in the LaTeX terminology): enumerated, ordered, and numbered lists. -->
<!-- Note the lack of orthgonality that means that elements other than <item> are ignored. -->
<!-- TODO: Use just xsl:apply-templates and instead of using modes, check inside the item template what the parent is? -->
 
<!-- Unordered lists -->
<template name="itemised-list" match="itemised-list|itemize|unordered-list|bulleted-list|bullet-list|bullet-points|UL|ul">
<common formats="/latex/xelatex/">
\begin{itemize}
<xsl:apply-templates select="item" mode="normal" />
\end{itemize}
</common>
<common formats="/html/xhtml/">
<ul>
<xsl:apply-templates select="item" mode="normal" />
</ul>
</common>
</template>
 
<!--
Ordered lists.
@start: The starting number for the list. [default 1]
-->
<template name="enumerated-list" match="enumerated-list|enumerate|ordered-list|numbered-list|question-list|OL|ol">
<common formats="/latex/xelatex/">
\begin{enumerate}
<xsl:if test='@start'>
<!--
Set the appropriate enum counter according to the depth. Use the format attribute of xsl:number to output it in Roman numerals. Depth must be at least 1 (enumi) and at most 4 (enumiv). Bizarrely, a count(ancestor::xxx) here gives 0 for the outermost element, whereas for section elements it gives 1?!?!
-->
<xsl:text>\setcounter{enum</xsl:text>
<xsl:number value="min( ( 1 + count( ancestor::enumerated-list|ancestor::enumerate|ancestor::ordered-list|ancestor::numbered-list|ancestor::question-list|ancestor::OL|ancestor::ol ), 4 ) )" format="i" />
<xsl:text>}{</xsl:text>
<!-- Remember that LaTeX adds 1 to the counter before using it. -->
<xsl:value-of select="@start - 1" />
<xsl:text>}</xsl:text>
</xsl:if>
<xsl:apply-templates select="item" mode="enumerated-list" />
\end{enumerate}
</common>
<common formats="/html/xhtml/">
<ol>
<xsl:if test="@start">
<!--
Note that we're using the START attribute of OL, which is actually deprecated in HTML 4 and XHTML. However, the alternative (using CSS styling) is useless, as it doesn't permit different number formatting for different levels of list (e.g., 1., a., ii., etc.). The only standards-compliant solution to this is to forgo HTML list elements completely and do it all ourselves. Ugh, no thanks!
-->
<xsl:attribute name="start">
<xsl:value-of select="@start" />
</xsl:attribute>
</xsl:if>
<xsl:apply-templates select="item" mode="enumerated-list" />
</ol>
</common>
</template>
<!-- Definition or description lists. -->
<template name="definition-list" match="definition-list|description-list|DL|dl">
<common formats="/latex/xelatex/">
\begin{description}
<xsl:apply-templates select="item" mode="definition-list" />
\end{description}
</common>
<common formats="/html/xhtml/">
<!--
<dl>s in HTML tend to come out with the spacing a bit wrong (or maybe it's just my browser?). Anyway, they don't appear to be displayed correctly. A more portable solution is to use plain <p>s with CSS margins to control the hanging indent. The tricky part is dealing with embedded <paragraph>s inside the <description-list>. The clever details are handled in the "definition-item" template.
-->
<xsl:apply-templates select="item" mode="definition-list" />
</common>
</template>
 
 
<!-- List elements -->
<template name="list-item" match="item" mode="normal">
<common formats="/latex/xelatex/"><xsl:text>\item </xsl:text><xsl:apply-templates /></common>
<common formats="/html/xhtml/">
<xsl:choose>
<!--
Check whether there are actual paragraphs or things that
should be treated like paragraphs inside the item. If so,
let them worry about inserting the <p> tags.
-->
<xsl:when test="count(paragraph|para|p|question|answer|code-block) != 0">
<li><xsl:apply-templates /></li>
</xsl:when>
<!--
Otherwise, insert <p> tags surrounding the item content
so that the item spacing looks OK.
-->
<xsl:otherwise>
<li><p><xsl:apply-templates /></p></li>
</xsl:otherwise>
</xsl:choose>
</common>
</template>
<!--
Provide the ability to set the numbering of specific items in enumerated lists. Results could be unpredictable if this is applied to an itemised list!
@value: the number to use for the next list item. [default 1]
-->
<template name="enumerated-item-value" match="item[@value]" mode="enumerated-list">
<common formats="/latex/xelatex/">
<!-- Set the appropriate enum counter. -->
<xsl:text>\setcounter{enum</xsl:text>
<xsl:number value="min( ( count( ancestor::enumerated-list|ancestor::enumerate|ancestor::ordered-list|ancestor::numbered-list|ancestor::question-list|ancestor::OL|ancestor::ol ), 4 ) )" format="i" />
<xsl:text>}{</xsl:text>
<!-- Remember that LaTeX adds 1 to the counter before using it. -->
<xsl:value-of select="@value - 1" />
<xsl:text>}</xsl:text>
<xsl:apply-templates select="." mode="normal" />
</common>
<!--
Unfortunately this can't just be a wrapper around the "normal" item template because of the nesting of attributes inside the element.
-->
<common formats="/html/xhtml/">
<xsl:choose>
<!--
Check whether there are actual paragraphs or things that
should be treated like paragraphs inside the item. If so,
let them worry about inserting the <p> tags.
-->
<xsl:when test="count(paragraph|para|p|question|answer|code-block) != 0">
<li>
<xsl:attribute name="value" select="@value" />
<xsl:apply-templates />
</li>
</xsl:when>
<!--
Otherwise, insert <p> tags surrounding the item content
so that the item spacing looks OK.
-->
<xsl:otherwise>
<li>
<xsl:attribute name="value" select="@value" />
<p><xsl:apply-templates /></p>
</li>
</xsl:otherwise>
</xsl:choose>
</common>
</template>
 
<template name="enumerated-item" match="item[not( @value )]" mode="enumerated-list">
<common>
<xsl:apply-templates select="." mode="normal" />
</common>
</template>
 
<template name="definition-item" match="item" mode="definition-list">
<common formats="/latex/xelatex/">
<xsl:text>\item[</xsl:text>
<xsl:apply-templates select="keyword|term|topic|DT|dt" />
<xsl:text>] </xsl:text>
<xsl:apply-templates select="definition|description|discourse|DD|dd" />
</common>
<common formats="/html/xhtml/">
<!--
We have to be a little clever here, because we're
transforming potentially multiple embedded elements
(embedded <paragraph>s in particular) into one or more
<p> tags in the HTML. We need to ensure that:
(a) we don't end up with nested <p> tags,
(b) all paragraphs are correctly indented, and
(c) if the first thing following the <definition>
is a <paragraph> or text node, it gets
positioned correctly relative to the <keyword>.
 
We know that the <keyword> won't have embedded
<paragraph>s (it doesn't really make sense, not that we
actually check :) The only thing we therefore need to
check for is <paragraph> elements inside the
<definition> element.
-->
<xsl:choose>
<!--
If the first sub-node of the <definition> is NOT a
<p> node, then the whole thing should be just simple
text and contain only basic formatting elements, if
anything (i.e., no lists!). We therefore just wrap
the <keyword> and <definition> within a <p> with a
hanging indent and finish. Note the use of
child::node[1|2], because we don't necessarily know
what variants of <keyword> and <definition> have
actually been used, but we know that they will
(should!) always be the first and second children of
the <item> respectively.
This probably is the most common case, so test for
it first.
-->
<xsl:when test="not(child::node()[2]/child::node()[1][self::p] or child::node()[2]/child::node()[1][self::paragraph])">
<p class="definition1">
<xsl:apply-templates select="child::node()[1]" />
<xsl:text> </xsl:text>
<xsl:apply-templates select="child::node()[2]" />
</p>
</xsl:when>
<!--
If the first sub-node of the <definition> IS a <p>
or <paragraph>, then we need to skip over the
processing of this element to avoid nested <p>s in
the output. Any remaining sub-nodes are processed
normally, except that we pass in the HTMLStyle
parameter to ensure that any remaining paragraph
elements are correctly indented. I would have used
modes for this, but it killed embedded <itemize>s,
because there isn't an <itemize> template with the
appropriate mode (nor is there a need for one). Grr.
-->
<xsl:otherwise>
<p class="definition1">
<xsl:apply-templates select="child::node()[1]" />
<xsl:text> </xsl:text>
<xsl:apply-templates select="child::node()[2]/child::node()[1]/node()" />
</p>
<xsl:apply-templates select="child::node()[2]/*[position() > 1]">
<xsl:with-param name="HTMLStyle">definition2</xsl:with-param>
</xsl:apply-templates>
</xsl:otherwise>
</xsl:choose>
</common>
</template>
<!--
Need to provide some context here as, e.g., <term> is also
a standalone element.
-->
<template name="keyword" match="item/keyword|item/term|item/topic|item/DT|item/dt">
<common formats="/latex/xelatex/"><xsl:apply-templates /></common>
<common formats="/html/xhtml/"><strong><xsl:apply-templates /></strong></common>
</template>
<!--
Need to provide some context here as, e.g., <description> is also used within <image>.
-->
<template name="definition" match="item/definition|item/description|item/discourse|item/DD|item/dd">
<common><xsl:apply-templates /></common>
</template>
<!-- Lists (itemised, enumerated, definition). -->
<include href="modules/lists.xml" />
 
 
<!--
Question text. This only exists so that we can ensure that appropriate
View
227
modules/lists.xml 0 → 100755
<?xml version="1.0" encoding="utf-8"?>
 
<!--
Environments (in the LaTeX terminology) for enumerated, ordered, and numbered lists. Note the lack of orthgonality that means that elements other than <item> inside lists are ignored.
TODO: Use just xsl:apply-templates and instead of using modes, check what the parent is inside the item template?
-->
 
<stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 
 
<!-- Unordered lists -->
<template name="itemised-list" match="itemised-list|itemize|unordered-list|bulleted-list|bullet-list|bullet-points|UL|ul">
<common formats="/latex/xelatex/">
\begin{itemize}
<xsl:apply-templates select="item" mode="normal" />
\end{itemize}
</common>
<common formats="/html/xhtml/">
<ul>
<xsl:apply-templates select="item" mode="normal" />
</ul>
</common>
</template>
 
<!--
Ordered lists.
@start: The starting number for the list. [default 1]
-->
<template name="enumerated-list" match="enumerated-list|enumerate|ordered-list|numbered-list|question-list|OL|ol">
<common formats="/latex/xelatex/">
\begin{enumerate}
<xsl:if test='@start'>
<!--
Set the appropriate enum counter according to the depth. Use the format attribute of xsl:number to output it in Roman numerals. Depth must be at least 1 (enumi) and at most 4 (enumiv). Bizarrely, a count(ancestor::xxx) here gives 0 for the outermost element, whereas for section elements it gives 1?!?!
-->
<xsl:text>\setcounter{enum</xsl:text>
<xsl:number value="min( ( 1 + count( ancestor::enumerated-list|ancestor::enumerate|ancestor::ordered-list|ancestor::numbered-list|ancestor::question-list|ancestor::OL|ancestor::ol ), 4 ) )" format="i" />
<xsl:text>}{</xsl:text>
<!-- Remember that LaTeX adds 1 to the counter before using it. -->
<xsl:value-of select="@start - 1" />
<xsl:text>}</xsl:text>
</xsl:if>
<xsl:apply-templates select="item" mode="enumerated-list" />
\end{enumerate}
</common>
<common formats="/html/xhtml/">
<ol>
<xsl:if test="@start">
<!--
Note that we're using the START attribute of OL, which is actually deprecated in HTML 4 and XHTML. However, the alternative (using CSS styling) is useless, as it doesn't permit different number formatting for different levels of list (e.g., 1., a., ii., etc.). The only standards-compliant solution to this is to forgo HTML list elements completely and do it all ourselves. Ugh, no thanks!
-->
<xsl:attribute name="start">
<xsl:value-of select="@start" />
</xsl:attribute>
</xsl:if>
<xsl:apply-templates select="item" mode="enumerated-list" />
</ol>
</common>
</template>
<!-- Definition or description lists. -->
<template name="definition-list" match="definition-list|description-list|DL|dl">
<common formats="/latex/xelatex/">
\begin{description}
<xsl:apply-templates select="item" mode="definition-list" />
\end{description}
</common>
<common formats="/html/xhtml/">
<!--
<dl>s in HTML tend to come out with the spacing a bit wrong (or maybe it's just my browser?). Anyway, they don't appear to be displayed correctly. A more portable solution is to use plain <p>s with CSS margins to control the hanging indent. The tricky part is dealing with embedded <paragraph>s inside the <description-list>. The clever details are handled in the "definition-item" template.
-->
<xsl:apply-templates select="item" mode="definition-list" />
</common>
</template>
 
 
<!-- List items for non-definition lists. -->
<template name="list-item" match="item" mode="normal">
<common formats="/latex/xelatex/"><xsl:text>\item </xsl:text><xsl:apply-templates /></common>
<common formats="/html/xhtml/">
<xsl:choose>
<!--
Check whether there are actual paragraphs or things that should be treated like paragraphs inside the item. If so, let them worry about inserting the <p> tags.
-->
<xsl:when test="count(paragraph|para|p|question|answer|code-block) != 0">
<li><xsl:apply-templates /></li>
</xsl:when>
<!--
Otherwise, insert <p> tags surrounding the item content so that the item spacing looks OK.
-->
<xsl:otherwise>
<li><p><xsl:apply-templates /></p></li>
</xsl:otherwise>
</xsl:choose>
</common>
</template>
<!--
Provide the ability to set the numbering of specific items in enumerated lists. Results could be unpredictable if this is applied to an itemised list!
@value: the number to use for the next list item. [default 1]
-->
<template name="enumerated-item-value" match="item[@value]" mode="enumerated-list">
<common formats="/latex/xelatex/">
<!-- Set the appropriate enum counter. -->
<xsl:text>\setcounter{enum</xsl:text>
<xsl:number value="min( ( count( ancestor::enumerated-list|ancestor::enumerate|ancestor::ordered-list|ancestor::numbered-list|ancestor::question-list|ancestor::OL|ancestor::ol ), 4 ) )" format="i" />
<xsl:text>}{</xsl:text>
<!-- Remember that LaTeX adds 1 to the counter before using it. -->
<xsl:value-of select="@value - 1" />
<xsl:text>}</xsl:text>
<xsl:apply-templates select="." mode="normal" />
</common>
<!--
Unfortunately this can't just be a wrapper around the "normal" item template because of the nesting of attributes inside the element.
-->
<common formats="/html/xhtml/">
<xsl:choose>
<!--
Check whether there are actual paragraphs or things that
should be treated like paragraphs inside the item. If so,
let them worry about inserting the <p> tags.
-->
<xsl:when test="count(paragraph|para|p|question|answer|code-block) != 0">
<li>
<xsl:attribute name="value" select="@value" />
<xsl:apply-templates />
</li>
</xsl:when>
<!--
Otherwise, insert <p> tags surrounding the item content
so that the item spacing looks OK.
-->
<xsl:otherwise>
<li>
<xsl:attribute name="value" select="@value" />
<p><xsl:apply-templates /></p>
</li>
</xsl:otherwise>
</xsl:choose>
</common>
</template>
<!-- Normally numbered enumerated item. -->
<template name="enumerated-item" match="item[not( @value )]" mode="enumerated-list">
<common>
<xsl:apply-templates select="." mode="normal" />
</common>
</template>
 
<!-- List items for definition lists. -->
<template name="definition-item" match="item" mode="definition-list">
<common formats="/latex/xelatex/">
<xsl:text>\item[</xsl:text>
<xsl:apply-templates select="keyword|term|topic|DT|dt" />
<xsl:text>] </xsl:text>
<xsl:apply-templates select="definition|description|discourse|DD|dd" />
</common>
<common formats="/html/xhtml/">
<!--
We have to be a little clever here, because we're transforming potentially multiple embedded elements (embedded <paragraph>s in particular) into one or more <p> tags in the HTML. We need to ensure that:
(a) we don't end up with nested <p> tags,
(b) all paragraphs are correctly indented, and
(c) if the first thing following the <definition> is a <paragraph> or text node, it gets positioned correctly relative to the <keyword>.
 
We know that the <keyword> won't have embedded <paragraph>s (it doesn't really make sense, not that we actually check :). The only thing we therefore need to check for is <paragraph> elements inside the <definition> element.
-->
<xsl:choose>
<!--
If the first sub-node of the <definition> is NOT a <p> node, then the whole thing should be just simple text and contain only basic formatting elements, if anything (i.e., no lists!). We therefore just wrap the <keyword> and <definition> within a <p> with a hanging indent and finish. Note the use of child::node[1|2], because we don't necessarily know what variants of <keyword> and <definition> have actually been used, but we know that they will (should!) always be the first and second children of the <item> respectively.
This probably is the most common case, so test for it first.
-->
<xsl:when test="not(child::node()[2]/child::node()[1][self::p] or child::node()[2]/child::node()[1][self::paragraph])">
<p class="definition1">
<xsl:apply-templates select="child::node()[1]" />
<xsl:text> </xsl:text>
<xsl:apply-templates select="child::node()[2]" />
</p>
</xsl:when>
<!--
If the first sub-node of the <definition> IS a <p> or <paragraph>, then we need to skip over the processing of this element to avoid nested <p>s in the output. Any remaining sub-nodes are processed normally, except that we pass in the HTMLStyle parameter to ensure that any remaining paragraph elements are correctly indented. I would have used modes for this, but it killed embedded <itemize>s, because there isn't an <itemize> template with the appropriate mode (nor is there a need for one). Grr.
-->
<xsl:otherwise>
<p class="definition1">
<xsl:apply-templates select="child::node()[1]" />
<xsl:text> </xsl:text>
<xsl:apply-templates select="child::node()[2]/child::node()[1]/node()" />
</p>
<xsl:apply-templates select="child::node()[2]/*[position() > 1]">
<xsl:with-param name="HTMLStyle">definition2</xsl:with-param>
</xsl:apply-templates>
</xsl:otherwise>
</xsl:choose>
</common>
</template>
<!--
Need to provide some context here as, e.g., <term> is also a standalone element.
-->
<template name="keyword" match="item/keyword|item/term|item/topic|item/DT|item/dt">
<common formats="/latex/xelatex/"><xsl:apply-templates /></common>
<common formats="/html/xhtml/"><strong><xsl:apply-templates /></strong></common>
</template>
<!--
Need to provide some context here as, e.g., <description> is also used within <image>.
-->
<template name="definition" match="item/definition|item/description|item/discourse|item/DD|item/dd">
<common><xsl:apply-templates /></common>
</template>
 
 
</stylesheet>