--- /dev/null
+<?xml version='1.0' encoding='UTF-8' ?>
+<!--
+ Nick's web site: Creative Commons license reformatter.
+
+ This tool processes the "official" Creative Commons license documents, some
+ of which come in a real messy SGML format, and converts them to usable XHTML.
+
+ Note that some of the source documents have tons of missing closing tags
+ so they will not parse correctly as XML. The sgml2xml filter is intended to
+ fix this.
+
+ Copyright © 2018 Nick Bowler
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <https://www.gnu.org/licenses/>
+-->
+<xsl:stylesheet version='1.0'
+ xmlns='http://www.w3.org/1999/xhtml'
+ xmlns:xhtml='http://www.w3.org/1999/xhtml'
+ xmlns:xsl='http://www.w3.org/1999/XSL/Transform'
+ xmlns:func='http://exslt.org/functions'
+ xmlns:f='http://draconx.ca/my-functions'
+ extension-element-prefixes='func f'
+ exclude-result-prefixes='xhtml'>
+
+<xsl:strip-space elements='*' />
+<xsl:output method='xml' encoding='UTF-8' omit-xml-declaration='yes' indent='yes' />
+
+<xsl:template match='node()|@*'>
+ <xsl:copy><xsl:apply-templates select='node()|@*' /></xsl:copy>
+</xsl:template>
+
+<!-- identity rule to patch up namespace -->
+<xsl:template name='fixup-node' match='*'>
+ <xsl:element name='{local-name(.)}' namespace='http://www.w3.org/1999/xhtml'>
+ <xsl:apply-templates select='node()|@*' />
+ </xsl:element>
+</xsl:template>
+
+<xsl:template match='node()'>
+ <xsl:param name='list-label' />
+
+ <xsl:if test='$list-label'>
+ <span><xsl:value-of select='$list-label' /> </span>
+ </xsl:if>
+
+ <xsl:choose>
+ <xsl:when test='self::text()'>
+ <xsl:copy />
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:call-template name='fixup-node' />
+ </xsl:otherwise>
+ </xsl:choose>
+</xsl:template>
+
+<xsl:template match='p'>
+ <xsl:param name='list-label' />
+
+ <p>
+ <xsl:apply-templates select='@*' />
+ <xsl:if test='$list-label'>
+ <span><xsl:value-of select='$list-label' /> </span>
+ </xsl:if>
+ <xsl:apply-templates select='node()' />
+ </p>
+</xsl:template>
+
+<xsl:template match='span[@style]'>
+ <xsl:param name='list-label' />
+
+ <xsl:if test='$list-label'>
+ <span><xsl:value-of select='$list-label' /> </span>
+ </xsl:if>
+
+ <em><xsl:apply-templates select='node()' /></em>
+</xsl:template>
+
+<!-- Older XHTML editions have title in h2 outside of deed-main-content -->
+<xsl:template mode='toplevel' match='xhtml:h2'>
+ <h1><xsl:apply-templates select='node()|@*' /></h1>
+</xsl:template>
+
+<xsl:template match='h3'>
+ <h1><xsl:apply-templates select='node()|@*' /></h1>
+</xsl:template>
+
+<xsl:template name='cc-section-heading'>
+ <xsl:param name='heading' select='strong[1]|xhtml:strong[1]' />
+ <xsl:choose>
+ <xsl:when test='substring($heading, string-length($heading))="."'>
+ <xsl:value-of
+ select='substring($heading, 1, string-length($heading)-1)' />
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select='$heading' />
+ </xsl:otherwise>
+ </xsl:choose>
+</xsl:template>
+
+<xsl:template match='p[starts-with(strong, "Section")]'>
+ <h2>
+ <xsl:apply-templates select='@*' />
+ <xsl:call-template name='cc-section-heading' />
+ </h2>
+</xsl:template>
+
+<xsl:template match='xhtml:h3[xhtml:em[1]]'>
+ <h2>
+ <xsl:value-of select='.' />
+ </h2>
+</xsl:template>
+
+<xsl:template match='xhtml:p[xhtml:strong[1]]'>
+ <xsl:variable name='heading' select='xhtml:strong[1]' />
+ <xsl:variable name='section-num'
+ select='number(substring-before($heading, "."))' />
+
+ <h2>
+ <xsl:if test='$section-num'>
+ <xsl:attribute name='id'>
+ <xsl:value-of select='concat("s", $section-num)' />
+ </xsl:attribute>
+ </xsl:if>
+ <xsl:call-template name='cc-section-heading' />
+ </h2>
+ <p>
+ <xsl:apply-templates select='@*|node()[position()>1]' />
+ </p>
+</xsl:template>
+
+<xsl:template match='a[normalize-space(text())=
+ "creativecommons.org/compatiblelicenses"]'>
+ <a href='https://{normalize-space(text())}'>
+ <xsl:apply-templates select='@*[local-name(.)!="href"]' />
+ <xsl:text>https://​</xsl:text>
+ <xsl:text>creative­commons.org/​</xsl:text>
+ <xsl:text>compatible­licenses</xsl:text>
+ </a>
+</xsl:template>
+
+<xsl:template match='div'>
+ <xsl:apply-templates select='node()' />
+</xsl:template>
+
+<xsl:template name='list-number'>
+ <xsl:param name='type' select='substring(concat(../@type,"1"),1,1)' />
+ <xsl:param name='start' select='(text()[normalize-space(.)] | *)[1]' />
+ <xsl:param name='count' select='count(node())' />
+
+ <xsl:apply-templates select='$start'>
+ <xsl:with-param name='list-label'>
+ <xsl:number value='position()' format='{$type}.' />
+ </xsl:with-param>
+ </xsl:apply-templates>
+ <xsl:apply-templates
+ select='$start/following-sibling::node()[$count>position()]' />
+</xsl:template>
+
+<xsl:template match='ol/li|xhtml:ol/xhtml:li'>
+ <xsl:variable name='first' select='(text()[normalize-space(.)] | *)[1]' />
+ <xsl:variable name='firstblock' select='*[f:node-is-block(.)]' />
+
+ <li>
+ <xsl:apply-templates select='@*' />
+ <xsl:choose>
+ <xsl:when test='$first/self::p'>
+ <xsl:call-template name='list-number' />
+ </xsl:when>
+ <xsl:when test='$firstblock' xml:space='preserve'>
+ <p>
+ <xsl:call-template name='list-number' xml:space='default'>
+ <xsl:with-param name='count'
+ select='count($first/following-sibling::*[f:node-is-span(.)])+1' />
+ </xsl:call-template>
+ </p>
+ <xsl:apply-templates
+ select='$firstblock|$firstblock/following-sibling::node()' />
+ </xsl:when>
+ <xsl:otherwise xml:space='preserve'>
+ <p>
+ <xsl:call-template name='list-number' xml:space='default' />
+ </p>
+ </xsl:otherwise>
+ </xsl:choose>
+ </li>
+</xsl:template>
+
+<xsl:template match='ol|xhtml:ol'>
+ <xsl:variable name='type' select='@type' />
+
+ <ul class='ordered'>
+ <xsl:apply-templates select='li | xhtml:li
+ | following-sibling::*[1][self::ol and @start]/li' />
+ </ul>
+</xsl:template>
+<xsl:template match='ol[@start]' />
+
+<!-- Definitions -->
+<!--
+<xsl:template match='ol[starts-with(preceding-sibling::p[1], "Section 1")]'>
+ <dl class='terms'>
+ <xsl:for-each select='li'>
+ <dt><xsl:value-of select='node()[1]' /></dt>
+ <dd><p><xsl:apply-templates select='node()[position()>1]' /></p></dd>
+ </xsl:for-each>
+ </dl>
+</xsl:template>
+-->
+
+<xsl:template match='node()[following-sibling::h3]' />
+<xsl:template match='node()[preceding-sibling::p[@class="shaded"]]' />
+<xsl:template match='node()[@class="shaded"]' />
+<xsl:template match='node()[following-sibling::xhtml:h3]' />
+<xsl:template match='xhtml:blockquote' />
+
+<xsl:template mode='toplevel' match='text()|@*' />
+<xsl:template mode='toplevel' match='*[@id="deed-main-content"]/node()'>
+ <xsl:apply-templates select='.' />
+</xsl:template>
+
+<func:function name='f:node-is-block'>
+ <xsl:param name='node' select='.' />
+ <xsl:variable name='tag' select='local-name($node)' />
+
+ <!-- XXX incomplete -->
+ <func:result select='starts-with($tag, "h") or $tag="div" or $tag="p"
+ or $tag="ul" or $tag="ol" or $tag="blockquote"' />
+</func:function>
+
+<func:function name='f:node-is-span'>
+ <xsl:param name='node' select='.' />
+
+ <xsl:choose>
+ <xsl:when test='$node/self::text()'>
+ <func:result select='normalize-space($node)' />
+ </xsl:when>
+ <xsl:otherwise>
+ <func:result select='not(f:node-is-block($node))' />
+ </xsl:otherwise>
+ </xsl:choose>
+</func:function>
+
+<func:function name='f:consecutive-spans'>
+ <xsl:param name='start' select='.' />
+ <xsl:param name='next' select='$start/following-sibling::node()[1]' />
+
+ <xsl:choose>
+ <xsl:when test='f:node-is-span($start)'>
+ <func:result select='$start | f:consecutive-spans($next)' />
+ </xsl:when>
+ <xsl:otherwise>
+ <func:result select='/..' />
+ </xsl:otherwise>
+ </xsl:choose>
+</func:function>
+
+<xsl:template mode='toplevel' match='*[@id="deed-main-content"]/node()[f:node-is-span(.)]'>
+ <xsl:variable name='prev' select='preceding-sibling::node()[1]' />
+
+ <xsl:if test='not(f:node-is-span($prev) or self::img)'>
+ <p>
+ <xsl:apply-templates select='f:consecutive-spans(.)' />
+ </p>
+ </xsl:if>
+</xsl:template>
+
+<xsl:template match='/'>
+ <xsl:apply-templates mode='toplevel' select='*' />
+</xsl:template>
+
+</xsl:stylesheet>