<?xml version="1.0" encoding="utf-8"?> <!-- tex2mn 0.5.0 - converts Metanorma documents from LaTeX to AsciiDoc Copyright (C) 2019-2020 Ribose Inc. <open.source@ribose.com> This project is available under the terms of the MIT License. --> <xsl:stylesheet version = "1.0" xmlns:xsl = "http://www.w3.org/1999/XSL/Transform" xmlns:ltx = "http://dlmf.nist.gov/LaTeXML" xmlns:str = "http://exslt.org/strings" extension-element-prefixes = "str" exclude-result-prefixes = "ltx str"> <xsl:output method="text" omit-xml-declaration="yes" indent="no"/> <xsl:strip-space elements="*" /> <!-- NOTE: these are tags which are either matched explicitly or ignored --> <xsl:template match="ltx:tags|ltx:title|ltx:toctitle|ltx:rdf"/> <!-- <xsl:template match="@*|node()"> <xsl:copy><xsl:apply-templates select="@*|node()"/></xsl:copy> </xsl:template> --> <!-- NOTE: it's apparently forbidden (by latexmlpost) to use a variable in a predicate --> <xsl:template match="ltx:section[translate(ltx:title/text(), 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz')='foreword' or ltx:rdf[@property='mn:attributes']/text()='heading=foreword']"> <xsl:text>[[Foreword]]
</xsl:text> <xsl:value-of select="concat('.', ltx:title/text(), '
')"/> <xsl:apply-templates/> </xsl:template> <xsl:template name="term-extras"> <xsl:for-each select="tokenize(@alternate, ',')"> <xsl:value-of select="concat('alternate:[', ., ']')"/> <xsl:call-template name="newline"/> </xsl:for-each> <xsl:for-each select="tokenize(@deprecated, ',')"> <xsl:value-of select="concat('deprecated:[', ., ']')"/> <xsl:call-template name="newline"/> </xsl:for-each> <xsl:if test="@domain"> <xsl:value-of select="concat('domain:[', @domain, ']')"/> <xsl:call-template name="newline"/> </xsl:if> </xsl:template> <xsl:template name="newline"> <xsl:text>
</xsl:text> </xsl:template> <!-- Document root --> <xsl:template match="/"> <xsl:call-template name="document-title"/> <xsl:call-template name="document-attributes"/> <xsl:apply-templates/> </xsl:template> <!-- Document title --> <xsl:template name="document-title"> <xsl:if test="ltx:document/ltx:title"> <xsl:value-of select="concat('= ', ltx:document/ltx:title, '
')"/> </xsl:if> </xsl:template> <!-- Document attributes --> <xsl:template name="document-attributes"> <xsl:for-each select="ltx:document/ltx:rdf"> <xsl:if test="@content"> <xsl:value-of select="concat(':', @property, ': ', @content, '
')"/> </xsl:if> <xsl:if test="not(@content)"> <xsl:value-of select="concat(':', @property, ':
')"/> </xsl:if> </xsl:for-each> <xsl:if test="ltx:document/ltx:rdf"> <xsl:call-template name="newline"/> </xsl:if> </xsl:template> <xsl:template match="ltx:text[@content]"> <xsl:value-of select="concat('{', @content, '}')"/> </xsl:template> <xsl:template match="ltx:text[@class='with-mn-attributes']"> <xsl:value-of select="concat('[', ltx:rdf[@property='mn:attributes']/text(), ']#')"/> <xsl:apply-templates/> <xsl:text>#</xsl:text> </xsl:template> <!-- Sectioning --> <xsl:template name="heading"> <xsl:param name="depth"/> <xsl:param name="extra"/> <!-- optional label --> <xsl:if test="@labels"> <!-- NOTE: latexml lists and prefixes labels as "LABEL:lab1 LABEL:lab2" so we take the first one and drop the prefix --> <xsl:value-of select="concat('[[', substring-after(substring-before(concat(@labels, ' '), ' '), ':'), ']]
')"/> </xsl:if> <!-- optional attributes tag --> <xsl:choose> <xsl:when test="ltx:rdf[@property='mn:attributes'] and $extra"> <xsl:value-of select="concat('[', $extra, ',', ltx:rdf[@property='mn:attributes']/text(), ']')"/> <xsl:call-template name="newline"/> </xsl:when> <xsl:when test="ltx:rdf[@property='mn:attributes'] or $extra"> <xsl:value-of select="concat('[', $extra, ltx:rdf[@property='mn:attributes']/text(), ']')"/> <xsl:call-template name="newline"/> </xsl:when> </xsl:choose> <!-- heading command --> <xsl:choose> <xsl:when test="ltx:title/text()!=''"> <xsl:value-of select="concat($depth, ' ', ltx:title/text())"/> </xsl:when> <xsl:otherwise> <xsl:value-of select="concat($depth, ' ', '{blank}')"/> </xsl:otherwise> </xsl:choose> <xsl:call-template name="newline"/> <!-- blank line --> <xsl:call-template name="newline"/> <!-- contents --> <xsl:apply-templates/> </xsl:template> <xsl:template match="ltx:appendix"> <xsl:call-template name="heading"> <xsl:with-param name="depth" select="'=='" /> <xsl:with-param name="extra" select="'appendix'" /> </xsl:call-template> </xsl:template> <xsl:template match="ltx:section"> <xsl:call-template name="heading"> <xsl:with-param name="depth" select="'=='" /> </xsl:call-template> </xsl:template> <xsl:template match="ltx:subsection"> <xsl:call-template name="heading"> <xsl:with-param name="depth" select="'==='" /> </xsl:call-template> </xsl:template> <xsl:template match="ltx:subsubsection"> <xsl:call-template name="heading"> <xsl:with-param name="depth" select="'===='" /> </xsl:call-template> </xsl:template> <xsl:template match="ltx:paragraph"> <xsl:call-template name="heading"> <xsl:with-param name="depth" select="'====='" /> </xsl:call-template> </xsl:template> <xsl:template match="ltx:subparagraph"> <xsl:call-template name="heading"> <xsl:with-param name="depth" select="'======'" /> </xsl:call-template> </xsl:template> <!-- Text formatting --> <xsl:template match="ltx:text[@font='bold']">**<xsl:apply-templates/>**</xsl:template> <xsl:template match="ltx:text[@font='italic']">__<xsl:apply-templates/>__</xsl:template> <xsl:template match="ltx:text[@font='typewriter']">``<xsl:apply-templates/>``</xsl:template> <xsl:template match="ltx:text[@font='smallcaps']">[smallcap]#<xsl:apply-templates/>#</xsl:template> <xsl:template match="ltx:text[@class='strikethrough']">[strike]#<xsl:apply-templates/>#</xsl:template> <xsl:template match="ltx:sup">^<xsl:apply-templates/>^</xsl:template> <xsl:template match="ltx:sub">~<xsl:apply-templates/>~</xsl:template> <!-- Paragraphs and their alignment --> <xsl:template name="paragraph-alignment"> <xsl:if test="../@align"> <!-- NOTE: parent is expected to be ltx:para --> <xsl:value-of select="concat('[align=', ../@align, ']')"/> <xsl:call-template name="newline"/> </xsl:if> </xsl:template> <xsl:template match="ltx:para"> <xsl:apply-templates/> <xsl:call-template name="newline"/> </xsl:template> <xsl:template match="ltx:p"> <xsl:call-template name="paragraph-alignment"/> <xsl:apply-templates/> <xsl:call-template name="newline"/> <!-- this is the trailing newline of the last line --> <xsl:if test="current()[following-sibling::*]"> <xsl:call-template name="newline"/> </xsl:if> </xsl:template> <!-- Quotes --> <xsl:template name="quote-attributes"> <xsl:text>[quote</xsl:text> <xsl:if test="ltx:rdf[@property='mn:attributes']"> <xsl:value-of select="concat(',', ltx:rdf[@property='mn:attributes']/text())"/> </xsl:if> <xsl:text>]
</xsl:text> </xsl:template> <xsl:template name="quote-delimiter"> <xsl:text>_____
</xsl:text> </xsl:template> <!-- <xsl:template match="ltx:quote"> --> <xsl:template match="ltx:*[@class='block-quote']" priority="1"> <xsl:call-template name="quote-attributes"/> <xsl:call-template name="quote-delimiter"/> <xsl:apply-templates/><xsl:if test="name()='p'"><xsl:text>
</xsl:text></xsl:if> <xsl:call-template name="quote-delimiter"/> <!-- TODO: should a blank line be here? --> </xsl:template> <!-- Admonitions --> <xsl:template name="block-admonition__attributes"> <xsl:value-of select="concat('[', translate(substring(@class, 19), $lowercase, $uppercase))"/> <xsl:if test="ltx:rdf[@property='mn:attributes']"> <xsl:value-of select="concat(',', ltx:rdf[@property='mn:attributes']/text())"/> </xsl:if> <xsl:text>]
</xsl:text> </xsl:template> <xsl:template name="block-admonition__delimiter"> <xsl:text>====
</xsl:text> </xsl:template> <xsl:template match="//ltx:*[starts-with(@class, 'block-admonition--')]"> <xsl:call-template name="block-admonition__attributes"/> <xsl:call-template name="block-admonition__delimiter"/> <xsl:apply-templates/><xsl:if test="name()='p'"><xsl:text>
</xsl:text></xsl:if> <xsl:call-template name="block-admonition__delimiter"/> </xsl:template> <!-- Footnotes --> <xsl:template match="ltx:note"> <xsl:value-of select="concat(' footnote:[', text(), ']')"/> </xsl:template> <!-- Hard line breaks (in paragraphs) --> <xsl:template match="ltx:p/ltx:break"> <xsl:text> +
</xsl:text> </xsl:template> <!-- Lists (arbitrarily nested, w/ line breaks and paragraphs) --> <xsl:template name="list__continuation_marker"> <xsl:text>+
</xsl:text> </xsl:template> <xsl:template name="list__item_label_marker"> <xsl:if test="../@labels"> <!-- NOTE: latexml lists and prefixes labels as "LABEL:lab1 LABEL:lab2" so we take the first one and drop the prefix --> <xsl:value-of select="concat('[[', substring-after(substring-before(concat(../@labels, ' '), ' '), ':'), ']] ')"/> </xsl:if> </xsl:template> <xsl:template match="ltx:item/ltx:para/ltx:p"> <xsl:apply-templates/> <xsl:call-template name="newline"/> <!-- this is the trailing newline of the last line --> </xsl:template> <!-- Unordered lists --> <xsl:template name="list--unordered__item_depth_marker"> <xsl:for-each select="ancestor-or-self::ltx:itemize">*</xsl:for-each> <xsl:text> </xsl:text> </xsl:template> <xsl:template match="ltx:itemize/ltx:item/ltx:para[not(preceding-sibling::ltx:para)]"> <xsl:call-template name="list--unordered__item_depth_marker"/> <xsl:call-template name="list__item_label_marker"/> <xsl:apply-templates/> </xsl:template> <xsl:template match="ltx:itemize/ltx:item/ltx:para[preceding-sibling::ltx:para]"> <xsl:call-template name="list__continuation_marker"/> <xsl:call-template name="list__item_label_marker"/> <xsl:apply-templates/> </xsl:template> <!-- Ordered lists --> <xsl:template name="list--ordered__item_depth_marker"> <xsl:for-each select="ancestor-or-self::ltx:enumerate">.</xsl:for-each> <xsl:text> </xsl:text> </xsl:template> <xsl:template match="ltx:enumerate/ltx:item/ltx:para[not(preceding-sibling::ltx:para)]"> <xsl:call-template name="list--ordered__item_depth_marker"/> <xsl:call-template name="list__item_label_marker"/> <xsl:apply-templates/> </xsl:template> <xsl:template match="ltx:enumerate/ltx:item/ltx:para[preceding-sibling::ltx:para]"> <xsl:call-template name="list__continuation_marker"/> <xsl:call-template name="list__item_label_marker"/> <xsl:apply-templates/> </xsl:template> <!-- Description lists --> <xsl:template match="ltx:description"> <xsl:for-each select="ltx:item"> <xsl:apply-templates select="ltx:tags/ltx:tag[not(@role)]"/> <xsl:text>:</xsl:text> <xsl:for-each select="ancestor-or-self::ltx:description">:</xsl:for-each> <xsl:text>
</xsl:text> <xsl:apply-templates/> </xsl:for-each> </xsl:template> <xsl:template match="ltx:description/ltx:item/ltx:para[not(preceding-sibling::ltx:para)]"> <xsl:apply-templates/> </xsl:template> <xsl:template match="ltx:description/ltx:item/ltx:para[preceding-sibling::ltx:para]"> <xsl:call-template name="list__continuation_marker"/> <xsl:apply-templates/> </xsl:template> <!-- Figures --> <xsl:template name="figure__label"> <xsl:if test="@labels"> <!-- NOTE: latexml lists and prefixes labels as "LABEL:lab1 LABEL:lab2" so we take the first one and drop the prefix --> <xsl:value-of select="concat('[[', substring-after(substring-before(concat(@labels, ' '), ' '), ':'), ']]
')"/> </xsl:if> <xsl:if test="not(@labels)"> <!-- TODO: drop this unless it's required by asciidoc --> <xsl:value-of select="concat('[[', @xml:id, ']]
')"/> </xsl:if> </xsl:template> <!-- NOTE: this matches only parent of composite figures --> <xsl:template match="ltx:figure[./ltx:figure]"> <xsl:call-template name="figure__label"/> <xsl:apply-templates select="ltx:caption"/> <xsl:call-template name="figure__attributes"/> <xsl:text>====
</xsl:text> <xsl:apply-templates select="ltx:figure"/> <xsl:text>====
</xsl:text> <xsl:call-template name="newline"/> <xsl:apply-templates select="ltx:paragraph"/> </xsl:template> <!-- NOTE: this matches either simple figures or children of composite figures --> <xsl:template match="ltx:figure[not(./ltx:figure)]"> <xsl:call-template name="figure__label"/> <xsl:apply-templates select="ltx:caption"/> <xsl:call-template name="figure__attributes"/> <xsl:apply-templates select="ltx:graphics"/> <xsl:apply-templates select="ltx:verbatim"/> <!-- NOTE: this is temporary --> <xsl:call-template name="newline"/> <xsl:if test="./ltx:description"> <xsl:text>*Key*
</xsl:text> <xsl:call-template name="newline"/> <xsl:apply-templates select="./ltx:description"/> <xsl:call-template name="newline"/> </xsl:if> </xsl:template> <xsl:template match="ltx:figure/ltx:graphics"> <!-- TODO: we could use the caption as alt text, perhaps? --> <xsl:value-of select="concat('image::', @graphic, '[]
')"/> </xsl:template> <xsl:template name="figure__attributes"> <xsl:if test="ltx:rdf[@property='mn:attributes']"> <xsl:value-of select="concat('[', ltx:rdf[@property='mn:attributes']/text(), ']
')"/> </xsl:if> </xsl:template> <xsl:template match="ltx:figure/ltx:caption/ltx:tag"/> <!-- NOTE: is it correct to assume there's only one ltx:tex inside the caption? --> <xsl:template match="ltx:figure/ltx:caption/ltx:text"> <xsl:value-of select="concat('.', text(), '
')"/> </xsl:template> <!-- Math --> <xsl:template match="ltx:equation"> <xsl:if test="@labels"> <!-- NOTE: latexml lists and prefixes labels as "LABEL:lab1 LABEL:lab2" so we take the first one and drop the prefix --> <xsl:value-of select="concat('[[', substring-after(substring-before(concat(@labels, ' '), ' '), ':'), ']]
')"/> </xsl:if> <!-- TODO: should distinction between environments be stricter? --> <!-- equation, gather --> <xsl:apply-templates select="ltx:Math"/> <!-- align --> <xsl:apply-templates select="ltx:MathFork/ltx:Math"/> <xsl:call-template name="newline"/> </xsl:template> <xsl:template match="ltx:Math[@mode='inline']"> <xsl:value-of select="concat('stem:[', @tex, ']')"/> </xsl:template> <xsl:template match="ltx:Math[not(@mode) or @mode='display']"> <xsl:text>[stem]
</xsl:text> <xsl:text>++++
</xsl:text> <xsl:value-of select="@tex"/> <xsl:text>
++++
</xsl:text> </xsl:template> <!-- Tables --> <xsl:template match="ltx:table"> <xsl:if test="@labels"> <!-- NOTE: latexml lists and prefixes labels as "LABEL:lab1 LABEL:lab2" so we take the first one and drop the prefix --> <xsl:value-of select="concat('[[', substring-after(substring-before(concat(@labels, ' '), ' '), ':'), ']]
')"/> </xsl:if> <xsl:apply-templates select="ltx:caption"/> <xsl:apply-templates select="ltx:tabular"/> <xsl:call-template name="newline"/> </xsl:template> <xsl:template match="ltx:table/ltx:caption/ltx:tag"/> <!-- NOTE: is it correct to assume there's only one ltx:tex inside the caption? --> <xsl:template match="ltx:table/ltx:caption/ltx:text"> <xsl:value-of select="concat('.', text(), '
')"/> </xsl:template> <xsl:template match="ltx:tabular"> <xsl:value-of select="concat('[cols=', count(ltx:tbody/ltx:tr[1]/ltx:td), '*]
')"/> <xsl:apply-templates/> </xsl:template> <xsl:template match="ltx:tbody"> <xsl:text>|===
</xsl:text> <xsl:apply-templates/> <xsl:text>|===
</xsl:text> </xsl:template> <xsl:template match="ltx:tr"> <xsl:apply-templates/> <xsl:if test="current()[following-sibling::*]"> <xsl:call-template name="newline"/> </xsl:if> </xsl:template> <xsl:template match="ltx:td"> <xsl:text>| </xsl:text> <xsl:apply-templates/> <xsl:text>
</xsl:text> </xsl:template> <!-- Links --> <xsl:template match="ltx:ref[@href]"> <!-- NOTE: to handle *anything* a user might throw at us, we use the explicit link macro --> <xsl:choose> <xsl:when test="@href!=node()"> <xsl:value-of select="concat('link:++', @href, '++', '[', node(), ']')"/> </xsl:when> <xsl:otherwise> <xsl:value-of select="concat('link:++', @href, '++', '[]')"/> </xsl:otherwise> </xsl:choose> </xsl:template> <!-- Cross references --> <xsl:template match="ltx:ref[@labelref]"> <xsl:choose> <!-- NOTE: by default (disabled with nocrossref) latexmk would add a child text node containing @labelref so we couldn't choose here --> <xsl:when test="node()"> <xsl:value-of select="concat('<<', substring-after(@labelref, ':'), ', ', text(), '>>')"/> </xsl:when> <xsl:otherwise> <xsl:value-of select="concat('<<', substring-after(@labelref, ':'), '>>')"/> </xsl:otherwise> </xsl:choose> </xsl:template> <!-- Reviewer notes --> <xsl:template match="ltx:*[@class='block-sidebar']" priority="1"> <xsl:call-template name="block-sidebar__attributes"/> <xsl:call-template name="block-sidebar__delimiter"/> <xsl:apply-templates/> <xsl:call-template name="block-sidebar__delimiter"/> <xsl:if test="current()[following-sibling::*]"> <xsl:call-template name="newline"/> </xsl:if> </xsl:template> <xsl:template name="block-sidebar__attributes"> <xsl:if test="ltx:rdf[@property='mn:attributes']"> <xsl:value-of select="concat('[', ltx:rdf[@property='mn:attributes']/text(), ']
')"/> </xsl:if> </xsl:template> <xsl:template name="block-sidebar__delimiter"> <!-- TODO: should we handle block nesting? --> <xsl:text>****
</xsl:text> </xsl:template> <!-- Blocks --> <!-- NOTE: we expect to match only p, block and inline-block but use priority to simplify the XSL --> <xsl:template match="ltx:*[starts-with(@class, 'block-example--')]" priority="1"> <xsl:value-of select="concat('[.', substring-after(@class, 'block-example--'), ']
')"/> <xsl:call-template name="block--example__delimiter"/> <!-- NOTE: if we matched a p we need an extra line termination --> <xsl:apply-templates/><xsl:if test="name()='p'"><xsl:text>
</xsl:text></xsl:if> <xsl:call-template name="block--example__delimiter"/> <xsl:if test="current()[following-sibling::*]"> <xsl:call-template name="newline"/> </xsl:if> </xsl:template> <xsl:template name="block--example__delimiter"> <!-- NOTE: we add a = for each nesting level --> <xsl:for-each select="ancestor::ltx:*[starts-with(@class, 'block-example--')]">=</xsl:for-each> <xsl:text>====
</xsl:text> </xsl:template> <!-- NOTE: we expect to match only p, block and inline-block but use priority to simplify the XSL --> <xsl:template match="ltx:*[starts-with(@class, 'block-open--')]" priority="1"> <xsl:value-of select="concat('[.', substring-after(@class, 'block-open--'), ']
')"/> <xsl:call-template name="block--open__delimiter"/> <xsl:apply-templates/> <xsl:text>
</xsl:text> <xsl:call-template name="block--open__delimiter"/> <xsl:if test="current()[following-sibling::*]"> <xsl:call-template name="newline"/> </xsl:if> </xsl:template> <xsl:template name="block--open__delimiter"> <xsl:text>--
</xsl:text> </xsl:template> <!-- Verbatim --> <!-- NOTE: this is temporary, undocumented and we'll end up using lstlistings in the final version --> <xsl:template match="ltx:verbatim"> <xsl:text>....</xsl:text> <xsl:apply-templates/> <xsl:text>....
</xsl:text> <xsl:if test="current()[following-sibling::*]"> <xsl:call-template name="newline"/> </xsl:if> </xsl:template> <!-- Terms and Definitions --> <xsl:template match="ltx:*[@class='block-example']" priority="1"> <xsl:text>[example]
</xsl:text> <xsl:call-template name="block--example__delimiter"/> <!-- NOTE: if we matched a p we need an extra line termination --> <xsl:apply-templates/><xsl:if test="name()='p'"><xsl:text>
</xsl:text></xsl:if> <xsl:call-template name="block--example__delimiter"/> <xsl:if test="current()[following-sibling::*]"> <xsl:call-template name="newline"/> </xsl:if> </xsl:template> <xsl:template match="ltx:para[@class='source']"> <xsl:text>[.source]
</xsl:text> <xsl:apply-templates/> <xsl:call-template name="newline"/> </xsl:template> <xsl:template match="ltx:rdf[@property='alt' or @property='deprecated' or @property='domain']"> <xsl:value-of select="concat(@property, ':[')"/> <xsl:apply-templates/> <xsl:text>]
</xsl:text> <xsl:if test="current()[not(following-sibling::ltx:rdf)]"> <xsl:call-template name="newline"/> </xsl:if> </xsl:template> <!-- Citations --> <xsl:template match="ltx:cite"> <xsl:text><<</xsl:text> <xsl:value-of select="ltx:bibref/@bibrefs"/> <xsl:if test="./following-sibling::ltx:rdf[@property='mn:attributes']/text()"> <xsl:value-of select="concat(',', ./following-sibling::ltx:rdf[@property='mn:attributes'])"/> </xsl:if> <xsl:text>>></xsl:text> </xsl:template> <!-- Bibliography --> <xsl:template match="ltx:bibliography/ltx:title"> <xsl:text>[bibliography]
</xsl:text> <xsl:value-of select="concat('== ', ., '
')"/> <xsl:call-template name="newline"/> </xsl:template> <!-- NOTE: this matches embedded bibliographies written by the user --> <xsl:template match="ltx:bibliography[not(@files)]/ltx:biblist"> <xsl:for-each select="ltx:bibitem"> <xsl:text>* </xsl:text> <!-- NOTE: remember that position() should be equivalent to refnum if no label is given --> <xsl:value-of select="concat('[[[', @key, ',', ./ltx:tags/ltx:tag[@role='refnum'], ']]]')"/> <!-- NOTE: embedded bibliographic entries produce one bibblock each --> <xsl:apply-templates match="ltx:bibblock"/> <xsl:text>
</xsl:text> <!-- <xsl:if test="string-length(substring(node(), 1, 1))!='
'"><xsl:text>
</xsl:text></xsl:if> --> </xsl:for-each> <xsl:call-template name="newline"/> </xsl:template> <!-- NOTE: this matches BibTeX bibliographies generated by the MakeBibliography preprocessor --> <xsl:template match="ltx:bibliography[@files]/ltx:biblist"> <xsl:for-each select="ltx:bibitem"> <xsl:text>* </xsl:text> <!-- NOTE: remember that position() should be equivalent to refnum if no label is given --> <xsl:value-of select="concat('[[[', @key, ',', ./ltx:tags/ltx:tag[@role='refnum'], ']]]', '
')"/> <!-- NOTE: [not(contains(@class, 'ltx_bib_cited'))] skips the "Cited by" block which we aren't handling --> <xsl:for-each select="ltx:bibblock[not(contains(@class, 'ltx_bib_cited'))]"> <!-- NOTE: instead of handling whitespace through concatenation we just break the line --> <!-- NOTE: this intercepts blocks beginning with an initial (e.g. "A. Einstein") and prepends a {blank} to avoid generating a spurious list --> <xsl:if test="string-length(substring-before(node(), '. '))=1"><xsl:text>{blank}</xsl:text></xsl:if> <xsl:apply-templates/> <xsl:text>
</xsl:text> </xsl:for-each> <xsl:text>
</xsl:text> </xsl:for-each> </xsl:template> <!-- Utilities --> <!-- XSL 2.0 has upper-case() but we must use translate() with XSL 1.0 --> <xsl:variable name="lowercase" select="'abcdefghijklmnopqrstuvwxyz'" /> <xsl:variable name="uppercase" select="'ABCDEFGHIJKLMNOPQRSTUVWXYZ'" /> </xsl:stylesheet>