@pretextbook/pretext-html 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +42 -3
- package/assets/preview-html.xsl +230 -230
- package/assets/upstream.json +7 -7
- package/assets/xsl/README.md +0 -0
- package/assets/xsl/entities.ent +154 -154
- package/assets/xsl/extract-asymptote.xsl +68 -68
- package/assets/xsl/extract-biblio-csl.xsl +327 -327
- package/assets/xsl/extract-datafile.xsl +71 -71
- package/assets/xsl/extract-dynamic.xsl +139 -139
- package/assets/xsl/extract-identity.xsl +136 -136
- package/assets/xsl/extract-interactive.xsl +81 -81
- package/assets/xsl/extract-latex-image.xsl +118 -118
- package/assets/xsl/extract-mermaid.xsl +58 -58
- package/assets/xsl/extract-mom.xsl +63 -63
- package/assets/xsl/extract-pg.xsl +2897 -2897
- package/assets/xsl/extract-prefigure.xsl +157 -157
- package/assets/xsl/extract-qrcode.xsl +100 -100
- package/assets/xsl/extract-runestone-page-template.xsl +139 -139
- package/assets/xsl/extract-sageplot.xsl +166 -166
- package/assets/xsl/extract-stack.xsl +56 -56
- package/assets/xsl/extract-trace.xsl +134 -134
- package/assets/xsl/extract-youtube.xsl +63 -63
- package/assets/xsl/html-symbols.xsl +3344 -3344
- package/assets/xsl/latex/pretext-latex-AIM.xsl +56 -56
- package/assets/xsl/latex/pretext-latex-CLP.xsl +148 -148
- package/assets/xsl/latex/pretext-latex-chaos.xsl +317 -317
- package/assets/xsl/latex/pretext-latex-dyslexic-font.xsl +76 -76
- package/assets/xsl/latex/pretext-latex-guide.xsl +104 -104
- package/assets/xsl/latex/pretext-latex-texstyle.xsl +862 -862
- package/assets/xsl/localizations/README.md +0 -0
- package/assets/xsl/localizations/af-ZA.xml +276 -276
- package/assets/xsl/localizations/bg-BG.xml +276 -276
- package/assets/xsl/localizations/ca-ES.xml +285 -285
- package/assets/xsl/localizations/cs-CZ.xml +280 -280
- package/assets/xsl/localizations/de-DE.xml +281 -281
- package/assets/xsl/localizations/en-US.xml +427 -427
- package/assets/xsl/localizations/es-ES.xml +287 -287
- package/assets/xsl/localizations/fi-FI.xml +275 -275
- package/assets/xsl/localizations/fr-CA.xml +276 -276
- package/assets/xsl/localizations/fr-FR.xml +280 -280
- package/assets/xsl/localizations/hu-HU.xml +280 -280
- package/assets/xsl/localizations/it-IT.xml +276 -276
- package/assets/xsl/localizations/ku-CKB.xml +275 -275
- package/assets/xsl/localizations/localizations.xml +48 -48
- package/assets/xsl/localizations/nl-NL.xml +275 -275
- package/assets/xsl/localizations/pt-BR.xml +288 -288
- package/assets/xsl/localizations/pt-PT.xml +292 -292
- package/assets/xsl/localizations/zh-HANS.xml +269 -269
- package/assets/xsl/pretext-assembly.xsl +4795 -4795
- package/assets/xsl/pretext-basic-html.xsl +86 -86
- package/assets/xsl/pretext-beamer.xsl +662 -662
- package/assets/xsl/pretext-braille-preprint.xsl +2249 -2249
- package/assets/xsl/pretext-common.xsl +12018 -12018
- package/assets/xsl/pretext-dynamic.xsl +65 -65
- package/assets/xsl/pretext-epub.xsl +1483 -1483
- package/assets/xsl/pretext-fo.xsl +4593 -4593
- package/assets/xsl/pretext-html.xsl +14791 -14791
- package/assets/xsl/pretext-json-manifest.xsl +150 -150
- package/assets/xsl/pretext-jupyter.xsl +868 -868
- package/assets/xsl/pretext-latex-classic.xsl +952 -952
- package/assets/xsl/pretext-latex-common.xsl +11563 -11563
- package/assets/xsl/pretext-latex.xsl +47 -47
- package/assets/xsl/pretext-litprog.xsl +105 -105
- package/assets/xsl/pretext-merge.xsl +41 -41
- package/assets/xsl/pretext-numbers.xsl +875 -875
- package/assets/xsl/pretext-revealjs.xsl +522 -522
- package/assets/xsl/pretext-runestone-fitb.xsl +1233 -1233
- package/assets/xsl/pretext-runestone-static.xsl +1438 -1438
- package/assets/xsl/pretext-runestone.xsl +3083 -3083
- package/assets/xsl/pretext-sage-doctest.xsl +289 -289
- package/assets/xsl/pretext-smc.xsl +492 -492
- package/assets/xsl/pretext-solution-manual-latex.xsl +323 -323
- package/assets/xsl/pretext-text-utilities.xsl +1217 -1217
- package/assets/xsl/pretext-text.xsl +392 -392
- package/assets/xsl/pretext-units.xsl +195 -195
- package/assets/xsl/pretext-view-source.xsl +157 -157
- package/assets/xsl/pretext-ww-problem-sets.xsl +391 -391
- package/assets/xsl/publisher-variables.xsl +4756 -4756
- package/assets/xsl/support/README.md +0 -0
- package/assets/xsl/support/extract-math.xsl +256 -256
- package/assets/xsl/support/package-math.xsl +141 -141
- package/assets/xsl/support/play-button/README.md +0 -0
- package/assets/xsl/support/play-button/play-button.png +0 -0
- package/assets/xsl/support/play-button/play-button.svg +3 -3
- package/assets/xsl/support/pretext-pg-macros.xsl +110 -110
- package/assets/xsl/support/webpack_static_imports.xml +14 -14
- package/assets/xsl/tests/README.md +0 -0
- package/assets/xsl/tests/null.xml +3 -3
- package/assets/xsl/tests/pretext-text-utilities-test.xsl +333 -333
- package/assets/xsl/utilities/README.md +0 -0
- package/assets/xsl/utilities/author-report.xsl +107 -107
- package/assets/xsl/utilities/deprecate-autoname.sed +18 -18
- package/assets/xsl/utilities/deprecate-index.sed +33 -33
- package/assets/xsl/utilities/fix-deprecations.xsl +663 -663
- package/assets/xsl/utilities/pretext-enhanced-source.xsl +112 -112
- package/assets/xsl/utilities/report-publisher-variables.xsl +162 -162
- package/assets/xsl/xml-to-json.xsl +326 -326
- package/assets/xsl/xml-to-string.xsl +328 -328
- package/dist/{cli-C6tfAVvi.js → cli-BQizBK0N.js} +74 -72
- package/dist/cli.d.ts +0 -0
- package/dist/cli.js +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.js +12 -6
- package/dist/mounts.d.ts +0 -0
- package/dist/publication.d.ts +0 -0
- package/dist/renderer.d.ts +10 -0
- package/dist/sourcemap.d.ts +0 -0
- package/dist/theme.d.ts +68 -0
- package/dist/theme.js +93 -0
- package/dist/xinclude.d.ts +0 -0
- package/package.json +14 -2
|
@@ -1,1217 +1,1217 @@
|
|
|
1
|
-
<?xml version='1.0'?>
|
|
2
|
-
|
|
3
|
-
<!--********************************************************************
|
|
4
|
-
Copyright 2022 Robert A. Beezer
|
|
5
|
-
|
|
6
|
-
This file is part of PreTeXt.
|
|
7
|
-
|
|
8
|
-
PreTeXt is free software: you can redistribute it and/or modify
|
|
9
|
-
it under the terms of the GNU General Public License as published by
|
|
10
|
-
the Free Software Foundation, either version 2 or version 3 of the
|
|
11
|
-
License (at your option).
|
|
12
|
-
|
|
13
|
-
PreTeXt is distributed in the hope that it will be useful,
|
|
14
|
-
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
15
|
-
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
16
|
-
GNU General Public License for more details.
|
|
17
|
-
|
|
18
|
-
You should have received a copy of the GNU General Public License
|
|
19
|
-
along with PreTeXt. If not, see <http://www.gnu.org/licenses/>.
|
|
20
|
-
*********************************************************************-->
|
|
21
|
-
|
|
22
|
-
<!-- Indicated basic utilities are from: -->
|
|
23
|
-
<!-- XSLT Cookbook, 2nd Edition -->
|
|
24
|
-
<!-- Copyright 2006, O'Reilly Media, Inc. -->
|
|
25
|
-
<!-- -->
|
|
26
|
-
<!-- From the section of the Preface, "Using Code Examples": -->
|
|
27
|
-
<!-- "You do not need to contact us for permission unless -->
|
|
28
|
-
<!-- you're reproducing a significant portion of the code. -->
|
|
29
|
-
<!-- For example, writing a program that uses several chunks -->
|
|
30
|
-
<!-- of code from this book does not require permission." -->
|
|
31
|
-
|
|
32
|
-
<!-- This stylesheet is meant to xsl:include'd into other stylesheets. -->
|
|
33
|
-
<!-- All the templates were once part of "pretext-common.xsl" (2022-03-27) -->
|
|
34
|
-
<!-- and so are being included at the point where the vast majority were -->
|
|
35
|
-
<!-- originally created. Perhaps the include can move to a more obvious -->
|
|
36
|
-
<!-- location near the top of that file. There is no entry template and -->
|
|
37
|
-
<!-- every template is a named template which relies on parameters, not -->
|
|
38
|
-
<!-- context or a match/select mechanism. (With some exceptions.) -->
|
|
39
|
-
<!-- -->
|
|
40
|
-
<!-- Used in: -->
|
|
41
|
-
<!-- xsl/pretext-common.xsl (2022-03-27) -->
|
|
42
|
-
<!-- xsl/pretext/pretext-runestone-static.xsl (2022-03-28) -->
|
|
43
|
-
|
|
44
|
-
<!-- "unit" tests for these templates are (partially) implemented in -->
|
|
45
|
-
<!-- xsl/tests/pretext-text-utilities-test.xsl -->
|
|
46
|
-
<!-- Before modifying any templates in this file, you are encouraged to -->
|
|
47
|
-
<!-- make sure there is a set of tests for the template(s) and use those -->
|
|
48
|
-
<!-- to verify changes allong with diffs of sample-book/sample-article -->
|
|
49
|
-
|
|
50
|
-
<!-- There are &LOWERCASE; and &UPPERCASE; entities -->
|
|
51
|
-
<!-- in the "file-extension" template (only?) -->
|
|
52
|
-
<!DOCTYPE xsl:stylesheet [
|
|
53
|
-
<!ENTITY % entities SYSTEM "entities.ent">
|
|
54
|
-
%entities;
|
|
55
|
-
]>
|
|
56
|
-
|
|
57
|
-
<!-- EXSL needed for token list template (only?) -->
|
|
58
|
-
<xsl:stylesheet
|
|
59
|
-
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"
|
|
60
|
-
xmlns:xml="http://www.w3.org/XML/1998/namespace"
|
|
61
|
-
xmlns:pi="http://pretextbook.org/2020/pretext/internal"
|
|
62
|
-
xmlns:str="http://exslt.org/strings"
|
|
63
|
-
xmlns:exsl="http://exslt.org/common"
|
|
64
|
-
xmlns:math="http://exslt.org/math"
|
|
65
|
-
xmlns:set="http://exslt.org/sets"
|
|
66
|
-
extension-element-prefixes="pi str math"
|
|
67
|
-
>
|
|
68
|
-
|
|
69
|
-
<!-- Allow serialization of XML in various contexts -->
|
|
70
|
-
<!-- See the XSL file for more info about Lenz' utility -->
|
|
71
|
-
<xsl:import href="./xml-to-string.xsl"/>
|
|
72
|
-
|
|
73
|
-
<!-- ########################## -->
|
|
74
|
-
<!-- Text Manipulation Routines -->
|
|
75
|
-
<!-- ########################## -->
|
|
76
|
-
|
|
77
|
-
<!-- Various bits of textual material -->
|
|
78
|
-
<!-- (eg Sage, code, verbatim, LaTeX) -->
|
|
79
|
-
<!-- require manipulation to -->
|
|
80
|
-
<!-- -->
|
|
81
|
-
<!-- (a) behave in some output format -->
|
|
82
|
-
<!-- (b) produce human-readable output (LaTeX) -->
|
|
83
|
-
|
|
84
|
-
<!-- We need to identify particular characters -->
|
|
85
|
-
<!-- space, tab, carriage return, newline -->
|
|
86
|
-
<xsl:variable name="whitespaces">
|
|
87
|
-
<xsl:text> 	
</xsl:text>
|
|
88
|
-
</xsl:variable>
|
|
89
|
-
|
|
90
|
-
<!-- Sanitize Code -->
|
|
91
|
-
<!-- No leading whitespace, no trailing -->
|
|
92
|
-
<!-- http://stackoverflow.com/questions/1134318/xslt-xslstrip-space-does-not-work -->
|
|
93
|
-
<!-- Trim all whitespace at end of code hunk -->
|
|
94
|
-
<!-- Append carriage return to mark last line, remove later -->
|
|
95
|
-
<!-- preserve-intentional keeps all whitespace that comes -->
|
|
96
|
-
<!-- before the last newline -->
|
|
97
|
-
<xsl:template name="trim-end">
|
|
98
|
-
<xsl:param name="text"/>
|
|
99
|
-
<xsl:param name="preserve-intentional" select="false()" />
|
|
100
|
-
<xsl:variable name="last-char" select="substring($text, string-length($text), 1)" />
|
|
101
|
-
<xsl:choose>
|
|
102
|
-
<xsl:when test="$last-char=''">
|
|
103
|
-
<xsl:text>
</xsl:text>
|
|
104
|
-
</xsl:when>
|
|
105
|
-
<xsl:when test="($preserve-intentional = true()) and ($last-char = '
')">
|
|
106
|
-
<xsl:value-of select="$text"/>
|
|
107
|
-
</xsl:when>
|
|
108
|
-
<xsl:when test="contains($whitespaces, $last-char)">
|
|
109
|
-
<xsl:call-template name="trim-end">
|
|
110
|
-
<xsl:with-param name="text" select="substring($text, 1, string-length($text) - 1)" />
|
|
111
|
-
<xsl:with-param name="preserve-intentional" select="$preserve-intentional" />
|
|
112
|
-
</xsl:call-template>
|
|
113
|
-
</xsl:when>
|
|
114
|
-
<xsl:otherwise>
|
|
115
|
-
<xsl:value-of select="$text" />
|
|
116
|
-
<xsl:text>
</xsl:text>
|
|
117
|
-
</xsl:otherwise>
|
|
118
|
-
</xsl:choose>
|
|
119
|
-
</xsl:template>
|
|
120
|
-
|
|
121
|
-
<!-- Trim all totally whitespace lines from beginning of code hunk -->
|
|
122
|
-
<!-- preserve-intentional removes all whitespace through first -->
|
|
123
|
-
<!-- newline (inclusive) and preserves the rest. -->
|
|
124
|
-
<xsl:template name="trim-start-lines">
|
|
125
|
-
<xsl:param name="text"/>
|
|
126
|
-
<xsl:param name="pad" select="''"/>
|
|
127
|
-
<xsl:param name="preserve-intentional" select="false()" />
|
|
128
|
-
<xsl:variable name="first-char" select="substring($text, 1, 1)" />
|
|
129
|
-
<xsl:choose>
|
|
130
|
-
<!-- Possibly nothing, return just final carriage return -->
|
|
131
|
-
<xsl:when test="$first-char=''">
|
|
132
|
-
<xsl:text>
</xsl:text>
|
|
133
|
-
</xsl:when>
|
|
134
|
-
<xsl:when test="$first-char='
'">
|
|
135
|
-
<xsl:choose>
|
|
136
|
-
<xsl:when test="$preserve-intentional=true()">
|
|
137
|
-
<xsl:value-of select="substring($text, 2)" />
|
|
138
|
-
</xsl:when>
|
|
139
|
-
<xsl:otherwise>
|
|
140
|
-
<xsl:call-template name="trim-start-lines">
|
|
141
|
-
<xsl:with-param name="text" select="substring($text, 2)" />
|
|
142
|
-
</xsl:call-template>
|
|
143
|
-
</xsl:otherwise>
|
|
144
|
-
</xsl:choose>
|
|
145
|
-
</xsl:when>
|
|
146
|
-
<xsl:when test="contains($whitespaces, $first-char)">
|
|
147
|
-
<xsl:call-template name="trim-start-lines">
|
|
148
|
-
<xsl:with-param name="text" select="substring($text, 2)" />
|
|
149
|
-
<xsl:with-param name="pad" select="concat($pad, $first-char)" />
|
|
150
|
-
<xsl:with-param name="preserve-intentional" select="$preserve-intentional" />
|
|
151
|
-
</xsl:call-template>
|
|
152
|
-
</xsl:when>
|
|
153
|
-
<xsl:otherwise>
|
|
154
|
-
<xsl:value-of select="concat($pad, $text)" />
|
|
155
|
-
</xsl:otherwise>
|
|
156
|
-
</xsl:choose>
|
|
157
|
-
</xsl:template>
|
|
158
|
-
|
|
159
|
-
<!-- Compute length of indentation of first line -->
|
|
160
|
-
<!-- Assumes no leading blank lines -->
|
|
161
|
-
<xsl:template name="count-pad-length">
|
|
162
|
-
<xsl:param name="text"/>
|
|
163
|
-
<xsl:param name="index" select="1"/>
|
|
164
|
-
<xsl:variable name="first-char" select="substring($text, $index, 1)" />
|
|
165
|
-
<xsl:choose>
|
|
166
|
-
<!-- reached end of string or newline... bail out -->
|
|
167
|
-
<xsl:when test="$first-char = '' or $first-char = '
'">
|
|
168
|
-
<xsl:value-of select="$index - 1"/>
|
|
169
|
-
</xsl:when>
|
|
170
|
-
<xsl:when test="contains($whitespaces, $first-char)">
|
|
171
|
-
<xsl:call-template name="count-pad-length">
|
|
172
|
-
<xsl:with-param name="text" select="$text" />
|
|
173
|
-
<xsl:with-param name="index" select="$index + 1" />
|
|
174
|
-
</xsl:call-template>
|
|
175
|
-
</xsl:when>
|
|
176
|
-
<xsl:otherwise>
|
|
177
|
-
<xsl:value-of select="$index - 1" />
|
|
178
|
-
</xsl:otherwise>
|
|
179
|
-
</xsl:choose>
|
|
180
|
-
</xsl:template>
|
|
181
|
-
|
|
182
|
-
<!-- Compute width of left margin -->
|
|
183
|
-
<!-- Assumes each line ends in a newline -->
|
|
184
|
-
<!-- A blank line will not contribute -->
|
|
185
|
-
<!-- Intentionally non-recursive to avoid recursion depth issues -->
|
|
186
|
-
<!-- on long code samples -->
|
|
187
|
-
<xsl:template name="left-margin">
|
|
188
|
-
<xsl:param name="text" />
|
|
189
|
-
|
|
190
|
-
<!-- construct a variable that is just a list of padding counts -->
|
|
191
|
-
<!-- as pad nodes -->
|
|
192
|
-
<xsl:variable name="lines" select="str:tokenize($text, '
')" />
|
|
193
|
-
<xsl:variable name="pad-counts-rtf">
|
|
194
|
-
<xsl:for-each select="$lines">
|
|
195
|
-
<!-- str:tokenize in current implementation does not produce -->
|
|
196
|
-
<!-- zero-length strings. (e.g. string between two newlines) -->
|
|
197
|
-
<!-- but that appears to differ between implementations, so -->
|
|
198
|
-
<!-- guard against it -->
|
|
199
|
-
<xsl:if test=". != ''">
|
|
200
|
-
<pad>
|
|
201
|
-
<xsl:call-template name="count-pad-length">
|
|
202
|
-
<xsl:with-param name="text" select="." />
|
|
203
|
-
</xsl:call-template>
|
|
204
|
-
</pad>
|
|
205
|
-
</xsl:if>
|
|
206
|
-
</xsl:for-each>
|
|
207
|
-
</xsl:variable>
|
|
208
|
-
<xsl:variable name="pad-counts" select="exsl:node-set($pad-counts-rtf)"/>
|
|
209
|
-
|
|
210
|
-
<!-- grab minimum value from list-->
|
|
211
|
-
<xsl:variable name="min-pad" select="math:min($pad-counts/pad)" />
|
|
212
|
-
|
|
213
|
-
<!-- min-pad will be NaN if there was nothing to count -->
|
|
214
|
-
<xsl:choose>
|
|
215
|
-
<xsl:when test="string($min-pad)='NaN'">
|
|
216
|
-
<xsl:value-of select="0" />
|
|
217
|
-
</xsl:when>
|
|
218
|
-
<xsl:otherwise>
|
|
219
|
-
<xsl:value-of select="$min-pad" />
|
|
220
|
-
</xsl:otherwise>
|
|
221
|
-
</xsl:choose>
|
|
222
|
-
</xsl:template>
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
<!-- Divide and conquer strip-indentation -->
|
|
226
|
-
<!-- Appropriate for long chunks of text. Minimal overhead on small -->
|
|
227
|
-
<!-- chunks of text. -->
|
|
228
|
-
<!-- An "out-dented" line is assumed to be intermediate blank line -->
|
|
229
|
-
<!-- indent parameter is a number giving number of characters to strip -->
|
|
230
|
-
<xsl:template name="strip-indentation">
|
|
231
|
-
<xsl:param name="text" />
|
|
232
|
-
<xsl:param name="indent" />
|
|
233
|
-
|
|
234
|
-
<!-- string length at which to give up divide and conquer -->
|
|
235
|
-
<xsl:variable name="divide-threshold" select="500" />
|
|
236
|
-
|
|
237
|
-
<xsl:variable name="text-len" select="string-length($text)" />
|
|
238
|
-
<xsl:choose>
|
|
239
|
-
<!-- short string, hand off to line by line algorithm -->
|
|
240
|
-
<xsl:when test="$divide-threshold > $text-len">
|
|
241
|
-
<xsl:call-template name="strip-indentation-core">
|
|
242
|
-
<xsl:with-param name="text" select="$text" />
|
|
243
|
-
<xsl:with-param name="indent" select="$indent" />
|
|
244
|
-
</xsl:call-template>
|
|
245
|
-
</xsl:when>
|
|
246
|
-
<xsl:otherwise>
|
|
247
|
-
<!-- Cut string in half -->
|
|
248
|
-
<xsl:variable name="cut-location" select="floor(string-length($text) div 2)"/>
|
|
249
|
-
<xsl:variable name="first-half" select="substring($text, 1, $cut-location)"/>
|
|
250
|
-
<xsl:variable name="second-half" select="substring($text, $cut-location + 1)"/>
|
|
251
|
-
<!-- First half needs to take on everything before first newline -->
|
|
252
|
-
<!-- in second-half and have a trailing newline -->
|
|
253
|
-
<xsl:variable name="first-half-augmented" select="concat($first-half, substring-before($second-half, '
'), '
')"/>
|
|
254
|
-
<!-- Second half only gets text after the first newline in it -->
|
|
255
|
-
<xsl:variable name="second-half-augmented" select="substring-after($second-half, '
')"/>
|
|
256
|
-
|
|
257
|
-
<!-- Stop dividing? -->
|
|
258
|
-
<xsl:choose>
|
|
259
|
-
<xsl:when test="$second-half-augmented = ''">
|
|
260
|
-
<!-- Nothing in second half (can happen with really long lines) -->
|
|
261
|
-
<!-- Give up and hand first half to line-by-line -->
|
|
262
|
-
<xsl:call-template name="strip-indentation-core">
|
|
263
|
-
<xsl:with-param name="text" select="$first-half-augmented" />
|
|
264
|
-
<xsl:with-param name="indent" select="$indent" />
|
|
265
|
-
</xsl:call-template>
|
|
266
|
-
</xsl:when>
|
|
267
|
-
<xsl:otherwise>
|
|
268
|
-
<!-- Recurse on each half -->
|
|
269
|
-
<xsl:call-template name="strip-indentation">
|
|
270
|
-
<xsl:with-param name="text" select="$first-half-augmented" />
|
|
271
|
-
<xsl:with-param name="indent" select="$indent" />
|
|
272
|
-
</xsl:call-template>
|
|
273
|
-
<xsl:call-template name="strip-indentation">
|
|
274
|
-
<xsl:with-param name="text" select="$second-half-augmented" />
|
|
275
|
-
<xsl:with-param name="indent" select="$indent" />
|
|
276
|
-
</xsl:call-template>
|
|
277
|
-
</xsl:otherwise>
|
|
278
|
-
</xsl:choose>
|
|
279
|
-
</xsl:otherwise>
|
|
280
|
-
</xsl:choose>
|
|
281
|
-
</xsl:template>
|
|
282
|
-
|
|
283
|
-
<!-- Line by line strip-indentation -->
|
|
284
|
-
<!-- should only be called on shortish chunks of text -->
|
|
285
|
-
<!-- (dozens of lines not hundreds) -->
|
|
286
|
-
<!-- An "out-dented" line is assumed to be intermediate blank line -->
|
|
287
|
-
<!-- indent parameter is a number giving number of characters to strip -->
|
|
288
|
-
<xsl:template name="strip-indentation-core">
|
|
289
|
-
<xsl:param name="text" />
|
|
290
|
-
<xsl:param name="indent" />
|
|
291
|
-
<xsl:if test="$text != ''">
|
|
292
|
-
<xsl:variable name="first-line" select="substring-before($text, '
')" />
|
|
293
|
-
<xsl:if test="string-length($first-line) > $indent" >
|
|
294
|
-
<xsl:value-of select="substring($first-line, $indent + 1)" />
|
|
295
|
-
</xsl:if>
|
|
296
|
-
<xsl:text>
</xsl:text>
|
|
297
|
-
<xsl:call-template name="strip-indentation-core">
|
|
298
|
-
<xsl:with-param name="text" select="substring-after($text, '
')" />
|
|
299
|
-
<xsl:with-param name="indent" select="$indent" />
|
|
300
|
-
</xsl:call-template>
|
|
301
|
-
</xsl:if>
|
|
302
|
-
</xsl:template>
|
|
303
|
-
|
|
304
|
-
<!-- Add a common string in front of every line of a block -->
|
|
305
|
-
<!-- Typically spaces to format output block for doctest -->
|
|
306
|
-
<!-- indent parameter is a string -->
|
|
307
|
-
<!-- Assumes last character is xA -->
|
|
308
|
-
<!-- Result has trailing xA -->
|
|
309
|
-
<xsl:template name="add-indentation">
|
|
310
|
-
<xsl:param name="text" />
|
|
311
|
-
<xsl:param name="indent" />
|
|
312
|
-
<xsl:if test="$text != ''">
|
|
313
|
-
<xsl:value-of select="concat($indent,substring-before($text, '
'))" />
|
|
314
|
-
<xsl:text>
</xsl:text>
|
|
315
|
-
<xsl:call-template name="add-indentation">
|
|
316
|
-
<xsl:with-param name="text" select="substring-after($text, '
')" />
|
|
317
|
-
<xsl:with-param name="indent" select="$indent" />
|
|
318
|
-
</xsl:call-template>
|
|
319
|
-
</xsl:if>
|
|
320
|
-
</xsl:template>
|
|
321
|
-
|
|
322
|
-
<!-- Shift all lines in text to the left far enough that -->
|
|
323
|
-
<!-- line with the least indentation is at the left margin -->
|
|
324
|
-
<xsl:template name="left-align-text">
|
|
325
|
-
<xsl:param name="text" />
|
|
326
|
-
<xsl:variable name="left-margin">
|
|
327
|
-
<xsl:call-template name="left-margin">
|
|
328
|
-
<xsl:with-param name="text" select="$text" />
|
|
329
|
-
</xsl:call-template>
|
|
330
|
-
</xsl:variable>
|
|
331
|
-
<xsl:variable name="stripped-text">
|
|
332
|
-
<xsl:call-template name="strip-indentation">
|
|
333
|
-
<!-- strip-indentation requires trailing newline -->
|
|
334
|
-
<!-- add one here and trim it when done -->
|
|
335
|
-
<xsl:with-param name="text" select="concat($text, '
')" />
|
|
336
|
-
<xsl:with-param name="indent" select="$left-margin" />
|
|
337
|
-
</xsl:call-template>
|
|
338
|
-
</xsl:variable>
|
|
339
|
-
<!-- produce value without the added newline -->
|
|
340
|
-
<xsl:value-of select="substring($stripped-text, 1, string-length($stripped-text) - 1)" />
|
|
341
|
-
</xsl:template>
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
<!-- Main template for cleaning up hunks of raw text -->
|
|
345
|
-
<!-- -->
|
|
346
|
-
<!-- 1) Trim all trailing whitespace -->
|
|
347
|
-
<!-- 2) Add carriage return marker to last line -->
|
|
348
|
-
<!-- 3) Strip all totally blank leading lines -->
|
|
349
|
-
<!-- 4) Determine indentation of left-most non-blank line -->
|
|
350
|
-
<!-- 5) Strip indentation from all lines -->
|
|
351
|
-
<!-- 6) Allow intermediate blank lines -->
|
|
352
|
-
|
|
353
|
-
<xsl:template name="sanitize-text">
|
|
354
|
-
<xsl:param name="text" />
|
|
355
|
-
<xsl:param name="preserve-end" select="false()" />
|
|
356
|
-
<xsl:param name="preserve-start" select="false()" />
|
|
357
|
-
<xsl:variable name="trimmed-text">
|
|
358
|
-
<xsl:call-template name="trim-start-lines">
|
|
359
|
-
<xsl:with-param name="text">
|
|
360
|
-
<xsl:call-template name="trim-end">
|
|
361
|
-
<xsl:with-param name="text" select="$text" />
|
|
362
|
-
<xsl:with-param name="preserve-intentional" select="$preserve-end" />
|
|
363
|
-
</xsl:call-template>
|
|
364
|
-
</xsl:with-param>
|
|
365
|
-
<xsl:with-param name="preserve-intentional" select="$preserve-start" />
|
|
366
|
-
</xsl:call-template>
|
|
367
|
-
</xsl:variable>
|
|
368
|
-
<xsl:call-template name="left-align-text" >
|
|
369
|
-
<xsl:with-param name="text" select="$trimmed-text" />
|
|
370
|
-
</xsl:call-template>
|
|
371
|
-
</xsl:template>
|
|
372
|
-
|
|
373
|
-
<!-- Substrings at last markers -->
|
|
374
|
-
<!-- XSLT Cookbook, 2nd Edition -->
|
|
375
|
-
<!-- Copyright 2006, O'Reilly Media, Inc. -->
|
|
376
|
-
<!-- Recipe 2.4, nearly verbatim, reformatted -->
|
|
377
|
-
<xsl:template name="substring-before-last-iterative">
|
|
378
|
-
<xsl:param name="input" />
|
|
379
|
-
<xsl:param name="substr" />
|
|
380
|
-
<xsl:if test="$substr and contains($input, $substr)">
|
|
381
|
-
<xsl:variable name="temp" select="substring-after($input, $substr)" />
|
|
382
|
-
<xsl:value-of select="substring-before($input, $substr)" />
|
|
383
|
-
<xsl:if test="contains($temp, $substr)">
|
|
384
|
-
<xsl:value-of select="$substr" />
|
|
385
|
-
<xsl:call-template name="substring-before-last-iterative">
|
|
386
|
-
<xsl:with-param name="input" select="$temp" />
|
|
387
|
-
<xsl:with-param name="substr" select="$substr" />
|
|
388
|
-
</xsl:call-template>
|
|
389
|
-
</xsl:if>
|
|
390
|
-
</xsl:if>
|
|
391
|
-
</xsl:template>
|
|
392
|
-
|
|
393
|
-
<!-- Substrings at last markers -->
|
|
394
|
-
<!-- Approach - keep throwing away the first half of the string -->
|
|
395
|
-
<!-- until we reach a point where one more slice would result -->
|
|
396
|
-
<!-- in no more copies of substr. Produce everything that was -->
|
|
397
|
-
<!-- sliced, then let iterative version handle the rest. -->
|
|
398
|
-
<!-- Implemented mostly to prevent lxml from dying due to -->
|
|
399
|
-
<!-- depth limit when processing large strings -->
|
|
400
|
-
<xsl:template name="substring-before-last">
|
|
401
|
-
<xsl:param name="input" />
|
|
402
|
-
<xsl:param name="substr" />
|
|
403
|
-
|
|
404
|
-
<xsl:variable name="mid-index" select="ceiling(string-length($input) div 2)"/>
|
|
405
|
-
<xsl:variable name="front" select="substring($input, 1, $mid-index)"/>
|
|
406
|
-
<xsl:variable name="back" select="substring($input, $mid-index + 1)"/>
|
|
407
|
-
|
|
408
|
-
<xsl:choose>
|
|
409
|
-
<xsl:when test="contains($back, $substr)">
|
|
410
|
-
<!-- Need front for sure, recurse on back -->
|
|
411
|
-
<xsl:value-of select="$front" />
|
|
412
|
-
<xsl:call-template name="substring-before-last">
|
|
413
|
-
<xsl:with-param name="input" select="$back" />
|
|
414
|
-
<xsl:with-param name="substr" select="$substr" />
|
|
415
|
-
</xsl:call-template>
|
|
416
|
-
</xsl:when>
|
|
417
|
-
<xsl:otherwise>
|
|
418
|
-
<!-- substr might be in front, or bridging front and back -->
|
|
419
|
-
<!-- hand off entire string to iterative version -->
|
|
420
|
-
<xsl:call-template name="substring-before-last-iterative">
|
|
421
|
-
<xsl:with-param name="input" select="$input" />
|
|
422
|
-
<xsl:with-param name="substr" select="$substr" />
|
|
423
|
-
</xsl:call-template>
|
|
424
|
-
</xsl:otherwise>
|
|
425
|
-
</xsl:choose>
|
|
426
|
-
</xsl:template>
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
<!-- substring from $input after first instance of $substr -->
|
|
430
|
-
<!-- if no match, returns original string -->
|
|
431
|
-
<!-- similar to substring-after() function but preserves original -->
|
|
432
|
-
<xsl:template name="substring-after-preserve">
|
|
433
|
-
<xsl:param name="input"/>
|
|
434
|
-
<xsl:param name="substr"/>
|
|
435
|
-
<!-- Extract the string which comes after the first occurrence -->
|
|
436
|
-
<xsl:variable name="temp" select="substring-after($input,$substr)"/>
|
|
437
|
-
<xsl:choose>
|
|
438
|
-
<xsl:when test="$temp = ''">
|
|
439
|
-
<xsl:value-of select="$input"/>
|
|
440
|
-
</xsl:when>
|
|
441
|
-
<xsl:otherwise>
|
|
442
|
-
<xsl:value-of select="$temp"/>
|
|
443
|
-
</xsl:otherwise>
|
|
444
|
-
</xsl:choose>
|
|
445
|
-
</xsl:template>
|
|
446
|
-
|
|
447
|
-
<!-- If the substring is not contained, the first substring-after() -->
|
|
448
|
-
<!-- will return empty and entire template will return empty. To -->
|
|
449
|
-
<!-- get the whole string, prepend $input with $substr prior to using -->
|
|
450
|
-
<xsl:template name="substring-after-last">
|
|
451
|
-
<xsl:param name="input"/>
|
|
452
|
-
<xsl:param name="substr"/>
|
|
453
|
-
<!-- Extract the string which comes after the first occurrence -->
|
|
454
|
-
<xsl:variable name="temp" select="substring-after($input,$substr)"/>
|
|
455
|
-
<xsl:choose>
|
|
456
|
-
<!-- If it still contains the search string then recursively process -->
|
|
457
|
-
<xsl:when test="$substr and contains($temp,$substr)">
|
|
458
|
-
<xsl:call-template name="substring-after-last">
|
|
459
|
-
<xsl:with-param name="input" select="$temp"/>
|
|
460
|
-
<xsl:with-param name="substr" select="$substr"/>
|
|
461
|
-
</xsl:call-template>
|
|
462
|
-
</xsl:when>
|
|
463
|
-
<xsl:otherwise>
|
|
464
|
-
<xsl:value-of select="$temp"/>
|
|
465
|
-
</xsl:otherwise>
|
|
466
|
-
</xsl:choose>
|
|
467
|
-
</xsl:template>
|
|
468
|
-
|
|
469
|
-
<!-- Duplicating Strings -->
|
|
470
|
-
<!-- XSLT Cookbook, 2nd Edition -->
|
|
471
|
-
<!-- Copyright 2006, O'Reilly Media, Inc. -->
|
|
472
|
-
<!-- Recipe 2.5, nearly verbatim, reformatted -->
|
|
473
|
-
<xsl:template name="duplicate-string">
|
|
474
|
-
<xsl:param name="text" />
|
|
475
|
-
<xsl:param name="count" select="1" />
|
|
476
|
-
<xsl:choose>
|
|
477
|
-
<xsl:when test="not($count) or not($text)" />
|
|
478
|
-
<xsl:when test="$count = 1">
|
|
479
|
-
<xsl:value-of select="$text" />
|
|
480
|
-
</xsl:when>
|
|
481
|
-
<xsl:otherwise>
|
|
482
|
-
<!-- If $count is odd, append one copy of input -->
|
|
483
|
-
<xsl:if test="$count mod 2">
|
|
484
|
-
<xsl:value-of select="$text" />
|
|
485
|
-
</xsl:if>
|
|
486
|
-
<!-- Recursively apply template, after -->
|
|
487
|
-
<!-- doubling input and halving count -->
|
|
488
|
-
<xsl:call-template name="duplicate-string">
|
|
489
|
-
<xsl:with-param name="text" select="concat($text,$text)" />
|
|
490
|
-
<xsl:with-param name="count" select="floor($count div 2)" />
|
|
491
|
-
</xsl:call-template>
|
|
492
|
-
</xsl:otherwise>
|
|
493
|
-
</xsl:choose>
|
|
494
|
-
</xsl:template>
|
|
495
|
-
|
|
496
|
-
<!-- Prepending Strings -->
|
|
497
|
-
<!-- Add count copies of the string pad to each line of text -->
|
|
498
|
-
<!-- Presumes text has a newline character at the very end -->
|
|
499
|
-
<xsl:template name="prepend-string">
|
|
500
|
-
<xsl:param name="text" />
|
|
501
|
-
<xsl:param name="pad" />
|
|
502
|
-
<xsl:param name="count" select="1" />
|
|
503
|
-
<xsl:variable name="bigpad">
|
|
504
|
-
<xsl:call-template name="duplicate-string">
|
|
505
|
-
<xsl:with-param name="text" select="$pad" />
|
|
506
|
-
<xsl:with-param name="count" select="$count" />
|
|
507
|
-
</xsl:call-template>
|
|
508
|
-
</xsl:variable>
|
|
509
|
-
<!-- Quit when string becomes empty -->
|
|
510
|
-
<xsl:if test="string-length($text)">
|
|
511
|
-
<xsl:variable name="first-line" select="substring-before($text, '
')" />
|
|
512
|
-
<xsl:value-of select="$bigpad" />
|
|
513
|
-
<xsl:value-of select="$first-line" />
|
|
514
|
-
<xsl:text>
</xsl:text>
|
|
515
|
-
<!-- recursive call on remaining lines -->
|
|
516
|
-
<xsl:call-template name="prepend-string">
|
|
517
|
-
<xsl:with-param name="text" select="substring-after($text, '
')" />
|
|
518
|
-
<xsl:with-param name="pad" select="$bigpad" />
|
|
519
|
-
<xsl:with-param name="count" select="1" />
|
|
520
|
-
</xsl:call-template>
|
|
521
|
-
</xsl:if>
|
|
522
|
-
</xsl:template>
|
|
523
|
-
|
|
524
|
-
<!-- Counting Substrings -->
|
|
525
|
-
<xsl:template name="count-substring">
|
|
526
|
-
<xsl:param name="text" />
|
|
527
|
-
<xsl:param name="word" />
|
|
528
|
-
<xsl:param name="count" select="'0'" />
|
|
529
|
-
<xsl:choose>
|
|
530
|
-
<xsl:when test="not(contains($text, $word))">
|
|
531
|
-
<xsl:value-of select="$count" />
|
|
532
|
-
</xsl:when>
|
|
533
|
-
<xsl:otherwise>
|
|
534
|
-
<xsl:call-template name="count-substring">
|
|
535
|
-
<xsl:with-param name="text" select="substring-after($text, $word)" />
|
|
536
|
-
<xsl:with-param name="word" select="$word" />
|
|
537
|
-
<xsl:with-param name="count" select="$count + 1" />
|
|
538
|
-
</xsl:call-template>
|
|
539
|
-
</xsl:otherwise>
|
|
540
|
-
</xsl:choose>
|
|
541
|
-
</xsl:template>
|
|
542
|
-
|
|
543
|
-
<!-- Remove empty lines -->
|
|
544
|
-
<!-- These are lines with no characters -->
|
|
545
|
-
<!-- at all, just a newline -->
|
|
546
|
-
<!-- 2017-01-22: UNUSED, UNTESTED, incorporate with caution -->
|
|
547
|
-
<xsl:template name="strip-empty-lines">
|
|
548
|
-
<xsl:param name="text" />
|
|
549
|
-
<xsl:choose>
|
|
550
|
-
<!-- no more splitting, output $text, empty or not -->
|
|
551
|
-
<xsl:when test="not(contains($text, '
'))">
|
|
552
|
-
<xsl:value-of select="$text" />
|
|
553
|
-
</xsl:when>
|
|
554
|
-
<xsl:otherwise>
|
|
555
|
-
<xsl:variable name="firstline" select="substring-before($text, '
')" />
|
|
556
|
-
<xsl:choose>
|
|
557
|
-
<!-- silently drop an empty line, newline already gone -->
|
|
558
|
-
<xsl:when test="not($firstline)" />
|
|
559
|
-
<!-- output first line with restored newline -->
|
|
560
|
-
<xsl:otherwise>
|
|
561
|
-
<xsl:value-of select="concat($firstline, '
')" />
|
|
562
|
-
</xsl:otherwise>
|
|
563
|
-
</xsl:choose>
|
|
564
|
-
<!-- recurse with remainder -->
|
|
565
|
-
<xsl:call-template name="strip-empty-lines">
|
|
566
|
-
<xsl:with-param name="text" select="substring-after($text, '
')" />
|
|
567
|
-
</xsl:call-template>
|
|
568
|
-
</xsl:otherwise>
|
|
569
|
-
</xsl:choose>
|
|
570
|
-
</xsl:template>
|
|
571
|
-
|
|
572
|
-
<!-- Merge consecutive empty lines -->
|
|
573
|
-
<!-- In other words, if there are three or more consecutive newline -->
|
|
574
|
-
<!-- characters, replace them with just two newline characters. -->
|
|
575
|
-
<xsl:template name="consolidate-empty-lines">
|
|
576
|
-
<xsl:param name="text" />
|
|
577
|
-
<xsl:choose>
|
|
578
|
-
<xsl:when test="not(contains($text, '


