<?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>