1 <?xml version='1.0' encoding='UTF-8' ?>
3 Nick's web site: Creative Commons license reformatter.
5 This tool processes the "official" Creative Commons license documents, some
6 of which come in a real messy SGML format, and converts them to usable XHTML.
8 Note that some of the source documents have tons of missing closing tags
9 so they will not parse correctly as XML. The sgml2xml filter is intended to
12 Copyright © 2018-2019 Nick Bowler
14 This program is free software: you can redistribute it and/or modify
15 it under the terms of the GNU General Public License as published by
16 the Free Software Foundation, either version 3 of the License, or
17 (at your option) any later version.
19 This program is distributed in the hope that it will be useful,
20 but WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 GNU General Public License for more details.
24 You should have received a copy of the GNU General Public License
25 along with this program. If not, see <https://www.gnu.org/licenses/>
27 <xsl:stylesheet version='1.0'
28 xmlns='http://www.w3.org/1999/xhtml'
29 xmlns:xhtml='http://www.w3.org/1999/xhtml'
30 xmlns:xsl='http://www.w3.org/1999/XSL/Transform'
31 xmlns:func='http://exslt.org/functions'
32 xmlns:f='http://draconx.ca/my-functions'
33 extension-element-prefixes='func f'
34 exclude-result-prefixes='xhtml'>
36 <xsl:strip-space elements='*' />
37 <xsl:output method='xml' encoding='UTF-8' omit-xml-declaration='yes' indent='yes' />
39 <xsl:template match='node()|@*'>
40 <xsl:copy><xsl:apply-templates select='node()|@*' /></xsl:copy>
43 <!-- identity rule to patch up namespace -->
44 <xsl:template name='fixup-node' match='*'>
45 <xsl:element name='{local-name(.)}' namespace='http://www.w3.org/1999/xhtml'>
46 <xsl:apply-templates select='node()|@*' />
50 <xsl:template match='node()'>
51 <xsl:param name='list-label' />
53 <xsl:if test='$list-label'>
54 <span><xsl:value-of select='$list-label' /> </span>
58 <xsl:when test='self::text()'>
62 <xsl:call-template name='fixup-node' />
67 <xsl:template match='p'>
68 <xsl:param name='list-label' />
71 <xsl:apply-templates select='@*' />
72 <xsl:if test='$list-label'>
73 <span><xsl:value-of select='$list-label' /> </span>
75 <xsl:apply-templates select='node()' />
79 <xsl:template match='span[@style]'>
80 <xsl:param name='list-label' />
82 <xsl:if test='$list-label'>
83 <span><xsl:value-of select='$list-label' /> </span>
86 <em><xsl:apply-templates select='node()' /></em>
89 <!-- Older XHTML editions have title in h2 outside of deed-main-content -->
90 <xsl:template mode='toplevel' match='xhtml:h2'>
91 <h1><xsl:apply-templates select='node()|@*' /></h1>
94 <xsl:template match='h3'>
95 <h1><xsl:apply-templates select='node()|@*' /></h1>
98 <xsl:template name='cc-section-heading'>
99 <xsl:param name='heading' select='strong[1]|xhtml:strong[1]' />
101 <xsl:when test='substring($heading, string-length($heading))="."'>
103 select='substring($heading, 1, string-length($heading)-1)' />
106 <xsl:value-of select='$heading' />
111 <xsl:template match='p[starts-with(strong, "Section")]'>
113 <xsl:apply-templates select='@*' />
114 <xsl:call-template name='cc-section-heading' />
118 <xsl:template match='xhtml:h3[xhtml:em[1]]'>
120 <xsl:value-of select='.' />
124 <xsl:template match='xhtml:p[xhtml:strong[1]]'>
125 <xsl:variable name='heading' select='xhtml:strong[1]' />
126 <xsl:variable name='section-num'
127 select='number(substring-before($heading, "."))' />
130 <xsl:if test='$section-num'>
131 <xsl:attribute name='id'>
132 <xsl:value-of select='concat("s", $section-num)' />
135 <xsl:call-template name='cc-section-heading' />
138 <xsl:apply-templates select='@*|node()[position()>1]' />
142 <xsl:template match='a[normalize-space(text())=
143 "creativecommons.org/compatiblelicenses"]'>
144 <a href='https://{normalize-space(text())}'>
145 <xsl:apply-templates select='@*[local-name(.)!="href"]' />
146 <xsl:text>https://​</xsl:text>
147 <xsl:text>creative­commons.org/​</xsl:text>
148 <xsl:text>compatible­licenses</xsl:text>
152 <xsl:template match='div'>
153 <xsl:apply-templates select='node()' />
156 <xsl:template name='list-number'>
157 <xsl:param name='type' select='substring(concat(../@type,"1"),1,1)' />
158 <xsl:param name='start' select='(text()[normalize-space(.)] | *)[1]' />
159 <xsl:param name='count' select='count(node())' />
161 <xsl:apply-templates select='$start'>
162 <xsl:with-param name='list-label'>
163 <xsl:number value='position()' format='{$type}.' />
165 </xsl:apply-templates>
167 select='$start/following-sibling::node()[$count>position()]' />
170 <xsl:template match='ol/li|xhtml:ol/xhtml:li'>
171 <xsl:variable name='first' select='(text()[normalize-space(.)] | *)[1]' />
172 <xsl:variable name='firstblock' select='*[f:node-is-block(.)]' />
175 <xsl:apply-templates select='@*' />
177 <xsl:when test='$first/self::p'>
178 <xsl:call-template name='list-number' />
180 <xsl:when test='$firstblock' xml:space='preserve'>
182 <xsl:call-template name='list-number' xml:space='default'>
183 <xsl:with-param name='count'
184 select='count($first/following-sibling::*[f:node-is-span(.)])+1' />
188 select='$firstblock|$firstblock/following-sibling::node()' />
190 <xsl:otherwise xml:space='preserve'>
192 <xsl:call-template name='list-number' xml:space='default' />
199 <xsl:template match='ol|xhtml:ol'>
200 <xsl:variable name='type' select='@type' />
203 <xsl:apply-templates select='li | xhtml:li
204 | following-sibling::*[1][self::ol and @start]/li' />
207 <xsl:template match='ol[@start]' />
209 <xsl:template match='node()[following-sibling::h3]' />
210 <xsl:template match='node()[preceding-sibling::p[@class="shaded"]]' />
211 <xsl:template match='node()[@class="shaded"]' />
212 <xsl:template match='node()[following-sibling::xhtml:h3]' />
213 <xsl:template match='xhtml:blockquote' />
215 <xsl:template mode='toplevel' match='text()|@*' />
216 <xsl:template mode='toplevel' match='*[@id="deed-main-content"]/node()'>
217 <xsl:apply-templates select='.' />
220 <func:function name='f:node-is-block'>
221 <xsl:param name='node' select='.' />
222 <xsl:variable name='tag' select='local-name($node)' />
224 <!-- XXX incomplete -->
225 <func:result select='starts-with($tag, "h") or $tag="div" or $tag="p"
226 or $tag="ul" or $tag="ol" or $tag="blockquote"' />
229 <func:function name='f:node-is-span'>
230 <xsl:param name='node' select='.' />
233 <xsl:when test='$node/self::text()'>
234 <func:result select='normalize-space($node)' />
237 <func:result select='not(f:node-is-block($node))' />
242 <func:function name='f:consecutive-spans'>
243 <xsl:param name='start' select='.' />
244 <xsl:param name='next' select='$start/following-sibling::node()[1]' />
247 <xsl:when test='f:node-is-span($start)'>
248 <func:result select='$start | f:consecutive-spans($next)' />
251 <func:result select='/..' />
256 <xsl:template mode='toplevel' match='*[@id="deed-main-content"]/node()[f:node-is-span(.)]'>
257 <xsl:variable name='prev' select='preceding-sibling::node()[1]' />
259 <xsl:if test='not(f:node-is-span($prev) or self::img)'>
261 <xsl:apply-templates select='f:consecutive-spans(.)' />
266 <xsl:template match='/'>
267 <xsl:apply-templates mode='toplevel' select='*' />