'))">
|
|
579
|
-
<xsl:value-of select="$text" />
|
|
580
|
-
</xsl:when>
|
|
581
|
-
<xsl:otherwise>
|
|
582
|
-
<xsl:call-template name="consolidate-empty-lines">
|
|
583
|
-
<xsl:with-param name="text" select="str:replace($text,'


','

')" />
|
|
584
|
-
</xsl:call-template>
|
|
585
|
-
</xsl:otherwise>
|
|
586
|
-
</xsl:choose>
|
|
587
|
-
</xsl:template>
|
|
588
|
-
|
|
589
|
-
<!-- Gobble leading whitespace -->
|
|
590
|
-
<!-- Drop consecutive leading spaces and tabs, only -->
|
|
591
|
-
<!-- Designed for a single line as input -->
|
|
592
|
-
<!-- Used after maniplating sentence ending punctuation -->
|
|
593
|
-
<xsl:template name="strip-leading-blanks">
|
|
594
|
-
<xsl:param name="text" />
|
|
595
|
-
<xsl:variable name="first-char" select="substring($text, 1, 1)" />
|
|
596
|
-
<xsl:choose>
|
|
597
|
-
<!-- if empty, done -->
|
|
598
|
-
<xsl:when test="not($first-char)" />
|
|
599
|
-
<!-- first character is space, tab, drop it -->
|
|
600
|
-
<xsl:when test="contains(' 	', $first-char)">
|
|
601
|
-
<xsl:call-template name="strip-leading-blanks">
|
|
602
|
-
<xsl:with-param name="text" select="substring($text, 2)" />
|
|
603
|
-
</xsl:call-template>
|
|
604
|
-
</xsl:when>
|
|
605
|
-
<!-- finished stripping, output as-is -->
|
|
606
|
-
<xsl:otherwise>
|
|
607
|
-
<xsl:value-of select="$text" />
|
|
608
|
-
</xsl:otherwise>
|
|
609
|
-
</xsl:choose>
|
|
610
|
-
</xsl:template>
|
|
611
|
-
|
|
612
|
-
<!-- Shove text left -->
|
|
613
|
-
<!-- Remove all leading whitespace from every line -->
|
|
614
|
-
<!-- Note: very similar to "sanitize-latex" below -->
|
|
615
|
-
<!-- 2017-01-22: UNUSED, UNTESTED, incorporate with caution -->
|
|
616
|
-
<xsl:template name="slide-text-left">
|
|
617
|
-
<xsl:param name="text" />
|
|
618
|
-
<xsl:choose>
|
|
619
|
-
<!-- no more splitting, strip leading whitespace -->
|
|
620
|
-
<xsl:when test="not(contains($text, '
'))">
|
|
621
|
-
<xsl:call-template name="strip-leading-blanks">
|
|
622
|
-
<xsl:with-param name="text">
|
|
623
|
-
<xsl:value-of select="$text" />
|
|
624
|
-
</xsl:with-param>
|
|
625
|
-
</xsl:call-template>
|
|
626
|
-
</xsl:when>
|
|
627
|
-
<xsl:otherwise>
|
|
628
|
-
<xsl:call-template name="strip-leading-blanks">
|
|
629
|
-
<xsl:with-param name="text" select="concat(substring-before($text, '
'), '
')" />
|
|
630
|
-
</xsl:call-template>
|
|
631
|
-
<!-- recurse with remainder -->
|
|
632
|
-
<xsl:call-template name="slide-text-left">
|
|
633
|
-
<xsl:with-param name="text" select="substring-after($text, '
')" />
|
|
634
|
-
</xsl:call-template>
|
|
635
|
-
</xsl:otherwise>
|
|
636
|
-
</xsl:choose>
|
|
637
|
-
</xsl:template>
|
|
638
|
-
|
|
639
|
-
<!-- Strip whitespace after line break -->
|
|
640
|
-
<!-- A hard line-break (newline) in authors' source will typically -->
|
|
641
|
-
<!-- introduce leading whitespace (spaces) prior to the next line. -->
|
|
642
|
-
<!-- This template scrubs the spaces, but leaves the newline (which -->
|
|
643
|
-
<!-- can be dealt with by the consumer). Strategy is to replace -->
|
|
644
|
-
<!-- <newline><space> by <newline> until it cannot be done anymore. -->
|
|
645
|
-
<xsl:template name="reduce-line-break">
|
|
646
|
-
<xsl:param name="text"/>
|
|
647
|
-
|
|
648
|
-
<xsl:choose>
|
|
649
|
-
<xsl:when test="not(contains($text, '
 '))">
|
|
650
|
-
<xsl:value-of select="$text"/>
|
|
651
|
-
</xsl:when>
|
|
652
|
-
<xsl:otherwise>
|
|
653
|
-
<xsl:call-template name="reduce-line-break">
|
|
654
|
-
<xsl:with-param name="text" select="str:replace($text, '
 ', '
')"/>
|
|
655
|
-
</xsl:call-template>
|
|
656
|
-
</xsl:otherwise>
|
|
657
|
-
</xsl:choose>
|
|
658
|
-
</xsl:template>
|
|
659
|
-
|
|
660
|
-
<!-- Sanitize Nemeth Braille -->
|
|
661
|
-
<!-- We receive Nemeth braille from MathJax and Speech Rule Engine (SRE) as -->
|
|
662
|
-
<!-- -->
|
|
663
|
-
<!-- 1. Optional indentation U+2800 for second, and subsequent lines of -->
|
|
664
|
-
<!-- 2D layout display math -->
|
|
665
|
-
<!-- 2. Actual content with U+2800 as spaces -->
|
|
666
|
-
<!-- 3. An optional run of U+2800 to form a uniform right margin for -->
|
|
667
|
-
<!-- (eventual) 2D physical devices. -->
|
|
668
|
-
<!-- -->
|
|
669
|
-
<!-- To play nice with liblouis we let U+2800 be an unbreakable space -->
|
|
670
|
-
<!-- and U+0020 ("regular" space) be a breakable space. So -->
|
|
671
|
-
<!-- -->
|
|
672
|
-
<!-- 1. We preserve indentation as unbreakable spaces. -->
|
|
673
|
-
<!-- 2. We convert content spaces to "regular" spaces. In some cases -->
|
|
674
|
-
<!-- we make convert them back to unbreakable spaces. -->
|
|
675
|
-
<!-- 3. We drop trailing (right margin) whitespace, as unnecessary, -->
|
|
676
|
-
<!-- and even problematic. -->
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
<!-- Break on newlines. Trim trailing whitespace, massage whitespace in -->
|
|
680
|
-
<!-- remainder. Reconstitute with same patter of newlines. Note: for -->
|
|
681
|
-
<!-- single-line braille from SRE there is no indentation and no trailing -->
|
|
682
|
-
<!-- whitespace for a right margin. -->
|
|
683
|
-
<!-- NB: "otherwise" might be simpler if some conditioning was different -->
|
|
684
|
-
<!-- in the "when. -->
|
|
685
|
-
|
|
686
|
-
<xsl:template name="sanitize-nemeth-braille">
|
|
687
|
-
<xsl:param name="text"/>
|
|
688
|
-
<xsl:choose>
|
|
689
|
-
<xsl:when test="contains($text, '
')">
|
|
690
|
-
<xsl:variable name="one-line" select="substring-before($text, '
')"/>
|
|
691
|
-
<!-- strip end of a single line of U+2800, a braille empty cell -->
|
|
692
|
-
<xsl:variable name="end-trimmed">
|
|
693
|
-
<xsl:call-template name="trim-nemeth-trailing-whitespace">
|
|
694
|
-
<xsl:with-param name="text" select="$one-line"/>
|
|
695
|
-
</xsl:call-template>
|
|
696
|
-
</xsl:variable>
|
|
697
|
-
<xsl:call-template name="convert-nemeth-whitespace">
|
|
698
|
-
<xsl:with-param name="text" select="$end-trimmed"/>
|
|
699
|
-
</xsl:call-template>
|
|
700
|
-
<!-- restore "split-out" newline -->
|
|
701
|
-
<xsl:text>
</xsl:text>
|
|
702
|
-
<!-- recursively process remainder -->
|
|
703
|
-
<xsl:call-template name="sanitize-nemeth-braille">
|
|
704
|
-
<xsl:with-param name="text" select="substring-after($text, '
')"/>
|
|
705
|
-
</xsl:call-template>
|
|
706
|
-
</xsl:when>
|
|
707
|
-
<xsl:otherwise>
|
|
708
|
-
<!-- last line, needs manipulation -->
|
|
709
|
-
<xsl:variable name="end-trimmed">
|
|
710
|
-
<xsl:call-template name="trim-nemeth-trailing-whitespace">
|
|
711
|
-
<xsl:with-param name="text" select="$text"/>
|
|
712
|
-
</xsl:call-template>
|
|
713
|
-
</xsl:variable>
|
|
714
|
-
<xsl:call-template name="convert-nemeth-whitespace">
|
|
715
|
-
<xsl:with-param name="text" select="$end-trimmed"/>
|
|
716
|
-
</xsl:call-template>
|
|
717
|
-
<!-- no newline to restore -->
|
|
718
|
-
</xsl:otherwise>
|
|
719
|
-
</xsl:choose>
|
|
720
|
-
</xsl:template>
|
|
721
|
-
|
|
722
|
-
<!-- Work in from right margin, dropping consecutive U+2800 -->
|
|
723
|
-
<xsl:template name="trim-nemeth-trailing-whitespace">
|
|
724
|
-
<xsl:param name="text"/>
|
|
725
|
-
<xsl:variable name="last-char" select="substring($text, string-length($text), 1)" />
|
|
726
|
-
<xsl:choose>
|
|
727
|
-
<xsl:when test="$last-char = '⠀'">
|
|
728
|
-
<xsl:call-template name="trim-nemeth-trailing-whitespace">
|
|
729
|
-
<xsl:with-param name="text" select="substring($text, 1, string-length($text) - 1)" />
|
|
730
|
-
</xsl:call-template>
|
|
731
|
-
</xsl:when>
|
|
732
|
-
<xsl:otherwise>
|
|
733
|
-
<xsl:value-of select="$text" />
|
|
734
|
-
</xsl:otherwise>
|
|
735
|
-
</xsl:choose>
|
|
736
|
-
</xsl:template>
|
|
737
|
-
|
|
738
|
-
<!-- Work in from the left. The $b-indentation boolean signals that -->
|
|
739
|
-
<!-- the last character examined was a U+2800 from the run of indentation -->
|
|
740
|
-
<!-- (which we simply duplicate). It begins true as the default value, -->
|
|
741
|
-
<!-- which is not present in initial call. Once it flips false, it stays -->
|
|
742
|
-
<!-- false. Spaces within content convert to "regular" spaces. -->
|
|
743
|
-
<!-- Note: once $b-indentation flips false, we could just do a -->
|
|
744
|
-
<!-- search/replace on the string to output with a "value-of" -->
|
|
745
|
-
|
|
746
|
-
<xsl:template name="convert-nemeth-whitespace">
|
|
747
|
-
<xsl:param name="text"/>
|
|
748
|
-
<xsl:param name="b-indentation" select="true()"/>
|
|
749
|
-
|
|
750
|
-
<xsl:choose>
|
|
751
|
-
<xsl:when test="$text">
|
|
752
|
-
<xsl:variable name="first-char" select="substring($text, 1, 1)"/>
|
|
753
|
-
<xsl:variable name="b-found-indentation" select="$b-indentation and ($first-char = '⠀')"/>
|
|
754
|
-
<xsl:choose>
|
|
755
|
-
<!-- echo a leading U+2800 in the indentation-->
|
|
756
|
-
<xsl:when test="$b-found-indentation">
|
|
757
|
-
<xsl:text>⠀</xsl:text>
|
|
758
|
-
</xsl:when>
|
|
759
|
-
<!-- convert space in content into a regular space -->
|
|
760
|
-
<xsl:when test="$first-char = '⠀'">
|
|
761
|
-
<xsl:text> </xsl:text>
|
|
762
|
-
</xsl:when>
|
|
763
|
-
<!-- echo any other character -->
|
|
764
|
-
<xsl:otherwise>
|
|
765
|
-
<xsl:value-of select="$first-char"/>
|
|
766
|
-
</xsl:otherwise>
|
|
767
|
-
</xsl:choose>
|
|
768
|
-
<!-- Recurse with all but the first character -->
|
|
769
|
-
<xsl:call-template name="convert-nemeth-whitespace">
|
|
770
|
-
<xsl:with-param name="text" select="substring($text, 2, string-length($text) - 1)"/>
|
|
771
|
-
<xsl:with-param name="b-indentation" select="$b-found-indentation"/>
|
|
772
|
-
</xsl:call-template>
|
|
773
|
-
</xsl:when>
|
|
774
|
-
<!-- $text is empty string, done -->
|
|
775
|
-
<xsl:otherwise/>
|
|
776
|
-
</xsl:choose>
|
|
777
|
-
</xsl:template>
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
<!-- Sanitize LaTex -->
|
|
781
|
-
<!-- We allow authors to include whitespace for readability -->
|
|
782
|
-
<!-- -->
|
|
783
|
-
<!-- (1) Newlines used to format complicated math (eg matrices) -->
|
|
784
|
-
<!-- (2) Newlines used to avoid word-wrapping in editing tools -->
|
|
785
|
-
<!-- (3) Newlines to support atomic version control changesets -->
|
|
786
|
-
<!-- (4) Source indentation of above, consonant with XML indentation -->
|
|
787
|
-
<!-- -->
|
|
788
|
-
<!-- But once we form LaTeX output we want to -->
|
|
789
|
-
<!-- -->
|
|
790
|
-
<!-- (i) Remove 100% whitespace lines -->
|
|
791
|
-
<!-- (ii) Remove leading whitespace -->
|
|
792
|
-
<!-- (iii) Finish without a newline -->
|
|
793
|
-
<!-- -->
|
|
794
|
-
<!-- So we -->
|
|
795
|
-
<!-- -->
|
|
796
|
-
<!-- (a) Strip all leading whitespace -->
|
|
797
|
-
<!-- (b) Remove any 100% resulting empty lines (newline only) -->
|
|
798
|
-
<!-- (c) Preserve remaining newlines (trailing after content) -->
|
|
799
|
-
<!-- (d) Preserve remaining whitespace (eg, within expressions) -->
|
|
800
|
-
<!-- (e) Take care with trailing characters, except final newline -->
|
|
801
|
-
<!-- -->
|
|
802
|
-
<!-- We can do this because of the limited purposes of the -->
|
|
803
|
-
<!-- m, me, men, md, mdn elements. The whitespace we strip is not -->
|
|
804
|
-
<!-- relevant/important, and what we leave does not change output -->
|
|
805
|
-
<xsl:template name="sanitize-latex">
|
|
806
|
-
<xsl:param name="text" />
|
|
807
|
-
<xsl:variable name="first-char" select="substring($text, 1, 1)" />
|
|
808
|
-
<xsl:choose>
|
|
809
|
-
<!-- empty, end recursion -->
|
|
810
|
-
<xsl:when test="$first-char = ''" />
|
|
811
|
-
<!-- first character is whitespace, including newline -->
|
|
812
|
-
<!-- silently drop it as we recurse on remainder -->
|
|
813
|
-
<xsl:when test="contains($whitespaces, $first-char)">
|
|
814
|
-
<xsl:call-template name="sanitize-latex">
|
|
815
|
-
<xsl:with-param name="text" select="substring($text, 2)" />
|
|
816
|
-
</xsl:call-template>
|
|
817
|
-
</xsl:when>
|
|
818
|
-
<!-- content followed by newline -->
|
|
819
|
-
<!-- split, preserve newline, output, and recurse, but -->
|
|
820
|
-
<!-- drop a newline that only protects trailing whitespace -->
|
|
821
|
-
<xsl:when test="contains($text, '
')">
|
|
822
|
-
<xsl:value-of select="substring-before($text, '
')" />
|
|
823
|
-
<xsl:variable name="remainder" select="substring-after($text, '
')" />
|
|
824
|
-
<xsl:choose>
|
|
825
|
-
<xsl:when test="normalize-space($remainder) = ''" />
|
|
826
|
-
<xsl:otherwise>
|
|
827
|
-
<xsl:text>
</xsl:text>
|
|
828
|
-
<xsl:call-template name="sanitize-latex">
|
|
829
|
-
<xsl:with-param name="text" select="$remainder" />
|
|
830
|
-
</xsl:call-template>
|
|
831
|
-
</xsl:otherwise>
|
|
832
|
-
</xsl:choose>
|
|
833
|
-
</xsl:when>
|
|
834
|
-
<!-- content, no following newline -->
|
|
835
|
-
<!-- output in full, end recursion -->
|
|
836
|
-
<xsl:otherwise>
|
|
837
|
-
<xsl:value-of select="$text" />
|
|
838
|
-
</xsl:otherwise>
|
|
839
|
-
</xsl:choose>
|
|
840
|
-
</xsl:template>
|
|
841
|
-
|
|
842
|
-
<!-- This collects "clause-ending" punctuation -->
|
|
843
|
-
<!-- from the *front* of a text node. It does not -->
|
|
844
|
-
<!-- change the text node, but simply outputs the -->
|
|
845
|
-
<!-- punctuation for use by another template -->
|
|
846
|
-
<xsl:template name="leading-clause-punctuation">
|
|
847
|
-
<xsl:param name="text" />
|
|
848
|
-
<xsl:variable name="first-char" select="substring($text, 1, 1)" />
|
|
849
|
-
<xsl:choose>
|
|
850
|
-
<!-- empty, quit -->
|
|
851
|
-
<xsl:when test="not($first-char)" />
|
|
852
|
-
<!-- if punctuation, output and recurse -->
|
|
853
|
-
<!-- else silently quit recursion -->
|
|
854
|
-
<xsl:when test="contains($clause-ending-marks, $first-char)">
|
|
855
|
-
<xsl:value-of select="$first-char" />
|
|
856
|
-
<xsl:call-template name="leading-clause-punctuation">
|
|
857
|
-
<xsl:with-param name="text" select="substring($text, 2)" />
|
|
858
|
-
</xsl:call-template>
|
|
859
|
-
</xsl:when>
|
|
860
|
-
<!-- consecutive only, stop collecting -->
|
|
861
|
-
<xsl:otherwise />
|
|
862
|
-
</xsl:choose>
|
|
863
|
-
</xsl:template>
|
|
864
|
-
|
|
865
|
-
<!-- If we absorb punctuation, we need to scrub it by -->
|
|
866
|
-
<!-- examining and manipulating the text node with -->
|
|
867
|
-
<!-- those characters. We drop consecutive punctuation. -->
|
|
868
|
-
<xsl:template name="drop-clause-punctuation">
|
|
869
|
-
<xsl:param name="text" />
|
|
870
|
-
<xsl:variable name="first-char" select="substring($text, 1, 1)" />
|
|
871
|
-
<xsl:choose>
|
|
872
|
-
<!-- if empty, done -->
|
|
873
|
-
<xsl:when test="not($first-char)" />
|
|
874
|
-
<!-- first character ends sentence, drop it, recurse -->
|
|
875
|
-
<xsl:when test="contains($clause-ending-marks, $first-char)">
|
|
876
|
-
<xsl:call-template name="drop-clause-punctuation">
|
|
877
|
-
<xsl:with-param name="text" select="substring($text, 2)" />
|
|
878
|
-
</xsl:call-template>
|
|
879
|
-
</xsl:when>
|
|
880
|
-
<!-- no more punctuation, output as-is -->
|
|
881
|
-
<xsl:otherwise>
|
|
882
|
-
<xsl:value-of select="$text" />
|
|
883
|
-
</xsl:otherwise>
|
|
884
|
-
</xsl:choose>
|
|
885
|
-
</xsl:template>
|
|
886
|
-
|
|
887
|
-
<!-- Remove consecutive run of blanks and -->
|
|
888
|
-
<!-- newlines in first portion of a string -->
|
|
889
|
-
<!-- Performance audited 2024-12-15 - this is so frequently called -->
|
|
890
|
-
<!-- in the simple case (nothing to strip) that just about any -->
|
|
891
|
-
<!-- optimization for the general case ends up being slower. -->
|
|
892
|
-
<xsl:template name="strip-leading-whitespace">
|
|
893
|
-
<xsl:param name="text" />
|
|
894
|
-
<xsl:variable name="first-char" select="substring($text, 1, 1)" />
|
|
895
|
-
<xsl:choose>
|
|
896
|
-
<!-- if empty, quit -->
|
|
897
|
-
<xsl:when test="not($first-char)" />
|
|
898
|
-
<!-- if first character is whitespace, drop it -->
|
|
899
|
-
<xsl:when test="contains($whitespaces, $first-char)">
|
|
900
|
-
<xsl:call-template name="strip-leading-whitespace">
|
|
901
|
-
<xsl:with-param name="text" select="substring($text, 2)" />
|
|
902
|
-
</xsl:call-template>
|
|
903
|
-
</xsl:when>
|
|
904
|
-
<!-- else finished stripping, output as-is -->
|
|
905
|
-
<xsl:otherwise>
|
|
906
|
-
<xsl:value-of select="$text" />
|
|
907
|
-
</xsl:otherwise>
|
|
908
|
-
</xsl:choose>
|
|
909
|
-
</xsl:template>
|
|
910
|
-
|
|
911
|
-
<!-- Remove consecutive run of blanks and -->
|
|
912
|
-
<!-- newlines in last portion of a string -->
|
|
913
|
-
<!-- Performance audited 2024-12-15 - this is so frequently called -->
|
|
914
|
-
<!-- in the simple case (nothing to strip) that just about any -->
|
|
915
|
-
<!-- optimization for the general case ends up being slower. -->
|
|
916
|
-
<xsl:template name="strip-trailing-whitespace">
|
|
917
|
-
<xsl:param name="text" />
|
|
918
|
-
<xsl:variable name="last-char" select="substring($text, string-length($text), 1)" />
|
|
919
|
-
<xsl:choose>
|
|
920
|
-
<!-- if empty, quit -->
|
|
921
|
-
<xsl:when test="not($last-char)" />
|
|
922
|
-
<!-- if last character is whitespace, drop it -->
|
|
923
|
-
<xsl:when test="contains($whitespaces, $last-char)">
|
|
924
|
-
<xsl:call-template name="strip-trailing-whitespace">
|
|
925
|
-
<xsl:with-param name="text" select="substring($text, 1, string-length($text)-1)" />
|
|
926
|
-
</xsl:call-template>
|
|
927
|
-
</xsl:when>
|
|
928
|
-
<!-- else finished stripping, output as-is -->
|
|
929
|
-
<xsl:otherwise>
|
|
930
|
-
<xsl:value-of select="$text" />
|
|
931
|
-
</xsl:otherwise>
|
|
932
|
-
</xsl:choose>
|
|
933
|
-
</xsl:template>
|
|
934
|
-
|
|
935
|
-
<!-- spurious newlines introduce whitespace on either side -->
|
|
936
|
-
<!-- we split at newlines, strip consecutive whitesapce on either side, -->
|
|
937
|
-
<!-- and replace newlines by spaces (could restore a single newline) -->
|
|
938
|
-
<xsl:template name="strip-newlines">
|
|
939
|
-
<xsl:param name="text" />
|
|
940
|
-
<xsl:choose>
|
|
941
|
-
<!-- if has newline, modify newline-free front portion -->
|
|
942
|
-
<!-- replace splitting newline with new separator -->
|
|
943
|
-
<!-- modify trailing portion, and recurse with it -->
|
|
944
|
-
<xsl:when test="contains($text, '
')">
|
|
945
|
-
<!-- clean trailing portion of left half -->
|
|
946
|
-
<xsl:call-template name="strip-trailing-whitespace">
|
|
947
|
-
<xsl:with-param name="text" select="substring-before($text, '
')" />
|
|
948
|
-
</xsl:call-template>
|
|
949
|
-
<!-- restore a separator, blank now -->
|
|
950
|
-
<!-- Note: this could be a newline, perhaps optionally (whitespace="breaks") -->
|
|
951
|
-
<!-- Note: this could be " %\n" in LaTeX output to be super explicit -->
|
|
952
|
-
<xsl:text> </xsl:text>
|
|
953
|
-
<!-- recurse with modified right half -->
|
|
954
|
-
<xsl:call-template name="strip-newlines">
|
|
955
|
-
<xsl:with-param name="text">
|
|
956
|
-
<!-- clean leading portion of right half -->
|
|
957
|
-
<xsl:call-template name="strip-leading-whitespace">
|
|
958
|
-
<xsl:with-param name="text" select="substring-after($text, '
')" />
|
|
959
|
-
</xsl:call-template>
|
|
960
|
-
</xsl:with-param>
|
|
961
|
-
</xsl:call-template>
|
|
962
|
-
</xsl:when>
|
|
963
|
-
<!-- else finished stripping, output as-is -->
|
|
964
|
-
<xsl:otherwise>
|
|
965
|
-
<xsl:value-of select="$text" />
|
|
966
|
-
</xsl:otherwise>
|
|
967
|
-
</xsl:choose>
|
|
968
|
-
</xsl:template>
|
|
969
|
-
|
|
970
|
-
<!-- JSON Escaped Strings -->
|
|
971
|
-
<!-- Convert a string, just prior to dropping it into a -->
|
|
972
|
-
<!-- JSON data structure, so this presumes nothing -->
|
|
973
|
-
<!-- special has been done with the contents before-hand -->
|
|
974
|
-
<!-- In order converted, using the standard JSON names: -->
|
|
975
|
-
<!-- reverse solidus (backslash), solidus (slash), -->
|
|
976
|
-
<!-- quotation mark, backspace, horizontal tab, -->
|
|
977
|
-
<!-- newline, form feed, carriage return -->
|
|
978
|
-
<!-- Escaping solidus (forward slash) is only necessary -->
|
|
979
|
-
<!-- for <\ inside a script tag (or similar?) It makes -->
|
|
980
|
-
<!-- URLs ugly, but we do it anyway so we don't get bit. -->
|
|
981
|
-
<!-- Strictly needed: backslash, double quote, newline. -->
|
|
982
|
-
<!-- XSLT3: -->
|
|
983
|
-
<!-- But XML 1.0 does not allow x08 (backspace) and x0c -->
|
|
984
|
-
<!-- (form feed) so we ignore them for now. Perhaps see -->
|
|
985
|
-
<!-- https://stackoverflow.com/questions/404107/ -->
|
|
986
|
-
<!-- why-are-control-characters-illegal-in-xml-1-0 -->
|
|
987
|
-
|
|
988
|
-
<!-- First define the replacements. These must be in -->
|
|
989
|
-
<!-- order as search + replace pairs -->
|
|
990
|
-
<xsl:variable name="json-replacements">
|
|
991
|
-
<search>\</search>
|
|
992
|
-
<replace>\\</replace>
|
|
993
|
-
<search>/</search>
|
|
994
|
-
<replace>\/</replace>
|
|
995
|
-
<search><xsl:value-of select="string('
')"/></search>
|
|
996
|
-
<replace>\n</replace>
|
|
997
|
-
<search><xsl:value-of select="string('	')"/></search>
|
|
998
|
-
<replace>\t</replace>
|
|
999
|
-
<search><xsl:value-of select="string('
')"/></search>
|
|
1000
|
-
<replace>\r</replace>
|
|
1001
|
-
<search><xsl:value-of select="string('"')"/></search>
|
|
1002
|
-
<replace>\"</replace>
|
|
1003
|
-
</xsl:variable>
|
|
1004
|
-
<xsl:variable name="json-replacements-search-set" select="exsl:node-set($json-replacements)/search" />
|
|
1005
|
-
<xsl:variable name="json-replacements-replace-set" select="exsl:node-set($json-replacements)/replace" />
|
|
1006
|
-
|
|
1007
|
-
<xsl:template name="escape-json-string">
|
|
1008
|
-
<xsl:param name="text"/>
|
|
1009
|
-
|
|
1010
|
-
<xsl:value-of select="str:replace($text, $json-replacements-search-set, $json-replacements-replace-set)" />
|
|
1011
|
-
</xsl:template>
|
|
1012
|
-
|
|
1013
|
-
<xsl:template name="quote-string">
|
|
1014
|
-
<xsl:param name="text" />
|
|
1015
|
-
<xsl:text>"</xsl:text>
|
|
1016
|
-
<xsl:value-of select="$text" />
|
|
1017
|
-
<xsl:text>"</xsl:text>
|
|
1018
|
-
</xsl:template>
|
|
1019
|
-
|
|
1020
|
-
<xsl:template name="quote-strip-string">
|
|
1021
|
-
<xsl:param name="text" />
|
|
1022
|
-
<xsl:text>"</xsl:text>
|
|
1023
|
-
<xsl:call-template name="strip-newlines">
|
|
1024
|
-
<xsl:with-param name="text" select="$text" />
|
|
1025
|
-
</xsl:call-template>
|
|
1026
|
-
<xsl:text>"</xsl:text>
|
|
1027
|
-
</xsl:template>
|
|
1028
|
-
|
|
1029
|
-
<xsl:template name="escape-quote-string">
|
|
1030
|
-
<xsl:param name="text" />
|
|
1031
|
-
<xsl:call-template name="quote-string">
|
|
1032
|
-
<xsl:with-param name="text">
|
|
1033
|
-
<xsl:call-template name="escape-json-string">
|
|
1034
|
-
<xsl:with-param name="text" select="$text"/>
|
|
1035
|
-
</xsl:call-template>
|
|
1036
|
-
</xsl:with-param>
|
|
1037
|
-
</xsl:call-template>
|
|
1038
|
-
</xsl:template>
|
|
1039
|
-
|
|
1040
|
-
<xsl:template name="escape-quote-xml">
|
|
1041
|
-
<xsl:param name="xml_content"/>
|
|
1042
|
-
<xsl:variable name="xml_text">
|
|
1043
|
-
<xsl:apply-templates select="exsl:node-set($xml_content)" mode="xml-to-string"/>
|
|
1044
|
-
</xsl:variable>
|
|
1045
|
-
<xsl:call-template name="escape-quote-string">
|
|
1046
|
-
<xsl:with-param name="text" select="$xml_text"/>
|
|
1047
|
-
</xsl:call-template>
|
|
1048
|
-
</xsl:template>
|
|
1049
|
-
|
|
1050
|
-
<!-- File Extension -->
|
|
1051
|
-
<!-- Input: full filename -->
|
|
1052
|
-
<!-- Output: extension (no period), lowercase'd -->
|
|
1053
|
-
<!-- Note: appended query string is stripped -->
|
|
1054
|
-
<xsl:template name="file-extension">
|
|
1055
|
-
<xsl:param name="filename" />
|
|
1056
|
-
<!-- Add a question mark, then grab leading substring -->
|
|
1057
|
-
<!-- This will fail if "?" is encoded -->
|
|
1058
|
-
<xsl:variable name="no-query-string" select="substring-before(concat($filename, '?'), '?')" />
|
|
1059
|
-
<!-- get extension after last period -->
|
|
1060
|
-
<!-- will return empty if no extension -->
|
|
1061
|
-
<xsl:variable name="extension">
|
|
1062
|
-
<xsl:call-template name="substring-after-last">
|
|
1063
|
-
<xsl:with-param name="input" select="$no-query-string" />
|
|
1064
|
-
<xsl:with-param name="substr" select="'.'" />
|
|
1065
|
-
</xsl:call-template>
|
|
1066
|
-
</xsl:variable>
|
|
1067
|
-
<!-- to lowercase -->
|
|
1068
|
-
<xsl:value-of select="translate($extension, &UPPERCASE;, &LOWERCASE;)" />
|
|
1069
|
-
</xsl:template>
|
|
1070
|
-
|
|
1071
|
-
<!-- ################# -->
|
|
1072
|
-
<!-- String Utilities -->
|
|
1073
|
-
<!-- ################# -->
|
|
1074
|
-
|
|
1075
|
-
<!-- Find a delimiter: find a character that can be wrapped around a string -->
|
|
1076
|
-
<!-- Take a string as one input and a list of characters as another input -->
|
|
1077
|
-
<!-- Return the first character from the list that is not in the string -->
|
|
1078
|
-
<xsl:template name="find-unused-character">
|
|
1079
|
-
<xsl:param name="string" select="''"/>
|
|
1080
|
-
<!-- set of characters that are candidates for use as delimiters -->
|
|
1081
|
-
<!-- with empty string as default, failure is guaranteed -->
|
|
1082
|
-
<xsl:param name="charset" select="''"/>
|
|
1083
|
-
<!-- If a character in $charset is inside the string, then we do -->
|
|
1084
|
-
<!-- not want to use it as a delimiter. The translate() function -->
|
|
1085
|
-
<!-- operates so as to morph its first argument, $charset. Called -->
|
|
1086
|
-
<!-- this way, each character of the $charset that is in $string, -->
|
|
1087
|
-
<!-- will be replaced by an empty string. So any character of -->
|
|
1088
|
-
<!-- $charset that survives un-translated, is not in $string. -->
|
|
1089
|
-
<xsl:variable name="characters" select="translate($charset, $string, '')"/>
|
|
1090
|
-
|
|
1091
|
-
<!-- We fail, big time, or elect to use the first available character -->
|
|
1092
|
-
<xsl:choose>
|
|
1093
|
-
<xsl:when test="$characters = ''">
|
|
1094
|
-
<xsl:message>PTX:FATAL: Unable to find an unused character in:
<xsl:value-of select="$string" />
using characters from: <xsl:value-of select="$charset" /></xsl:message>
|
|
1095
|
-
<xsl:apply-templates select="." mode="location-report" />
|
|
1096
|
-
<xsl:message terminate="yes"> That's fatal. Sorry. Quitting...</xsl:message>
|
|
1097
|
-
</xsl:when>
|
|
1098
|
-
<xsl:otherwise>
|
|
1099
|
-
<xsl:value-of select="substring($characters, 1, 1)"/>
|
|
1100
|
-
</xsl:otherwise>
|
|
1101
|
-
</xsl:choose>
|
|
1102
|
-
</xsl:template>
|
|
1103
|
-
|
|
1104
|
-
<!-- ############### -->
|
|
1105
|
-
<!-- Token Utilities -->
|
|
1106
|
-
<!-- ############### -->
|
|
1107
|
-
|
|
1108
|
-
<!-- The "tokenize()" function could replace this? -->
|
|
1109
|
-
<!-- And then dependence on EXSL might be removed. -->
|
|
1110
|
-
|
|
1111
|
-
<!-- Routines that can be employed in a recursive -->
|
|
1112
|
-
<!-- formulation to process a string (attribute value, -->
|
|
1113
|
-
<!-- usually) that is separated by spaces or by commas -->
|
|
1114
|
-
|
|
1115
|
-
<!-- Replace commas by blanks, constrict blanks to singletons, -->
|
|
1116
|
-
<!-- add trailing blank for last step of iteration -->
|
|
1117
|
-
<xsl:template name="prepare-token-list">
|
|
1118
|
-
<xsl:param name="token-list" />
|
|
1119
|
-
<xsl:value-of select="concat(normalize-space(str:replace($token-list, ',', ' ')), ' ')" />
|
|
1120
|
-
</xsl:template>
|
|
1121
|
-
|
|
1122
|
-
<!-- Now, to work through the $token-list -->
|
|
1123
|
-
<!-- 1. If $token-list = '', end recursion -->
|
|
1124
|
-
<!-- 2. Process substring-before($token-list, ' ') as next token -->
|
|
1125
|
-
<!-- 3. Pass substring-after($token-list, ' ') recursively -->
|
|
1126
|
-
|
|
1127
|
-
<!-- Generate a unique set of tokens from a given string -->
|
|
1128
|
-
<!-- Final structure will consist of set of <token>value</token> elements -->
|
|
1129
|
-
<!-- Produces a RTF, so result must be converted to nodeset -->
|
|
1130
|
-
<xsl:template name="unique-token-set">
|
|
1131
|
-
<xsl:param name="s" />
|
|
1132
|
-
<xsl:param name="delimiter" select="', '" />
|
|
1133
|
-
<xsl:variable name="token-list" select="str:tokenize($s, $delimiter)"/>
|
|
1134
|
-
<xsl:variable name="token-set-temp" select="set:distinct($token-list)"/>
|
|
1135
|
-
<!-- Next step is currently a no-op as str:tokenize drops empty strings. But that -->
|
|
1136
|
-
<!-- appears to not be part of the spec. So for safety, get difference with -->
|
|
1137
|
-
<!-- a nodeset composed of a single empty token -->
|
|
1138
|
-
<xsl:variable name="token-set" select="set:difference($token-set-temp, str:tokenize(''))"/>
|
|
1139
|
-
<xsl:copy-of select="$token-set" />
|
|
1140
|
-
</xsl:template>
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
<!-- ################################## -->
|
|
1144
|
-
<!-- Runestone Services General Support -->
|
|
1145
|
-
<!-- ################################## -->
|
|
1146
|
-
|
|
1147
|
-
<!-- Some items that are in play relative to Runestone Services -->
|
|
1148
|
-
<!-- that are independendt of dynamic/static and which can -->
|
|
1149
|
-
<!-- promote consistence if defined only once. End game is the -->
|
|
1150
|
-
<!-- text of a datafile, so appropriate here. However, they -->
|
|
1151
|
-
<!-- are a bit different than above in spirit, as they involve -->
|
|
1152
|
-
<!-- global variables, file manipulations, and are not named -->
|
|
1153
|
-
<!-- templates generally. They are necessary to create static -->
|
|
1154
|
-
<!-- versions of Runestone datafile elements during the -->
|
|
1155
|
-
<!-- assembly phase, and the enhanced-source stylesheet avoids -->
|
|
1156
|
-
<!-- using -common, hence movement here on 2023-10-30. -->
|
|
1157
|
-
|
|
1158
|
-
<!-- Datafiles have default rows and columns -->
|
|
1159
|
-
<xsl:variable name="datafile-default-rows" select="20"/>
|
|
1160
|
-
<xsl:variable name="datafile-default-cols" select="60"/>
|
|
1161
|
-
|
|
1162
|
-
<!-- Get a "view" of a chunk of text, from the "upper-left corner". -->
|
|
1163
|
-
<!-- Motivation is a static version of a (large) datafile of text -->
|
|
1164
|
-
<!-- for interactive programs to consume. -->
|
|
1165
|
-
<!-- text: the text, we provide a version hit by "santitize-tex" -->
|
|
1166
|
-
<!-- above, which pulls left, and drops leading blank lines. -->
|
|
1167
|
-
<!-- nrows: the number of (initial) lines output -->
|
|
1168
|
-
<!-- ncols: the number of (initial) characters on each line -->
|
|
1169
|
-
<!-- if not provided, the entire line is output -->
|
|
1170
|
-
<!-- -->
|
|
1171
|
-
<!-- NB: there can be excess blank lines (nrows in not a maximum) -->
|
|
1172
|
-
<!-- TODO: could be extended to have a "start" location other than -->
|
|
1173
|
-
<!-- upper left corner. Consume initial lines with no action, -->
|
|
1174
|
-
<!-- decrementing start line, then switch to outputing lines -->
|
|
1175
|
-
<!-- themselves. Substring selection should be obvious. -->
|
|
1176
|
-
<xsl:template name="text-viewport">
|
|
1177
|
-
<xsl:param name="text"/>
|
|
1178
|
-
<xsl:param name="nrows"/>
|
|
1179
|
-
<xsl:param name="ncols" select="''"/>
|
|
1180
|
-
|
|
1181
|
-
<xsl:choose>
|
|
1182
|
-
<!-- decremented (or initialized) to zero or below -->
|
|
1183
|
-
<xsl:when test="$nrows < 1"/>
|
|
1184
|
-
<!-- produce a line and recurse -->
|
|
1185
|
-
<xsl:otherwise>
|
|
1186
|
-
<xsl:variable name="line" select="substring-before($text, '
')"/>
|
|
1187
|
-
<xsl:choose>
|
|
1188
|
-
<!-- sentinel: output whole line -->
|
|
1189
|
-
<xsl:when test="$ncols = ''">
|
|
1190
|
-
<xsl:value-of select="$line"/>
|
|
1191
|
-
</xsl:when>
|
|
1192
|
-
<!-- within length limit: output whole line -->
|
|
1193
|
-
<xsl:when test="string-length($line) <= $ncols">
|
|
1194
|
-
<xsl:value-of select="$line"/>
|
|
1195
|
-
</xsl:when>
|
|
1196
|
-
<!-- truncate line to value of $ncols-1, and add -->
|
|
1197
|
-
<!-- a simple right arrow to indicate truncation -->
|
|
1198
|
-
<xsl:otherwise>
|
|
1199
|
-
<xsl:value-of select="substring($line, 1, $ncols - 1)"/>
|
|
1200
|
-
<!-- Unicode Character 'RIGHTWARDS ARROW' -->
|
|
1201
|
-
<xsl:text>→</xsl:text>
|
|
1202
|
-
</xsl:otherwise>
|
|
1203
|
-
</xsl:choose>
|
|
1204
|
-
<!-- restore the missing line-break -->
|
|
1205
|
-
<xsl:value-of select="'
'"/>
|
|
1206
|
-
<!-- rceurse, with remainder of text, requesting -->
|
|
1207
|
-
<!-- one less row, and simply passing along ncols -->
|
|
1208
|
-
<xsl:call-template name="text-viewport">
|
|
1209
|
-
<xsl:with-param name="text" select="substring-after($text, '
')"/>
|
|
1210
|
-
<xsl:with-param name="nrows" select="$nrows - 1"/>
|
|
1211
|
-
<xsl:with-param name="ncols" select="$ncols"/>
|
|
1212
|
-
</xsl:call-template>
|
|
1213
|
-
</xsl:otherwise>
|
|
1214
|
-
</xsl:choose>
|
|
1215
|
-
</xsl:template>
|
|
1216
|
-
|
|
1217
|
-
</xsl:stylesheet>
|
|
1
|
+
<?xml version='1.0'?>
|
|
2
|
+
|
|
3
|
+
<!--********************************************************************
|
|
4
|
+
Copyright 2022 Robert A. Beezer
|
|
5
|
+
|
|
6
|
+
This file is part of PreTeXt.
|
|
7
|
+
|
|
8
|
+
PreTeXt is free software: you can redistribute it and/or modify
|
|
9
|
+
it under the terms of the GNU General Public License as published by
|
|
10
|
+
the Free Software Foundation, either version 2 or version 3 of the
|
|
11
|
+
License (at your option).
|
|
12
|
+
|
|
13
|
+
PreTeXt is distributed in the hope that it will be useful,
|
|
14
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
15
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
16
|
+
GNU General Public License for more details.
|
|
17
|
+
|
|
18
|
+
You should have received a copy of the GNU General Public License
|
|
19
|
+
along with PreTeXt. If not, see <http://www.gnu.org/licenses/>.
|
|
20
|
+
*********************************************************************-->
|
|
21
|
+
|
|
22
|
+
<!-- Indicated basic utilities are from: -->
|
|
23
|
+
<!-- XSLT Cookbook, 2nd Edition -->
|
|
24
|
+
<!-- Copyright 2006, O'Reilly Media, Inc. -->
|
|
25
|
+
<!-- -->
|
|
26
|
+
<!-- From the section of the Preface, "Using Code Examples": -->
|
|
27
|
+
<!-- "You do not need to contact us for permission unless -->
|
|
28
|
+
<!-- you're reproducing a significant portion of the code. -->
|
|
29
|
+
<!-- For example, writing a program that uses several chunks -->
|
|
30
|
+
<!-- of code from this book does not require permission." -->
|
|
31
|
+
|
|
32
|
+
<!-- This stylesheet is meant to xsl:include'd into other stylesheets. -->
|
|
33
|
+
<!-- All the templates were once part of "pretext-common.xsl" (2022-03-27) -->
|
|
34
|
+
<!-- and so are being included at the point where the vast majority were -->
|
|
35
|
+
<!-- originally created. Perhaps the include can move to a more obvious -->
|
|
36
|
+
<!-- location near the top of that file. There is no entry template and -->
|
|
37
|
+
<!-- every template is a named template which relies on parameters, not -->
|
|
38
|
+
<!-- context or a match/select mechanism. (With some exceptions.) -->
|
|
39
|
+
<!-- -->
|
|
40
|
+
<!-- Used in: -->
|
|
41
|
+
<!-- xsl/pretext-common.xsl (2022-03-27) -->
|
|
42
|
+
<!-- xsl/pretext/pretext-runestone-static.xsl (2022-03-28) -->
|
|
43
|
+
|
|
44
|
+
<!-- "unit" tests for these templates are (partially) implemented in -->
|
|
45
|
+
<!-- xsl/tests/pretext-text-utilities-test.xsl -->
|
|
46
|
+
<!-- Before modifying any templates in this file, you are encouraged to -->
|
|
47
|
+
<!-- make sure there is a set of tests for the template(s) and use those -->
|
|
48
|
+
<!-- to verify changes allong with diffs of sample-book/sample-article -->
|
|
49
|
+
|
|
50
|
+
<!-- There are &LOWERCASE; and &UPPERCASE; entities -->
|
|
51
|
+
<!-- in the "file-extension" template (only?) -->
|
|
52
|
+
<!DOCTYPE xsl:stylesheet [
|
|
53
|
+
<!ENTITY % entities SYSTEM "entities.ent">
|
|
54
|
+
%entities;
|
|
55
|
+
]>
|
|
56
|
+
|
|
57
|
+
<!-- EXSL needed for token list template (only?) -->
|
|
58
|
+
<xsl:stylesheet
|
|
59
|
+
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"
|
|
60
|
+
xmlns:xml="http://www.w3.org/XML/1998/namespace"
|
|
61
|
+
xmlns:pi="http://pretextbook.org/2020/pretext/internal"
|
|
62
|
+
xmlns:str="http://exslt.org/strings"
|
|
63
|
+
xmlns:exsl="http://exslt.org/common"
|
|
64
|
+
xmlns:math="http://exslt.org/math"
|
|
65
|
+
xmlns:set="http://exslt.org/sets"
|
|
66
|
+
extension-element-prefixes="pi str math"
|
|
67
|
+
>
|
|
68
|
+
|
|
69
|
+
<!-- Allow serialization of XML in various contexts -->
|
|
70
|
+
<!-- See the XSL file for more info about Lenz' utility -->
|
|
71
|
+
<xsl:import href="./xml-to-string.xsl"/>
|
|
72
|
+
|
|
73
|
+
<!-- ########################## -->
|
|
74
|
+
<!-- Text Manipulation Routines -->
|
|
75
|
+
<!-- ########################## -->
|
|
76
|
+
|
|
77
|
+
<!-- Various bits of textual material -->
|
|
78
|
+
<!-- (eg Sage, code, verbatim, LaTeX) -->
|
|
79
|
+
<!-- require manipulation to -->
|
|
80
|
+
<!-- -->
|
|
81
|
+
<!-- (a) behave in some output format -->
|
|
82
|
+
<!-- (b) produce human-readable output (LaTeX) -->
|
|
83
|
+
|
|
84
|
+
<!-- We need to identify particular characters -->
|
|
85
|
+
<!-- space, tab, carriage return, newline -->
|
|
86
|
+
<xsl:variable name="whitespaces">
|
|
87
|
+
<xsl:text> 	
</xsl:text>
|
|
88
|
+
</xsl:variable>
|
|
89
|
+
|
|
90
|
+
<!-- Sanitize Code -->
|
|
91
|
+
<!-- No leading whitespace, no trailing -->
|
|
92
|
+
<!-- http://stackoverflow.com/questions/1134318/xslt-xslstrip-space-does-not-work -->
|
|
93
|
+
<!-- Trim all whitespace at end of code hunk -->
|
|
94
|
+
<!-- Append carriage return to mark last line, remove later -->
|
|
95
|
+
<!-- preserve-intentional keeps all whitespace that comes -->
|
|
96
|
+
<!-- before the last newline -->
|
|
97
|
+
<xsl:template name="trim-end">
|
|
98
|
+
<xsl:param name="text"/>
|
|
99
|
+
<xsl:param name="preserve-intentional" select="false()" />
|
|
100
|
+
<xsl:variable name="last-char" select="substring($text, string-length($text), 1)" />
|
|
101
|
+
<xsl:choose>
|
|
102
|
+
<xsl:when test="$last-char=''">
|
|
103
|
+
<xsl:text>
</xsl:text>
|
|
104
|
+
</xsl:when>
|
|
105
|
+
<xsl:when test="($preserve-intentional = true()) and ($last-char = '
')">
|
|
106
|
+
<xsl:value-of select="$text"/>
|
|
107
|
+
</xsl:when>
|
|
108
|
+
<xsl:when test="contains($whitespaces, $last-char)">
|
|
109
|
+
<xsl:call-template name="trim-end">
|
|
110
|
+
<xsl:with-param name="text" select="substring($text, 1, string-length($text) - 1)" />
|
|
111
|
+
<xsl:with-param name="preserve-intentional" select="$preserve-intentional" />
|
|
112
|
+
</xsl:call-template>
|
|
113
|
+
</xsl:when>
|
|
114
|
+
<xsl:otherwise>
|
|
115
|
+
<xsl:value-of select="$text" />
|
|
116
|
+
<xsl:text>
</xsl:text>
|
|
117
|
+
</xsl:otherwise>
|
|
118
|
+
</xsl:choose>
|
|
119
|
+
</xsl:template>
|
|
120
|
+
|
|
121
|
+
<!-- Trim all totally whitespace lines from beginning of code hunk -->
|
|
122
|
+
<!-- preserve-intentional removes all whitespace through first -->
|
|
123
|
+
<!-- newline (inclusive) and preserves the rest. -->
|
|
124
|
+
<xsl:template name="trim-start-lines">
|
|
125
|
+
<xsl:param name="text"/>
|
|
126
|
+
<xsl:param name="pad" select="''"/>
|
|
127
|
+
<xsl:param name="preserve-intentional" select="false()" />
|
|
128
|
+
<xsl:variable name="first-char" select="substring($text, 1, 1)" />
|
|
129
|
+
<xsl:choose>
|
|
130
|
+
<!-- Possibly nothing, return just final carriage return -->
|
|
131
|
+
<xsl:when test="$first-char=''">
|
|
132
|
+
<xsl:text>
</xsl:text>
|
|
133
|
+
</xsl:when>
|
|
134
|
+
<xsl:when test="$first-char='
'">
|
|
135
|
+
<xsl:choose>
|
|
136
|
+
<xsl:when test="$preserve-intentional=true()">
|
|
137
|
+
<xsl:value-of select="substring($text, 2)" />
|
|
138
|
+
</xsl:when>
|
|
139
|
+
<xsl:otherwise>
|
|
140
|
+
<xsl:call-template name="trim-start-lines">
|
|
141
|
+
<xsl:with-param name="text" select="substring($text, 2)" />
|
|
142
|
+
</xsl:call-template>
|
|
143
|
+
</xsl:otherwise>
|
|
144
|
+
</xsl:choose>
|
|
145
|
+
</xsl:when>
|
|
146
|
+
<xsl:when test="contains($whitespaces, $first-char)">
|
|
147
|
+
<xsl:call-template name="trim-start-lines">
|
|
148
|
+
<xsl:with-param name="text" select="substring($text, 2)" />
|
|
149
|
+
<xsl:with-param name="pad" select="concat($pad, $first-char)" />
|
|
150
|
+
<xsl:with-param name="preserve-intentional" select="$preserve-intentional" />
|
|
151
|
+
</xsl:call-template>
|
|
152
|
+
</xsl:when>
|
|
153
|
+
<xsl:otherwise>
|
|
154
|
+
<xsl:value-of select="concat($pad, $text)" />
|
|
155
|
+
</xsl:otherwise>
|
|
156
|
+
</xsl:choose>
|
|
157
|
+
</xsl:template>
|
|
158
|
+
|
|
159
|
+
<!-- Compute length of indentation of first line -->
|
|
160
|
+
<!-- Assumes no leading blank lines -->
|
|
161
|
+
<xsl:template name="count-pad-length">
|
|
162
|
+
<xsl:param name="text"/>
|
|
163
|
+
<xsl:param name="index" select="1"/>
|
|
164
|
+
<xsl:variable name="first-char" select="substring($text, $index, 1)" />
|
|
165
|
+
<xsl:choose>
|
|
166
|
+
<!-- reached end of string or newline... bail out -->
|
|
167
|
+
<xsl:when test="$first-char = '' or $first-char = '
'">
|
|
168
|
+
<xsl:value-of select="$index - 1"/>
|
|
169
|
+
</xsl:when>
|
|
170
|
+
<xsl:when test="contains($whitespaces, $first-char)">
|
|
171
|
+
<xsl:call-template name="count-pad-length">
|
|
172
|
+
<xsl:with-param name="text" select="$text" />
|
|
173
|
+
<xsl:with-param name="index" select="$index + 1" />
|
|
174
|
+
</xsl:call-template>
|
|
175
|
+
</xsl:when>
|
|
176
|
+
<xsl:otherwise>
|
|
177
|
+
<xsl:value-of select="$index - 1" />
|
|
178
|
+
</xsl:otherwise>
|
|
179
|
+
</xsl:choose>
|
|
180
|
+
</xsl:template>
|
|
181
|
+
|
|
182
|
+
<!-- Compute width of left margin -->
|
|
183
|
+
<!-- Assumes each line ends in a newline -->
|
|
184
|
+
<!-- A blank line will not contribute -->
|
|
185
|
+
<!-- Intentionally non-recursive to avoid recursion depth issues -->
|
|
186
|
+
<!-- on long code samples -->
|
|
187
|
+
<xsl:template name="left-margin">
|
|
188
|
+
<xsl:param name="text" />
|
|
189
|
+
|
|
190
|
+
<!-- construct a variable that is just a list of padding counts -->
|
|
191
|
+
<!-- as pad nodes -->
|
|
192
|
+
<xsl:variable name="lines" select="str:tokenize($text, '
')" />
|
|
193
|
+
<xsl:variable name="pad-counts-rtf">
|
|
194
|
+
<xsl:for-each select="$lines">
|
|
195
|
+
<!-- str:tokenize in current implementation does not produce -->
|
|
196
|
+
<!-- zero-length strings. (e.g. string between two newlines) -->
|
|
197
|
+
<!-- but that appears to differ between implementations, so -->
|
|
198
|
+
<!-- guard against it -->
|
|
199
|
+
<xsl:if test=". != ''">
|
|
200
|
+
<pad>
|
|
201
|
+
<xsl:call-template name="count-pad-length">
|
|
202
|
+
<xsl:with-param name="text" select="." />
|
|
203
|
+
</xsl:call-template>
|
|
204
|
+
</pad>
|
|
205
|
+
</xsl:if>
|
|
206
|
+
</xsl:for-each>
|
|
207
|
+
</xsl:variable>
|
|
208
|
+
<xsl:variable name="pad-counts" select="exsl:node-set($pad-counts-rtf)"/>
|
|
209
|
+
|
|
210
|
+
<!-- grab minimum value from list-->
|
|
211
|
+
<xsl:variable name="min-pad" select="math:min($pad-counts/pad)" />
|
|
212
|
+
|
|
213
|
+
<!-- min-pad will be NaN if there was nothing to count -->
|
|
214
|
+
<xsl:choose>
|
|
215
|
+
<xsl:when test="string($min-pad)='NaN'">
|
|
216
|
+
<xsl:value-of select="0" />
|
|
217
|
+
</xsl:when>
|
|
218
|
+
<xsl:otherwise>
|
|
219
|
+
<xsl:value-of select="$min-pad" />
|
|
220
|
+
</xsl:otherwise>
|
|
221
|
+
</xsl:choose>
|
|
222
|
+
</xsl:template>
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
<!-- Divide and conquer strip-indentation -->
|
|
226
|
+
<!-- Appropriate for long chunks of text. Minimal overhead on small -->
|
|
227
|
+
<!-- chunks of text. -->
|
|
228
|
+
<!-- An "out-dented" line is assumed to be intermediate blank line -->
|
|
229
|
+
<!-- indent parameter is a number giving number of characters to strip -->
|
|
230
|
+
<xsl:template name="strip-indentation">
|
|
231
|
+
<xsl:param name="text" />
|
|
232
|
+
<xsl:param name="indent" />
|
|
233
|
+
|
|
234
|
+
<!-- string length at which to give up divide and conquer -->
|
|
235
|
+
<xsl:variable name="divide-threshold" select="500" />
|
|
236
|
+
|
|
237
|
+
<xsl:variable name="text-len" select="string-length($text)" />
|
|
238
|
+
<xsl:choose>
|
|
239
|
+
<!-- short string, hand off to line by line algorithm -->
|
|
240
|
+
<xsl:when test="$divide-threshold > $text-len">
|
|
241
|
+
<xsl:call-template name="strip-indentation-core">
|
|
242
|
+
<xsl:with-param name="text" select="$text" />
|
|
243
|
+
<xsl:with-param name="indent" select="$indent" />
|
|
244
|
+
</xsl:call-template>
|
|
245
|
+
</xsl:when>
|
|
246
|
+
<xsl:otherwise>
|
|
247
|
+
<!-- Cut string in half -->
|
|
248
|
+
<xsl:variable name="cut-location" select="floor(string-length($text) div 2)"/>
|
|
249
|
+
<xsl:variable name="first-half" select="substring($text, 1, $cut-location)"/>
|
|
250
|
+
<xsl:variable name="second-half" select="substring($text, $cut-location + 1)"/>
|
|
251
|
+
<!-- First half needs to take on everything before first newline -->
|
|
252
|
+
<!-- in second-half and have a trailing newline -->
|
|
253
|
+
<xsl:variable name="first-half-augmented" select="concat($first-half, substring-before($second-half, '
'), '
')"/>
|
|
254
|
+
<!-- Second half only gets text after the first newline in it -->
|
|
255
|
+
<xsl:variable name="second-half-augmented" select="substring-after($second-half, '
')"/>
|
|
256
|
+
|
|
257
|
+
<!-- Stop dividing? -->
|
|
258
|
+
<xsl:choose>
|
|
259
|
+
<xsl:when test="$second-half-augmented = ''">
|
|
260
|
+
<!-- Nothing in second half (can happen with really long lines) -->
|
|
261
|
+
<!-- Give up and hand first half to line-by-line -->
|
|
262
|
+
<xsl:call-template name="strip-indentation-core">
|
|
263
|
+
<xsl:with-param name="text" select="$first-half-augmented" />
|
|
264
|
+
<xsl:with-param name="indent" select="$indent" />
|
|
265
|
+
</xsl:call-template>
|
|
266
|
+
</xsl:when>
|
|
267
|
+
<xsl:otherwise>
|
|
268
|
+
<!-- Recurse on each half -->
|
|
269
|
+
<xsl:call-template name="strip-indentation">
|
|
270
|
+
<xsl:with-param name="text" select="$first-half-augmented" />
|
|
271
|
+
<xsl:with-param name="indent" select="$indent" />
|
|
272
|
+
</xsl:call-template>
|
|
273
|
+
<xsl:call-template name="strip-indentation">
|
|
274
|
+
<xsl:with-param name="text" select="$second-half-augmented" />
|
|
275
|
+
<xsl:with-param name="indent" select="$indent" />
|
|
276
|
+
</xsl:call-template>
|
|
277
|
+
</xsl:otherwise>
|
|
278
|
+
</xsl:choose>
|
|
279
|
+
</xsl:otherwise>
|
|
280
|
+
</xsl:choose>
|
|
281
|
+
</xsl:template>
|
|
282
|
+
|
|
283
|
+
<!-- Line by line strip-indentation -->
|
|
284
|
+
<!-- should only be called on shortish chunks of text -->
|
|
285
|
+
<!-- (dozens of lines not hundreds) -->
|
|
286
|
+
<!-- An "out-dented" line is assumed to be intermediate blank line -->
|
|
287
|
+
<!-- indent parameter is a number giving number of characters to strip -->
|
|
288
|
+
<xsl:template name="strip-indentation-core">
|
|
289
|
+
<xsl:param name="text" />
|
|
290
|
+
<xsl:param name="indent" />
|
|
291
|
+
<xsl:if test="$text != ''">
|
|
292
|
+
<xsl:variable name="first-line" select="substring-before($text, '
')" />
|
|
293
|
+
<xsl:if test="string-length($first-line) > $indent" >
|
|
294
|
+
<xsl:value-of select="substring($first-line, $indent + 1)" />
|
|
295
|
+
</xsl:if>
|
|
296
|
+
<xsl:text>
</xsl:text>
|
|
297
|
+
<xsl:call-template name="strip-indentation-core">
|
|
298
|
+
<xsl:with-param name="text" select="substring-after($text, '
')" />
|
|
299
|
+
<xsl:with-param name="indent" select="$indent" />
|
|
300
|
+
</xsl:call-template>
|
|
301
|
+
</xsl:if>
|
|
302
|
+
</xsl:template>
|
|
303
|
+
|
|
304
|
+
<!-- Add a common string in front of every line of a block -->
|
|
305
|
+
<!-- Typically spaces to format output block for doctest -->
|
|
306
|
+
<!-- indent parameter is a string -->
|
|
307
|
+
<!-- Assumes last character is xA -->
|
|
308
|
+
<!-- Result has trailing xA -->
|
|
309
|
+
<xsl:template name="add-indentation">
|
|
310
|
+
<xsl:param name="text" />
|
|
311
|
+
<xsl:param name="indent" />
|
|
312
|
+
<xsl:if test="$text != ''">
|
|
313
|
+
<xsl:value-of select="concat($indent,substring-before($text, '
'))" />
|
|
314
|
+
<xsl:text>
</xsl:text>
|
|
315
|
+
<xsl:call-template name="add-indentation">
|
|
316
|
+
<xsl:with-param name="text" select="substring-after($text, '
')" />
|
|
317
|
+
<xsl:with-param name="indent" select="$indent" />
|
|
318
|
+
</xsl:call-template>
|
|
319
|
+
</xsl:if>
|
|
320
|
+
</xsl:template>
|
|
321
|
+
|
|
322
|
+
<!-- Shift all lines in text to the left far enough that -->
|
|
323
|
+
<!-- line with the least indentation is at the left margin -->
|
|
324
|
+
<xsl:template name="left-align-text">
|
|
325
|
+
<xsl:param name="text" />
|
|
326
|
+
<xsl:variable name="left-margin">
|
|
327
|
+
<xsl:call-template name="left-margin">
|
|
328
|
+
<xsl:with-param name="text" select="$text" />
|
|
329
|
+
</xsl:call-template>
|
|
330
|
+
</xsl:variable>
|
|
331
|
+
<xsl:variable name="stripped-text">
|
|
332
|
+
<xsl:call-template name="strip-indentation">
|
|
333
|
+
<!-- strip-indentation requires trailing newline -->
|
|
334
|
+
<!-- add one here and trim it when done -->
|
|
335
|
+
<xsl:with-param name="text" select="concat($text, '
')" />
|
|
336
|
+
<xsl:with-param name="indent" select="$left-margin" />
|
|
337
|
+
</xsl:call-template>
|
|
338
|
+
</xsl:variable>
|
|
339
|
+
<!-- produce value without the added newline -->
|
|
340
|
+
<xsl:value-of select="substring($stripped-text, 1, string-length($stripped-text) - 1)" />
|
|
341
|
+
</xsl:template>
|
|
342
|
+
|
|
343
|
+
|
|
344
|
+
<!-- Main template for cleaning up hunks of raw text -->
|
|
345
|
+
<!-- -->
|
|
346
|
+
<!-- 1) Trim all trailing whitespace -->
|
|
347
|
+
<!-- 2) Add carriage return marker to last line -->
|
|
348
|
+
<!-- 3) Strip all totally blank leading lines -->
|
|
349
|
+
<!-- 4) Determine indentation of left-most non-blank line -->
|
|
350
|
+
<!-- 5) Strip indentation from all lines -->
|
|
351
|
+
<!-- 6) Allow intermediate blank lines -->
|
|
352
|
+
|
|
353
|
+
<xsl:template name="sanitize-text">
|
|
354
|
+
<xsl:param name="text" />
|
|
355
|
+
<xsl:param name="preserve-end" select="false()" />
|
|
356
|
+
<xsl:param name="preserve-start" select="false()" />
|
|
357
|
+
<xsl:variable name="trimmed-text">
|
|
358
|
+
<xsl:call-template name="trim-start-lines">
|
|
359
|
+
<xsl:with-param name="text">
|
|
360
|
+
<xsl:call-template name="trim-end">
|
|
361
|
+
<xsl:with-param name="text" select="$text" />
|
|
362
|
+
<xsl:with-param name="preserve-intentional" select="$preserve-end" />
|
|
363
|
+
</xsl:call-template>
|
|
364
|
+
</xsl:with-param>
|
|
365
|
+
<xsl:with-param name="preserve-intentional" select="$preserve-start" />
|
|
366
|
+
</xsl:call-template>
|
|
367
|
+
</xsl:variable>
|
|
368
|
+
<xsl:call-template name="left-align-text" >
|
|
369
|
+
<xsl:with-param name="text" select="$trimmed-text" />
|
|
370
|
+
</xsl:call-template>
|
|
371
|
+
</xsl:template>
|
|
372
|
+
|
|
373
|
+
<!-- Substrings at last markers -->
|
|
374
|
+
<!-- XSLT Cookbook, 2nd Edition -->
|
|
375
|
+
<!-- Copyright 2006, O'Reilly Media, Inc. -->
|
|
376
|
+
<!-- Recipe 2.4, nearly verbatim, reformatted -->
|
|
377
|
+
<xsl:template name="substring-before-last-iterative">
|
|
378
|
+
<xsl:param name="input" />
|
|
379
|
+
<xsl:param name="substr" />
|
|
380
|
+
<xsl:if test="$substr and contains($input, $substr)">
|
|
381
|
+
<xsl:variable name="temp" select="substring-after($input, $substr)" />
|
|
382
|
+
<xsl:value-of select="substring-before($input, $substr)" />
|
|
383
|
+
<xsl:if test="contains($temp, $substr)">
|
|
384
|
+
<xsl:value-of select="$substr" />
|
|
385
|
+
<xsl:call-template name="substring-before-last-iterative">
|
|
386
|
+
<xsl:with-param name="input" select="$temp" />
|
|
387
|
+
<xsl:with-param name="substr" select="$substr" />
|
|
388
|
+
</xsl:call-template>
|
|
389
|
+
</xsl:if>
|
|
390
|
+
</xsl:if>
|
|
391
|
+
</xsl:template>
|
|
392
|
+
|
|
393
|
+
<!-- Substrings at last markers -->
|
|
394
|
+
<!-- Approach - keep throwing away the first half of the string -->
|
|
395
|
+
<!-- until we reach a point where one more slice would result -->
|
|
396
|
+
<!-- in no more copies of substr. Produce everything that was -->
|
|
397
|
+
<!-- sliced, then let iterative version handle the rest. -->
|
|
398
|
+
<!-- Implemented mostly to prevent lxml from dying due to -->
|
|
399
|
+
<!-- depth limit when processing large strings -->
|
|
400
|
+
<xsl:template name="substring-before-last">
|
|
401
|
+
<xsl:param name="input" />
|
|
402
|
+
<xsl:param name="substr" />
|
|
403
|
+
|
|
404
|
+
<xsl:variable name="mid-index" select="ceiling(string-length($input) div 2)"/>
|
|
405
|
+
<xsl:variable name="front" select="substring($input, 1, $mid-index)"/>
|
|
406
|
+
<xsl:variable name="back" select="substring($input, $mid-index + 1)"/>
|
|
407
|
+
|
|
408
|
+
<xsl:choose>
|
|
409
|
+
<xsl:when test="contains($back, $substr)">
|
|
410
|
+
<!-- Need front for sure, recurse on back -->
|
|
411
|
+
<xsl:value-of select="$front" />
|
|
412
|
+
<xsl:call-template name="substring-before-last">
|
|
413
|
+
<xsl:with-param name="input" select="$back" />
|
|
414
|
+
<xsl:with-param name="substr" select="$substr" />
|
|
415
|
+
</xsl:call-template>
|
|
416
|
+
</xsl:when>
|
|
417
|
+
<xsl:otherwise>
|
|
418
|
+
<!-- substr might be in front, or bridging front and back -->
|
|
419
|
+
<!-- hand off entire string to iterative version -->
|
|
420
|
+
<xsl:call-template name="substring-before-last-iterative">
|
|
421
|
+
<xsl:with-param name="input" select="$input" />
|
|
422
|
+
<xsl:with-param name="substr" select="$substr" />
|
|
423
|
+
</xsl:call-template>
|
|
424
|
+
</xsl:otherwise>
|
|
425
|
+
</xsl:choose>
|
|
426
|
+
</xsl:template>
|
|
427
|
+
|
|
428
|
+
|
|
429
|
+
<!-- substring from $input after first instance of $substr -->
|
|
430
|
+
<!-- if no match, returns original string -->
|
|
431
|
+
<!-- similar to substring-after() function but preserves original -->
|
|
432
|
+
<xsl:template name="substring-after-preserve">
|
|
433
|
+
<xsl:param name="input"/>
|
|
434
|
+
<xsl:param name="substr"/>
|
|
435
|
+
<!-- Extract the string which comes after the first occurrence -->
|
|
436
|
+
<xsl:variable name="temp" select="substring-after($input,$substr)"/>
|
|
437
|
+
<xsl:choose>
|
|
438
|
+
<xsl:when test="$temp = ''">
|
|
439
|
+
<xsl:value-of select="$input"/>
|
|
440
|
+
</xsl:when>
|
|
441
|
+
<xsl:otherwise>
|
|
442
|
+
<xsl:value-of select="$temp"/>
|
|
443
|
+
</xsl:otherwise>
|
|
444
|
+
</xsl:choose>
|
|
445
|
+
</xsl:template>
|
|
446
|
+
|
|
447
|
+
<!-- If the substring is not contained, the first substring-after() -->
|
|
448
|
+
<!-- will return empty and entire template will return empty. To -->
|
|
449
|
+
<!-- get the whole string, prepend $input with $substr prior to using -->
|
|
450
|
+
<xsl:template name="substring-after-last">
|
|
451
|
+
<xsl:param name="input"/>
|
|
452
|
+
<xsl:param name="substr"/>
|
|
453
|
+
<!-- Extract the string which comes after the first occurrence -->
|
|
454
|
+
<xsl:variable name="temp" select="substring-after($input,$substr)"/>
|
|
455
|
+
<xsl:choose>
|
|
456
|
+
<!-- If it still contains the search string then recursively process -->
|
|
457
|
+
<xsl:when test="$substr and contains($temp,$substr)">
|
|
458
|
+
<xsl:call-template name="substring-after-last">
|
|
459
|
+
<xsl:with-param name="input" select="$temp"/>
|
|
460
|
+
<xsl:with-param name="substr" select="$substr"/>
|
|
461
|
+
</xsl:call-template>
|
|
462
|
+
</xsl:when>
|
|
463
|
+
<xsl:otherwise>
|
|
464
|
+
<xsl:value-of select="$temp"/>
|
|
465
|
+
</xsl:otherwise>
|
|
466
|
+
</xsl:choose>
|
|
467
|
+
</xsl:template>
|
|
468
|
+
|
|
469
|
+
<!-- Duplicating Strings -->
|
|
470
|
+
<!-- XSLT Cookbook, 2nd Edition -->
|
|
471
|
+
<!-- Copyright 2006, O'Reilly Media, Inc. -->
|
|
472
|
+
<!-- Recipe 2.5, nearly verbatim, reformatted -->
|
|
473
|
+
<xsl:template name="duplicate-string">
|
|
474
|
+
<xsl:param name="text" />
|
|
475
|
+
<xsl:param name="count" select="1" />
|
|
476
|
+
<xsl:choose>
|
|
477
|
+
<xsl:when test="not($count) or not($text)" />
|
|
478
|
+
<xsl:when test="$count = 1">
|
|
479
|
+
<xsl:value-of select="$text" />
|
|
480
|
+
</xsl:when>
|
|
481
|
+
<xsl:otherwise>
|
|
482
|
+
<!-- If $count is odd, append one copy of input -->
|
|
483
|
+
<xsl:if test="$count mod 2">
|
|
484
|
+
<xsl:value-of select="$text" />
|
|
485
|
+
</xsl:if>
|
|
486
|
+
<!-- Recursively apply template, after -->
|
|
487
|
+
<!-- doubling input and halving count -->
|
|
488
|
+
<xsl:call-template name="duplicate-string">
|
|
489
|
+
<xsl:with-param name="text" select="concat($text,$text)" />
|
|
490
|
+
<xsl:with-param name="count" select="floor($count div 2)" />
|
|
491
|
+
</xsl:call-template>
|
|
492
|
+
</xsl:otherwise>
|
|
493
|
+
</xsl:choose>
|
|
494
|
+
</xsl:template>
|
|
495
|
+
|
|
496
|
+
<!-- Prepending Strings -->
|
|
497
|
+
<!-- Add count copies of the string pad to each line of text -->
|
|
498
|
+
<!-- Presumes text has a newline character at the very end -->
|
|
499
|
+
<xsl:template name="prepend-string">
|
|
500
|
+
<xsl:param name="text" />
|
|
501
|
+
<xsl:param name="pad" />
|
|
502
|
+
<xsl:param name="count" select="1" />
|
|
503
|
+
<xsl:variable name="bigpad">
|
|
504
|
+
<xsl:call-template name="duplicate-string">
|
|
505
|
+
<xsl:with-param name="text" select="$pad" />
|
|
506
|
+
<xsl:with-param name="count" select="$count" />
|
|
507
|
+
</xsl:call-template>
|
|
508
|
+
</xsl:variable>
|
|
509
|
+
<!-- Quit when string becomes empty -->
|
|
510
|
+
<xsl:if test="string-length($text)">
|
|
511
|
+
<xsl:variable name="first-line" select="substring-before($text, '
')" />
|
|
512
|
+
<xsl:value-of select="$bigpad" />
|
|
513
|
+
<xsl:value-of select="$first-line" />
|
|
514
|
+
<xsl:text>
</xsl:text>
|
|
515
|
+
<!-- recursive call on remaining lines -->
|
|
516
|
+
<xsl:call-template name="prepend-string">
|
|
517
|
+
<xsl:with-param name="text" select="substring-after($text, '
')" />
|
|
518
|
+
<xsl:with-param name="pad" select="$bigpad" />
|
|
519
|
+
<xsl:with-param name="count" select="1" />
|
|
520
|
+
</xsl:call-template>
|
|
521
|
+
</xsl:if>
|
|
522
|
+
</xsl:template>
|
|
523
|
+
|
|
524
|
+
<!-- Counting Substrings -->
|
|
525
|
+
<xsl:template name="count-substring">
|
|
526
|
+
<xsl:param name="text" />
|
|
527
|
+
<xsl:param name="word" />
|
|
528
|
+
<xsl:param name="count" select="'0'" />
|
|
529
|
+
<xsl:choose>
|
|
530
|
+
<xsl:when test="not(contains($text, $word))">
|
|
531
|
+
<xsl:value-of select="$count" />
|
|
532
|
+
</xsl:when>
|
|
533
|
+
<xsl:otherwise>
|
|
534
|
+
<xsl:call-template name="count-substring">
|
|
535
|
+
<xsl:with-param name="text" select="substring-after($text, $word)" />
|
|
536
|
+
<xsl:with-param name="word" select="$word" />
|
|
537
|
+
<xsl:with-param name="count" select="$count + 1" />
|
|
538
|
+
</xsl:call-template>
|
|
539
|
+
</xsl:otherwise>
|
|
540
|
+
</xsl:choose>
|
|
541
|
+
</xsl:template>
|
|
542
|
+
|
|
543
|
+
<!-- Remove empty lines -->
|
|
544
|
+
<!-- These are lines with no characters -->
|
|
545
|
+
<!-- at all, just a newline -->
|
|
546
|
+
<!-- 2017-01-22: UNUSED, UNTESTED, incorporate with caution -->
|
|
547
|
+
<xsl:template name="strip-empty-lines">
|
|
548
|
+
<xsl:param name="text" />
|
|
549
|
+
<xsl:choose>
|
|
550
|
+
<!-- no more splitting, output $text, empty or not -->
|
|
551
|
+
<xsl:when test="not(contains($text, '
'))">
|
|
552
|
+
<xsl:value-of select="$text" />
|
|
553
|
+
</xsl:when>
|
|
554
|
+
<xsl:otherwise>
|
|
555
|
+
<xsl:variable name="firstline" select="substring-before($text, '
')" />
|
|
556
|
+
<xsl:choose>
|
|
557
|
+
<!-- silently drop an empty line, newline already gone -->
|
|
558
|
+
<xsl:when test="not($firstline)" />
|
|
559
|
+
<!-- output first line with restored newline -->
|
|
560
|
+
<xsl:otherwise>
|
|
561
|
+
<xsl:value-of select="concat($firstline, '
')" />
|
|
562
|
+
</xsl:otherwise>
|
|
563
|
+
</xsl:choose>
|
|
564
|
+
<!-- recurse with remainder -->
|
|
565
|
+
<xsl:call-template name="strip-empty-lines">
|
|
566
|
+
<xsl:with-param name="text" select="substring-after($text, '
')" />
|
|
567
|
+
</xsl:call-template>
|
|
568
|
+
</xsl:otherwise>
|
|
569
|
+
</xsl:choose>
|
|
570
|
+
</xsl:template>
|
|
571
|
+
|
|
572
|
+
<!-- Merge consecutive empty lines -->
|
|
573
|
+
<!-- In other words, if there are three or more consecutive newline -->
|
|
574
|
+
<!-- characters, replace them with just two newline characters. -->
|
|
575
|
+
<xsl:template name="consolidate-empty-lines">
|
|
576
|
+
<xsl:param name="text" />
|
|
577
|
+
<xsl:choose>
|
|
578
|
+
<xsl:when test="not(contains($text, '


'))">
|
|
579
|
+
<xsl:value-of select="$text" />
|
|
580
|
+
</xsl:when>
|
|
581
|
+
<xsl:otherwise>
|
|
582
|
+
<xsl:call-template name="consolidate-empty-lines">
|
|
583
|
+
<xsl:with-param name="text" select="str:replace($text,'


','

')" />
|
|
584
|
+
</xsl:call-template>
|
|
585
|
+
</xsl:otherwise>
|
|
586
|
+
</xsl:choose>
|
|
587
|
+
</xsl:template>
|
|
588
|
+
|
|
589
|
+
<!-- Gobble leading whitespace -->
|
|
590
|
+
<!-- Drop consecutive leading spaces and tabs, only -->
|
|
591
|
+
<!-- Designed for a single line as input -->
|
|
592
|
+
<!-- Used after maniplating sentence ending punctuation -->
|
|
593
|
+
<xsl:template name="strip-leading-blanks">
|
|
594
|
+
<xsl:param name="text" />
|
|
595
|
+
<xsl:variable name="first-char" select="substring($text, 1, 1)" />
|
|
596
|
+
<xsl:choose>
|
|
597
|
+
<!-- if empty, done -->
|
|
598
|
+
<xsl:when test="not($first-char)" />
|
|
599
|
+
<!-- first character is space, tab, drop it -->
|
|
600
|
+
<xsl:when test="contains(' 	', $first-char)">
|
|
601
|
+
<xsl:call-template name="strip-leading-blanks">
|
|
602
|
+
<xsl:with-param name="text" select="substring($text, 2)" />
|
|
603
|
+
</xsl:call-template>
|
|
604
|
+
</xsl:when>
|
|
605
|
+
<!-- finished stripping, output as-is -->
|
|
606
|
+
<xsl:otherwise>
|
|
607
|
+
<xsl:value-of select="$text" />
|
|
608
|
+
</xsl:otherwise>
|
|
609
|
+
</xsl:choose>
|
|
610
|
+
</xsl:template>
|
|
611
|
+
|
|
612
|
+
<!-- Shove text left -->
|
|
613
|
+
<!-- Remove all leading whitespace from every line -->
|
|
614
|
+
<!-- Note: very similar to "sanitize-latex" below -->
|
|
615
|
+
<!-- 2017-01-22: UNUSED, UNTESTED, incorporate with caution -->
|
|
616
|
+
<xsl:template name="slide-text-left">
|
|
617
|
+
<xsl:param name="text" />
|
|
618
|
+
<xsl:choose>
|
|
619
|
+
<!-- no more splitting, strip leading whitespace -->
|
|
620
|
+
<xsl:when test="not(contains($text, '
'))">
|
|
621
|
+
<xsl:call-template name="strip-leading-blanks">
|
|
622
|
+
<xsl:with-param name="text">
|
|
623
|
+
<xsl:value-of select="$text" />
|
|
624
|
+
</xsl:with-param>
|
|
625
|
+
</xsl:call-template>
|
|
626
|
+
</xsl:when>
|
|
627
|
+
<xsl:otherwise>
|
|
628
|
+
<xsl:call-template name="strip-leading-blanks">
|
|
629
|
+
<xsl:with-param name="text" select="concat(substring-before($text, '
'), '
')" />
|
|
630
|
+
</xsl:call-template>
|
|
631
|
+
<!-- recurse with remainder -->
|
|
632
|
+
<xsl:call-template name="slide-text-left">
|
|
633
|
+
<xsl:with-param name="text" select="substring-after($text, '
')" />
|
|
634
|
+
</xsl:call-template>
|
|
635
|
+
</xsl:otherwise>
|
|
636
|
+
</xsl:choose>
|
|
637
|
+
</xsl:template>
|
|
638
|
+
|
|
639
|
+
<!-- Strip whitespace after line break -->
|
|
640
|
+
<!-- A hard line-break (newline) in authors' source will typically -->
|
|
641
|
+
<!-- introduce leading whitespace (spaces) prior to the next line. -->
|
|
642
|
+
<!-- This template scrubs the spaces, but leaves the newline (which -->
|
|
643
|
+
<!-- can be dealt with by the consumer). Strategy is to replace -->
|
|
644
|
+
<!-- <newline><space> by <newline> until it cannot be done anymore. -->
|
|
645
|
+
<xsl:template name="reduce-line-break">
|
|
646
|
+
<xsl:param name="text"/>
|
|
647
|
+
|
|
648
|
+
<xsl:choose>
|
|
649
|
+
<xsl:when test="not(contains($text, '
 '))">
|
|
650
|
+
<xsl:value-of select="$text"/>
|
|
651
|
+
</xsl:when>
|
|
652
|
+
<xsl:otherwise>
|
|
653
|
+
<xsl:call-template name="reduce-line-break">
|
|
654
|
+
<xsl:with-param name="text" select="str:replace($text, '
 ', '
')"/>
|
|
655
|
+
</xsl:call-template>
|
|
656
|
+
</xsl:otherwise>
|
|
657
|
+
</xsl:choose>
|
|
658
|
+
</xsl:template>
|
|
659
|
+
|
|
660
|
+
<!-- Sanitize Nemeth Braille -->
|
|
661
|
+
<!-- We receive Nemeth braille from MathJax and Speech Rule Engine (SRE) as -->
|
|
662
|
+
<!-- -->
|
|
663
|
+
<!-- 1. Optional indentation U+2800 for second, and subsequent lines of -->
|
|
664
|
+
<!-- 2D layout display math -->
|
|
665
|
+
<!-- 2. Actual content with U+2800 as spaces -->
|
|
666
|
+
<!-- 3. An optional run of U+2800 to form a uniform right margin for -->
|
|
667
|
+
<!-- (eventual) 2D physical devices. -->
|
|
668
|
+
<!-- -->
|
|
669
|
+
<!-- To play nice with liblouis we let U+2800 be an unbreakable space -->
|
|
670
|
+
<!-- and U+0020 ("regular" space) be a breakable space. So -->
|
|
671
|
+
<!-- -->
|
|
672
|
+
<!-- 1. We preserve indentation as unbreakable spaces. -->
|
|
673
|
+
<!-- 2. We convert content spaces to "regular" spaces. In some cases -->
|
|
674
|
+
<!-- we make convert them back to unbreakable spaces. -->
|
|
675
|
+
<!-- 3. We drop trailing (right margin) whitespace, as unnecessary, -->
|
|
676
|
+
<!-- and even problematic. -->
|
|
677
|
+
|
|
678
|
+
|
|
679
|
+
<!-- Break on newlines. Trim trailing whitespace, massage whitespace in -->
|
|
680
|
+
<!-- remainder. Reconstitute with same patter of newlines. Note: for -->
|
|
681
|
+
<!-- single-line braille from SRE there is no indentation and no trailing -->
|
|
682
|
+
<!-- whitespace for a right margin. -->
|
|
683
|
+
<!-- NB: "otherwise" might be simpler if some conditioning was different -->
|
|
684
|
+
<!-- in the "when. -->
|
|
685
|
+
|
|
686
|
+
<xsl:template name="sanitize-nemeth-braille">
|
|
687
|
+
<xsl:param name="text"/>
|
|
688
|
+
<xsl:choose>
|
|
689
|
+
<xsl:when test="contains($text, '
')">
|
|
690
|
+
<xsl:variable name="one-line" select="substring-before($text, '
')"/>
|
|
691
|
+
<!-- strip end of a single line of U+2800, a braille empty cell -->
|
|
692
|
+
<xsl:variable name="end-trimmed">
|
|
693
|
+
<xsl:call-template name="trim-nemeth-trailing-whitespace">
|
|
694
|
+
<xsl:with-param name="text" select="$one-line"/>
|
|
695
|
+
</xsl:call-template>
|
|
696
|
+
</xsl:variable>
|
|
697
|
+
<xsl:call-template name="convert-nemeth-whitespace">
|
|
698
|
+
<xsl:with-param name="text" select="$end-trimmed"/>
|
|
699
|
+
</xsl:call-template>
|
|
700
|
+
<!-- restore "split-out" newline -->
|
|
701
|
+
<xsl:text>
</xsl:text>
|
|
702
|
+
<!-- recursively process remainder -->
|
|
703
|
+
<xsl:call-template name="sanitize-nemeth-braille">
|
|
704
|
+
<xsl:with-param name="text" select="substring-after($text, '
')"/>
|
|
705
|
+
</xsl:call-template>
|
|
706
|
+
</xsl:when>
|
|
707
|
+
<xsl:otherwise>
|
|
708
|
+
<!-- last line, needs manipulation -->
|
|
709
|
+
<xsl:variable name="end-trimmed">
|
|
710
|
+
<xsl:call-template name="trim-nemeth-trailing-whitespace">
|
|
711
|
+
<xsl:with-param name="text" select="$text"/>
|
|
712
|
+
</xsl:call-template>
|
|
713
|
+
</xsl:variable>
|
|
714
|
+
<xsl:call-template name="convert-nemeth-whitespace">
|
|
715
|
+
<xsl:with-param name="text" select="$end-trimmed"/>
|
|
716
|
+
</xsl:call-template>
|
|
717
|
+
<!-- no newline to restore -->
|
|
718
|
+
</xsl:otherwise>
|
|
719
|
+
</xsl:choose>
|
|
720
|
+
</xsl:template>
|
|
721
|
+
|
|
722
|
+
<!-- Work in from right margin, dropping consecutive U+2800 -->
|
|
723
|
+
<xsl:template name="trim-nemeth-trailing-whitespace">
|
|
724
|
+
<xsl:param name="text"/>
|
|
725
|
+
<xsl:variable name="last-char" select="substring($text, string-length($text), 1)" />
|
|
726
|
+
<xsl:choose>
|
|
727
|
+
<xsl:when test="$last-char = '⠀'">
|
|
728
|
+
<xsl:call-template name="trim-nemeth-trailing-whitespace">
|
|
729
|
+
<xsl:with-param name="text" select="substring($text, 1, string-length($text) - 1)" />
|
|
730
|
+
</xsl:call-template>
|
|
731
|
+
</xsl:when>
|
|
732
|
+
<xsl:otherwise>
|
|
733
|
+
<xsl:value-of select="$text" />
|
|
734
|
+
</xsl:otherwise>
|
|
735
|
+
</xsl:choose>
|
|
736
|
+
</xsl:template>
|
|
737
|
+
|
|
738
|
+
<!-- Work in from the left. The $b-indentation boolean signals that -->
|
|
739
|
+
<!-- the last character examined was a U+2800 from the run of indentation -->
|
|
740
|
+
<!-- (which we simply duplicate). It begins true as the default value, -->
|
|
741
|
+
<!-- which is not present in initial call. Once it flips false, it stays -->
|
|
742
|
+
<!-- false. Spaces within content convert to "regular" spaces. -->
|
|
743
|
+
<!-- Note: once $b-indentation flips false, we could just do a -->
|
|
744
|
+
<!-- search/replace on the string to output with a "value-of" -->
|
|
745
|
+
|
|
746
|
+
<xsl:template name="convert-nemeth-whitespace">
|
|
747
|
+
<xsl:param name="text"/>
|
|
748
|
+
<xsl:param name="b-indentation" select="true()"/>
|
|
749
|
+
|
|
750
|
+
<xsl:choose>
|
|
751
|
+
<xsl:when test="$text">
|
|
752
|
+
<xsl:variable name="first-char" select="substring($text, 1, 1)"/>
|
|
753
|
+
<xsl:variable name="b-found-indentation" select="$b-indentation and ($first-char = '⠀')"/>
|
|
754
|
+
<xsl:choose>
|
|
755
|
+
<!-- echo a leading U+2800 in the indentation-->
|
|
756
|
+
<xsl:when test="$b-found-indentation">
|
|
757
|
+
<xsl:text>⠀</xsl:text>
|
|
758
|
+
</xsl:when>
|
|
759
|
+
<!-- convert space in content into a regular space -->
|
|
760
|
+
<xsl:when test="$first-char = '⠀'">
|
|
761
|
+
<xsl:text> </xsl:text>
|
|
762
|
+
</xsl:when>
|
|
763
|
+
<!-- echo any other character -->
|
|
764
|
+
<xsl:otherwise>
|
|
765
|
+
<xsl:value-of select="$first-char"/>
|
|
766
|
+
</xsl:otherwise>
|
|
767
|
+
</xsl:choose>
|
|
768
|
+
<!-- Recurse with all but the first character -->
|
|
769
|
+
<xsl:call-template name="convert-nemeth-whitespace">
|
|
770
|
+
<xsl:with-param name="text" select="substring($text, 2, string-length($text) - 1)"/>
|
|
771
|
+
<xsl:with-param name="b-indentation" select="$b-found-indentation"/>
|
|
772
|
+
</xsl:call-template>
|
|
773
|
+
</xsl:when>
|
|
774
|
+
<!-- $text is empty string, done -->
|
|
775
|
+
<xsl:otherwise/>
|
|
776
|
+
</xsl:choose>
|
|
777
|
+
</xsl:template>
|
|
778
|
+
|
|
779
|
+
|
|
780
|
+
<!-- Sanitize LaTex -->
|
|
781
|
+
<!-- We allow authors to include whitespace for readability -->
|
|
782
|
+
<!-- -->
|
|
783
|
+
<!-- (1) Newlines used to format complicated math (eg matrices) -->
|
|
784
|
+
<!-- (2) Newlines used to avoid word-wrapping in editing tools -->
|
|
785
|
+
<!-- (3) Newlines to support atomic version control changesets -->
|
|
786
|
+
<!-- (4) Source indentation of above, consonant with XML indentation -->
|
|
787
|
+
<!-- -->
|
|
788
|
+
<!-- But once we form LaTeX output we want to -->
|
|
789
|
+
<!-- -->
|
|
790
|
+
<!-- (i) Remove 100% whitespace lines -->
|
|
791
|
+
<!-- (ii) Remove leading whitespace -->
|
|
792
|
+
<!-- (iii) Finish without a newline -->
|
|
793
|
+
<!-- -->
|
|
794
|
+
<!-- So we -->
|
|
795
|
+
<!-- -->
|
|
796
|
+
<!-- (a) Strip all leading whitespace -->
|
|
797
|
+
<!-- (b) Remove any 100% resulting empty lines (newline only) -->
|
|
798
|
+
<!-- (c) Preserve remaining newlines (trailing after content) -->
|
|
799
|
+
<!-- (d) Preserve remaining whitespace (eg, within expressions) -->
|
|
800
|
+
<!-- (e) Take care with trailing characters, except final newline -->
|
|
801
|
+
<!-- -->
|
|
802
|
+
<!-- We can do this because of the limited purposes of the -->
|
|
803
|
+
<!-- m, me, men, md, mdn elements. The whitespace we strip is not -->
|
|
804
|
+
<!-- relevant/important, and what we leave does not change output -->
|
|
805
|
+
<xsl:template name="sanitize-latex">
|
|
806
|
+
<xsl:param name="text" />
|
|
807
|
+
<xsl:variable name="first-char" select="substring($text, 1, 1)" />
|
|
808
|
+
<xsl:choose>
|
|
809
|
+
<!-- empty, end recursion -->
|
|
810
|
+
<xsl:when test="$first-char = ''" />
|
|
811
|
+
<!-- first character is whitespace, including newline -->
|
|
812
|
+
<!-- silently drop it as we recurse on remainder -->
|
|
813
|
+
<xsl:when test="contains($whitespaces, $first-char)">
|
|
814
|
+
<xsl:call-template name="sanitize-latex">
|
|
815
|
+
<xsl:with-param name="text" select="substring($text, 2)" />
|
|
816
|
+
</xsl:call-template>
|
|
817
|
+
</xsl:when>
|
|
818
|
+
<!-- content followed by newline -->
|
|
819
|
+
<!-- split, preserve newline, output, and recurse, but -->
|
|
820
|
+
<!-- drop a newline that only protects trailing whitespace -->
|
|
821
|
+
<xsl:when test="contains($text, '
')">
|
|
822
|
+
<xsl:value-of select="substring-before($text, '
')" />
|
|
823
|
+
<xsl:variable name="remainder" select="substring-after($text, '
')" />
|
|
824
|
+
<xsl:choose>
|
|
825
|
+
<xsl:when test="normalize-space($remainder) = ''" />
|
|
826
|
+
<xsl:otherwise>
|
|
827
|
+
<xsl:text>
</xsl:text>
|
|
828
|
+
<xsl:call-template name="sanitize-latex">
|
|
829
|
+
<xsl:with-param name="text" select="$remainder" />
|
|
830
|
+
</xsl:call-template>
|
|
831
|
+
</xsl:otherwise>
|
|
832
|
+
</xsl:choose>
|
|
833
|
+
</xsl:when>
|
|
834
|
+
<!-- content, no following newline -->
|
|
835
|
+
<!-- output in full, end recursion -->
|
|
836
|
+
<xsl:otherwise>
|
|
837
|
+
<xsl:value-of select="$text" />
|
|
838
|
+
</xsl:otherwise>
|
|
839
|
+
</xsl:choose>
|
|
840
|
+
</xsl:template>
|
|
841
|
+
|
|
842
|
+
<!-- This collects "clause-ending" punctuation -->
|
|
843
|
+
<!-- from the *front* of a text node. It does not -->
|
|
844
|
+
<!-- change the text node, but simply outputs the -->
|
|
845
|
+
<!-- punctuation for use by another template -->
|
|
846
|
+
<xsl:template name="leading-clause-punctuation">
|
|
847
|
+
<xsl:param name="text" />
|
|
848
|
+
<xsl:variable name="first-char" select="substring($text, 1, 1)" />
|
|
849
|
+
<xsl:choose>
|
|
850
|
+
<!-- empty, quit -->
|
|
851
|
+
<xsl:when test="not($first-char)" />
|
|
852
|
+
<!-- if punctuation, output and recurse -->
|
|
853
|
+
<!-- else silently quit recursion -->
|
|
854
|
+
<xsl:when test="contains($clause-ending-marks, $first-char)">
|
|
855
|
+
<xsl:value-of select="$first-char" />
|
|
856
|
+
<xsl:call-template name="leading-clause-punctuation">
|
|
857
|
+
<xsl:with-param name="text" select="substring($text, 2)" />
|
|
858
|
+
</xsl:call-template>
|
|
859
|
+
</xsl:when>
|
|
860
|
+
<!-- consecutive only, stop collecting -->
|
|
861
|
+
<xsl:otherwise />
|
|
862
|
+
</xsl:choose>
|
|
863
|
+
</xsl:template>
|
|
864
|
+
|
|
865
|
+
<!-- If we absorb punctuation, we need to scrub it by -->
|
|
866
|
+
<!-- examining and manipulating the text node with -->
|
|
867
|
+
<!-- those characters. We drop consecutive punctuation. -->
|
|
868
|
+
<xsl:template name="drop-clause-punctuation">
|
|
869
|
+
<xsl:param name="text" />
|
|
870
|
+
<xsl:variable name="first-char" select="substring($text, 1, 1)" />
|
|
871
|
+
<xsl:choose>
|
|
872
|
+
<!-- if empty, done -->
|
|
873
|
+
<xsl:when test="not($first-char)" />
|
|
874
|
+
<!-- first character ends sentence, drop it, recurse -->
|
|
875
|
+
<xsl:when test="contains($clause-ending-marks, $first-char)">
|
|
876
|
+
<xsl:call-template name="drop-clause-punctuation">
|
|
877
|
+
<xsl:with-param name="text" select="substring($text, 2)" />
|
|
878
|
+
</xsl:call-template>
|
|
879
|
+
</xsl:when>
|
|
880
|
+
<!-- no more punctuation, output as-is -->
|
|
881
|
+
<xsl:otherwise>
|
|
882
|
+
<xsl:value-of select="$text" />
|
|
883
|
+
</xsl:otherwise>
|
|
884
|
+
</xsl:choose>
|
|
885
|
+
</xsl:template>
|
|
886
|
+
|
|
887
|
+
<!-- Remove consecutive run of blanks and -->
|
|
888
|
+
<!-- newlines in first portion of a string -->
|
|
889
|
+
<!-- Performance audited 2024-12-15 - this is so frequently called -->
|
|
890
|
+
<!-- in the simple case (nothing to strip) that just about any -->
|
|
891
|
+
<!-- optimization for the general case ends up being slower. -->
|
|
892
|
+
<xsl:template name="strip-leading-whitespace">
|
|
893
|
+
<xsl:param name="text" />
|
|
894
|
+
<xsl:variable name="first-char" select="substring($text, 1, 1)" />
|
|
895
|
+
<xsl:choose>
|
|
896
|
+
<!-- if empty, quit -->
|
|
897
|
+
<xsl:when test="not($first-char)" />
|
|
898
|
+
<!-- if first character is whitespace, drop it -->
|
|
899
|
+
<xsl:when test="contains($whitespaces, $first-char)">
|
|
900
|
+
<xsl:call-template name="strip-leading-whitespace">
|
|
901
|
+
<xsl:with-param name="text" select="substring($text, 2)" />
|
|
902
|
+
</xsl:call-template>
|
|
903
|
+
</xsl:when>
|
|
904
|
+
<!-- else finished stripping, output as-is -->
|
|
905
|
+
<xsl:otherwise>
|
|
906
|
+
<xsl:value-of select="$text" />
|
|
907
|
+
</xsl:otherwise>
|
|
908
|
+
</xsl:choose>
|
|
909
|
+
</xsl:template>
|
|
910
|
+
|
|
911
|
+
<!-- Remove consecutive run of blanks and -->
|
|
912
|
+
<!-- newlines in last portion of a string -->
|
|
913
|
+
<!-- Performance audited 2024-12-15 - this is so frequently called -->
|
|
914
|
+
<!-- in the simple case (nothing to strip) that just about any -->
|
|
915
|
+
<!-- optimization for the general case ends up being slower. -->
|
|
916
|
+
<xsl:template name="strip-trailing-whitespace">
|
|
917
|
+
<xsl:param name="text" />
|
|
918
|
+
<xsl:variable name="last-char" select="substring($text, string-length($text), 1)" />
|
|
919
|
+
<xsl:choose>
|
|
920
|
+
<!-- if empty, quit -->
|
|
921
|
+
<xsl:when test="not($last-char)" />
|
|
922
|
+
<!-- if last character is whitespace, drop it -->
|
|
923
|
+
<xsl:when test="contains($whitespaces, $last-char)">
|
|
924
|
+
<xsl:call-template name="strip-trailing-whitespace">
|
|
925
|
+
<xsl:with-param name="text" select="substring($text, 1, string-length($text)-1)" />
|
|
926
|
+
</xsl:call-template>
|
|
927
|
+
</xsl:when>
|
|
928
|
+
<!-- else finished stripping, output as-is -->
|
|
929
|
+
<xsl:otherwise>
|
|
930
|
+
<xsl:value-of select="$text" />
|
|
931
|
+
</xsl:otherwise>
|
|
932
|
+
</xsl:choose>
|
|
933
|
+
</xsl:template>
|
|
934
|
+
|
|
935
|
+
<!-- spurious newlines introduce whitespace on either side -->
|
|
936
|
+
<!-- we split at newlines, strip consecutive whitesapce on either side, -->
|
|
937
|
+
<!-- and replace newlines by spaces (could restore a single newline) -->
|
|
938
|
+
<xsl:template name="strip-newlines">
|
|
939
|
+
<xsl:param name="text" />
|
|
940
|
+
<xsl:choose>
|
|
941
|
+
<!-- if has newline, modify newline-free front portion -->
|
|
942
|
+
<!-- replace splitting newline with new separator -->
|
|
943
|
+
<!-- modify trailing portion, and recurse with it -->
|
|
944
|
+
<xsl:when test="contains($text, '
')">
|
|
945
|
+
<!-- clean trailing portion of left half -->
|
|
946
|
+
<xsl:call-template name="strip-trailing-whitespace">
|
|
947
|
+
<xsl:with-param name="text" select="substring-before($text, '
')" />
|
|
948
|
+
</xsl:call-template>
|
|
949
|
+
<!-- restore a separator, blank now -->
|
|
950
|
+
<!-- Note: this could be a newline, perhaps optionally (whitespace="breaks") -->
|
|
951
|
+
<!-- Note: this could be " %\n" in LaTeX output to be super explicit -->
|
|
952
|
+
<xsl:text> </xsl:text>
|
|
953
|
+
<!-- recurse with modified right half -->
|
|
954
|
+
<xsl:call-template name="strip-newlines">
|
|
955
|
+
<xsl:with-param name="text">
|
|
956
|
+
<!-- clean leading portion of right half -->
|
|
957
|
+
<xsl:call-template name="strip-leading-whitespace">
|
|
958
|
+
<xsl:with-param name="text" select="substring-after($text, '
')" />
|
|
959
|
+
</xsl:call-template>
|
|
960
|
+
</xsl:with-param>
|
|
961
|
+
</xsl:call-template>
|
|
962
|
+
</xsl:when>
|
|
963
|
+
<!-- else finished stripping, output as-is -->
|
|
964
|
+
<xsl:otherwise>
|
|
965
|
+
<xsl:value-of select="$text" />
|
|
966
|
+
</xsl:otherwise>
|
|
967
|
+
</xsl:choose>
|
|
968
|
+
</xsl:template>
|
|
969
|
+
|
|
970
|
+
<!-- JSON Escaped Strings -->
|
|
971
|
+
<!-- Convert a string, just prior to dropping it into a -->
|
|
972
|
+
<!-- JSON data structure, so this presumes nothing -->
|
|
973
|
+
<!-- special has been done with the contents before-hand -->
|
|
974
|
+
<!-- In order converted, using the standard JSON names: -->
|
|
975
|
+
<!-- reverse solidus (backslash), solidus (slash), -->
|
|
976
|
+
<!-- quotation mark, backspace, horizontal tab, -->
|
|
977
|
+
<!-- newline, form feed, carriage return -->
|
|
978
|
+
<!-- Escaping solidus (forward slash) is only necessary -->
|
|
979
|
+
<!-- for <\ inside a script tag (or similar?) It makes -->
|
|
980
|
+
<!-- URLs ugly, but we do it anyway so we don't get bit. -->
|
|
981
|
+
<!-- Strictly needed: backslash, double quote, newline. -->
|
|
982
|
+
<!-- XSLT3: -->
|
|
983
|
+
<!-- But XML 1.0 does not allow x08 (backspace) and x0c -->
|
|
984
|
+
<!-- (form feed) so we ignore them for now. Perhaps see -->
|
|
985
|
+
<!-- https://stackoverflow.com/questions/404107/ -->
|
|
986
|
+
<!-- why-are-control-characters-illegal-in-xml-1-0 -->
|
|
987
|
+
|
|
988
|
+
<!-- First define the replacements. These must be in -->
|
|
989
|
+
<!-- order as search + replace pairs -->
|
|
990
|
+
<xsl:variable name="json-replacements">
|
|
991
|
+
<search>\</search>
|
|
992
|
+
<replace>\\</replace>
|
|
993
|
+
<search>/</search>
|
|
994
|
+
<replace>\/</replace>
|
|
995
|
+
<search><xsl:value-of select="string('
')"/></search>
|
|
996
|
+
<replace>\n</replace>
|
|
997
|
+
<search><xsl:value-of select="string('	')"/></search>
|
|
998
|
+
<replace>\t</replace>
|
|
999
|
+
<search><xsl:value-of select="string('
')"/></search>
|
|
1000
|
+
<replace>\r</replace>
|
|
1001
|
+
<search><xsl:value-of select="string('"')"/></search>
|
|
1002
|
+
<replace>\"</replace>
|
|
1003
|
+
</xsl:variable>
|
|
1004
|
+
<xsl:variable name="json-replacements-search-set" select="exsl:node-set($json-replacements)/search" />
|
|
1005
|
+
<xsl:variable name="json-replacements-replace-set" select="exsl:node-set($json-replacements)/replace" />
|
|
1006
|
+
|
|
1007
|
+
<xsl:template name="escape-json-string">
|
|
1008
|
+
<xsl:param name="text"/>
|
|
1009
|
+
|
|
1010
|
+
<xsl:value-of select="str:replace($text, $json-replacements-search-set, $json-replacements-replace-set)" />
|
|
1011
|
+
</xsl:template>
|
|
1012
|
+
|
|
1013
|
+
<xsl:template name="quote-string">
|
|
1014
|
+
<xsl:param name="text" />
|
|
1015
|
+
<xsl:text>"</xsl:text>
|
|
1016
|
+
<xsl:value-of select="$text" />
|
|
1017
|
+
<xsl:text>"</xsl:text>
|
|
1018
|
+
</xsl:template>
|
|
1019
|
+
|
|
1020
|
+
<xsl:template name="quote-strip-string">
|
|
1021
|
+
<xsl:param name="text" />
|
|
1022
|
+
<xsl:text>"</xsl:text>
|
|
1023
|
+
<xsl:call-template name="strip-newlines">
|
|
1024
|
+
<xsl:with-param name="text" select="$text" />
|
|
1025
|
+
</xsl:call-template>
|
|
1026
|
+
<xsl:text>"</xsl:text>
|
|
1027
|
+
</xsl:template>
|
|
1028
|
+
|
|
1029
|
+
<xsl:template name="escape-quote-string">
|
|
1030
|
+
<xsl:param name="text" />
|
|
1031
|
+
<xsl:call-template name="quote-string">
|
|
1032
|
+
<xsl:with-param name="text">
|
|
1033
|
+
<xsl:call-template name="escape-json-string">
|
|
1034
|
+
<xsl:with-param name="text" select="$text"/>
|
|
1035
|
+
</xsl:call-template>
|
|
1036
|
+
</xsl:with-param>
|
|
1037
|
+
</xsl:call-template>
|
|
1038
|
+
</xsl:template>
|
|
1039
|
+
|
|
1040
|
+
<xsl:template name="escape-quote-xml">
|
|
1041
|
+
<xsl:param name="xml_content"/>
|
|
1042
|
+
<xsl:variable name="xml_text">
|
|
1043
|
+
<xsl:apply-templates select="exsl:node-set($xml_content)" mode="xml-to-string"/>
|
|
1044
|
+
</xsl:variable>
|
|
1045
|
+
<xsl:call-template name="escape-quote-string">
|
|
1046
|
+
<xsl:with-param name="text" select="$xml_text"/>
|
|
1047
|
+
</xsl:call-template>
|
|
1048
|
+
</xsl:template>
|
|
1049
|
+
|
|
1050
|
+
<!-- File Extension -->
|
|
1051
|
+
<!-- Input: full filename -->
|
|
1052
|
+
<!-- Output: extension (no period), lowercase'd -->
|
|
1053
|
+
<!-- Note: appended query string is stripped -->
|
|
1054
|
+
<xsl:template name="file-extension">
|
|
1055
|
+
<xsl:param name="filename" />
|
|
1056
|
+
<!-- Add a question mark, then grab leading substring -->
|
|
1057
|
+
<!-- This will fail if "?" is encoded -->
|
|
1058
|
+
<xsl:variable name="no-query-string" select="substring-before(concat($filename, '?'), '?')" />
|
|
1059
|
+
<!-- get extension after last period -->
|
|
1060
|
+
<!-- will return empty if no extension -->
|
|
1061
|
+
<xsl:variable name="extension">
|
|
1062
|
+
<xsl:call-template name="substring-after-last">
|
|
1063
|
+
<xsl:with-param name="input" select="$no-query-string" />
|
|
1064
|
+
<xsl:with-param name="substr" select="'.'" />
|
|
1065
|
+
</xsl:call-template>
|
|
1066
|
+
</xsl:variable>
|
|
1067
|
+
<!-- to lowercase -->
|
|
1068
|
+
<xsl:value-of select="translate($extension, &UPPERCASE;, &LOWERCASE;)" />
|
|
1069
|
+
</xsl:template>
|
|
1070
|
+
|
|
1071
|
+
<!-- ################# -->
|
|
1072
|
+
<!-- String Utilities -->
|
|
1073
|
+
<!-- ################# -->
|
|
1074
|
+
|
|
1075
|
+
<!-- Find a delimiter: find a character that can be wrapped around a string -->
|
|
1076
|
+
<!-- Take a string as one input and a list of characters as another input -->
|
|
1077
|
+
<!-- Return the first character from the list that is not in the string -->
|
|
1078
|
+
<xsl:template name="find-unused-character">
|
|
1079
|
+
<xsl:param name="string" select="''"/>
|
|
1080
|
+
<!-- set of characters that are candidates for use as delimiters -->
|
|
1081
|
+
<!-- with empty string as default, failure is guaranteed -->
|
|
1082
|
+
<xsl:param name="charset" select="''"/>
|
|
1083
|
+
<!-- If a character in $charset is inside the string, then we do -->
|
|
1084
|
+
<!-- not want to use it as a delimiter. The translate() function -->
|
|
1085
|
+
<!-- operates so as to morph its first argument, $charset. Called -->
|
|
1086
|
+
<!-- this way, each character of the $charset that is in $string, -->
|
|
1087
|
+
<!-- will be replaced by an empty string. So any character of -->
|
|
1088
|
+
<!-- $charset that survives un-translated, is not in $string. -->
|
|
1089
|
+
<xsl:variable name="characters" select="translate($charset, $string, '')"/>
|
|
1090
|
+
|
|
1091
|
+
<!-- We fail, big time, or elect to use the first available character -->
|
|
1092
|
+
<xsl:choose>
|
|
1093
|
+
<xsl:when test="$characters = ''">
|
|
1094
|
+
<xsl:message>PTX:FATAL: Unable to find an unused character in:
<xsl:value-of select="$string" />
using characters from: <xsl:value-of select="$charset" /></xsl:message>
|
|
1095
|
+
<xsl:apply-templates select="." mode="location-report" />
|
|
1096
|
+
<xsl:message terminate="yes"> That's fatal. Sorry. Quitting...</xsl:message>
|
|
1097
|
+
</xsl:when>
|
|
1098
|
+
<xsl:otherwise>
|
|
1099
|
+
<xsl:value-of select="substring($characters, 1, 1)"/>
|
|
1100
|
+
</xsl:otherwise>
|
|
1101
|
+
</xsl:choose>
|
|
1102
|
+
</xsl:template>
|
|
1103
|
+
|
|
1104
|
+
<!-- ############### -->
|
|
1105
|
+
<!-- Token Utilities -->
|
|
1106
|
+
<!-- ############### -->
|
|
1107
|
+
|
|
1108
|
+
<!-- The "tokenize()" function could replace this? -->
|
|
1109
|
+
<!-- And then dependence on EXSL might be removed. -->
|
|
1110
|
+
|
|
1111
|
+
<!-- Routines that can be employed in a recursive -->
|
|
1112
|
+
<!-- formulation to process a string (attribute value, -->
|
|
1113
|
+
<!-- usually) that is separated by spaces or by commas -->
|
|
1114
|
+
|
|
1115
|
+
<!-- Replace commas by blanks, constrict blanks to singletons, -->
|
|
1116
|
+
<!-- add trailing blank for last step of iteration -->
|
|
1117
|
+
<xsl:template name="prepare-token-list">
|
|
1118
|
+
<xsl:param name="token-list" />
|
|
1119
|
+
<xsl:value-of select="concat(normalize-space(str:replace($token-list, ',', ' ')), ' ')" />
|
|
1120
|
+
</xsl:template>
|
|
1121
|
+
|
|
1122
|
+
<!-- Now, to work through the $token-list -->
|
|
1123
|
+
<!-- 1. If $token-list = '', end recursion -->
|
|
1124
|
+
<!-- 2. Process substring-before($token-list, ' ') as next token -->
|
|
1125
|
+
<!-- 3. Pass substring-after($token-list, ' ') recursively -->
|
|
1126
|
+
|
|
1127
|
+
<!-- Generate a unique set of tokens from a given string -->
|
|
1128
|
+
<!-- Final structure will consist of set of <token>value</token> elements -->
|
|
1129
|
+
<!-- Produces a RTF, so result must be converted to nodeset -->
|
|
1130
|
+
<xsl:template name="unique-token-set">
|
|
1131
|
+
<xsl:param name="s" />
|
|
1132
|
+
<xsl:param name="delimiter" select="', '" />
|
|
1133
|
+
<xsl:variable name="token-list" select="str:tokenize($s, $delimiter)"/>
|
|
1134
|
+
<xsl:variable name="token-set-temp" select="set:distinct($token-list)"/>
|
|
1135
|
+
<!-- Next step is currently a no-op as str:tokenize drops empty strings. But that -->
|
|
1136
|
+
<!-- appears to not be part of the spec. So for safety, get difference with -->
|
|
1137
|
+
<!-- a nodeset composed of a single empty token -->
|
|
1138
|
+
<xsl:variable name="token-set" select="set:difference($token-set-temp, str:tokenize(''))"/>
|
|
1139
|
+
<xsl:copy-of select="$token-set" />
|
|
1140
|
+
</xsl:template>
|
|
1141
|
+
|
|
1142
|
+
|
|
1143
|
+
<!-- ################################## -->
|
|
1144
|
+
<!-- Runestone Services General Support -->
|
|
1145
|
+
<!-- ################################## -->
|
|
1146
|
+
|
|
1147
|
+
<!-- Some items that are in play relative to Runestone Services -->
|
|
1148
|
+
<!-- that are independendt of dynamic/static and which can -->
|
|
1149
|
+
<!-- promote consistence if defined only once. End game is the -->
|
|
1150
|
+
<!-- text of a datafile, so appropriate here. However, they -->
|
|
1151
|
+
<!-- are a bit different than above in spirit, as they involve -->
|
|
1152
|
+
<!-- global variables, file manipulations, and are not named -->
|
|
1153
|
+
<!-- templates generally. They are necessary to create static -->
|
|
1154
|
+
<!-- versions of Runestone datafile elements during the -->
|
|
1155
|
+
<!-- assembly phase, and the enhanced-source stylesheet avoids -->
|
|
1156
|
+
<!-- using -common, hence movement here on 2023-10-30. -->
|
|
1157
|
+
|
|
1158
|
+
<!-- Datafiles have default rows and columns -->
|
|
1159
|
+
<xsl:variable name="datafile-default-rows" select="20"/>
|
|
1160
|
+
<xsl:variable name="datafile-default-cols" select="60"/>
|
|
1161
|
+
|
|
1162
|
+
<!-- Get a "view" of a chunk of text, from the "upper-left corner". -->
|
|
1163
|
+
<!-- Motivation is a static version of a (large) datafile of text -->
|
|
1164
|
+
<!-- for interactive programs to consume. -->
|
|
1165
|
+
<!-- text: the text, we provide a version hit by "santitize-tex" -->
|
|
1166
|
+
<!-- above, which pulls left, and drops leading blank lines. -->
|
|
1167
|
+
<!-- nrows: the number of (initial) lines output -->
|
|
1168
|
+
<!-- ncols: the number of (initial) characters on each line -->
|
|
1169
|
+
<!-- if not provided, the entire line is output -->
|
|
1170
|
+
<!-- -->
|
|
1171
|
+
<!-- NB: there can be excess blank lines (nrows in not a maximum) -->
|
|
1172
|
+
<!-- TODO: could be extended to have a "start" location other than -->
|
|
1173
|
+
<!-- upper left corner. Consume initial lines with no action, -->
|
|
1174
|
+
<!-- decrementing start line, then switch to outputing lines -->
|
|
1175
|
+
<!-- themselves. Substring selection should be obvious. -->
|
|
1176
|
+
<xsl:template name="text-viewport">
|
|
1177
|
+
<xsl:param name="text"/>
|
|
1178
|
+
<xsl:param name="nrows"/>
|
|
1179
|
+
<xsl:param name="ncols" select="''"/>
|
|
1180
|
+
|
|
1181
|
+
<xsl:choose>
|
|
1182
|
+
<!-- decremented (or initialized) to zero or below -->
|
|
1183
|
+
<xsl:when test="$nrows < 1"/>
|
|
1184
|
+
<!-- produce a line and recurse -->
|
|
1185
|
+
<xsl:otherwise>
|
|
1186
|
+
<xsl:variable name="line" select="substring-before($text, '
')"/>
|
|
1187
|
+
<xsl:choose>
|
|
1188
|
+
<!-- sentinel: output whole line -->
|
|
1189
|
+
<xsl:when test="$ncols = ''">
|
|
1190
|
+
<xsl:value-of select="$line"/>
|
|
1191
|
+
</xsl:when>
|
|
1192
|
+
<!-- within length limit: output whole line -->
|
|
1193
|
+
<xsl:when test="string-length($line) <= $ncols">
|
|
1194
|
+
<xsl:value-of select="$line"/>
|
|
1195
|
+
</xsl:when>
|
|
1196
|
+
<!-- truncate line to value of $ncols-1, and add -->
|
|
1197
|
+
<!-- a simple right arrow to indicate truncation -->
|
|
1198
|
+
<xsl:otherwise>
|
|
1199
|
+
<xsl:value-of select="substring($line, 1, $ncols - 1)"/>
|
|
1200
|
+
<!-- Unicode Character 'RIGHTWARDS ARROW' -->
|
|
1201
|
+
<xsl:text>→</xsl:text>
|
|
1202
|
+
</xsl:otherwise>
|
|
1203
|
+
</xsl:choose>
|
|
1204
|
+
<!-- restore the missing line-break -->
|
|
1205
|
+
<xsl:value-of select="'
'"/>
|
|
1206
|
+
<!-- rceurse, with remainder of text, requesting -->
|
|
1207
|
+
<!-- one less row, and simply passing along ncols -->
|
|
1208
|
+
<xsl:call-template name="text-viewport">
|
|
1209
|
+
<xsl:with-param name="text" select="substring-after($text, '
')"/>
|
|
1210
|
+
<xsl:with-param name="nrows" select="$nrows - 1"/>
|
|
1211
|
+
<xsl:with-param name="ncols" select="$ncols"/>
|
|
1212
|
+
</xsl:call-template>
|
|
1213
|
+
</xsl:otherwise>
|
|
1214
|
+
</xsl:choose>
|
|
1215
|
+
</xsl:template>
|
|
1216
|
+
|
|
1217
|
+
</xsl:stylesheet>
|