XSLT Explorer: docbook.xsl

48 imports, 769 templates, 208 functions, 100 variables, 202 params, 3 FIXME: comments

List of Imports
List of Templates
tp:orderedlist-properties
tp:process-list
tp:format-number
tp:group-or-arg
t:inline
tp:filter-callouts
tp:verbatim
tp:verbatim-array
tp:verbatim-lines
tp:verbatim-plain
tp:verbatim-raw
tp:verbatim-table
t:generate-index
t:index-zone-reference
tp:indexed-section
t:mediaobject-img
tp:viewport
t:table-footnotes
tp:resolve-persistent-toc-uris
t:chunk-cleanup
t:chunk-output
t:docbook
tp:cals-colspec
tp:cell
tp:list-of-titles
tp:toc
tp:tocentry-link
tp:link
tp:xref
t:person-name
t:person-name-family-given
t:person-name-first-last
t:person-name-last-first
t:person-name-list
t:biblioentry
tp:out-of-line-xlink
tp:simple-xlink
t:xlink
t:bottom-nav
t:chunk-footnotes
t:top-nav
List of Functions
fp:estimated-term-length()
fp:select-vert-members()
f:l10n-token()
f:l10n-token()
fp:l10n-token()
fp:minified-css()
f:attributes()
f:attributes()
f:date-format()
f:generate-id()
f:generate-id()
f:gentext-letters()
f:gentext-letters-for-language()
f:href()
f:id()
f:is-true()
f:l10n-language()
f:label-separator()
f:orderedlist-item-number()
f:orderedlist-item-numeration()
f:orderedlist-startingnumber()
f:pi()
f:pi()
f:pi-attributes()
fp:css-properties()
fp:lookup-string()
fp:parse-key-value-pairs()
fp:parse-key-value-pairs()
fp:pi-attributes()
fp:pi-from-list()
fp:pi-pi-attributes()
fp:properties()
fp:replace-element()
fp:replace-element()
fp:separator()
f:refsection()
f:relative-path()
f:section()
f:section-depth()
f:spaces()
f:step-number()
f:step-numeration()
f:target()
f:tokenize-on-char()
f:translate-attribute()
f:unique-id()
f:uri-scheme()
fp:common-attributes()
fp:common-attributes()
fp:nearest-relevant-ancestor()
fp:title-properties()
f:absolute-length()
f:empty-length()
f:equal-lengths()
f:is-empty-length()
f:length-string()
f:length-units()
f:make-length()
f:make-length()
f:make-length()
f:parse-length()
f:relative-length()
f:highlight-verbatim()
fp:array-append()
fp:array-pad()
fp:balance-line()
fp:balance-markup()
fp:balance-markup()
fp:contains()
fp:following()
fp:inject()
fp:inject-array()
fp:inject-into-chars()
fp:inject-into-line()
fp:injection-array()
fp:line-number()
fp:line-to-chars()
fp:make-lines()
fp:make-lines-array()
fp:open()
fp:unflatten()
fp:unflatten()
fp:unflatten-line()
fp:unflatten-line()
fp:up-to()
fp:validate-injection-array()
fp:verbatim-properties()
f:verbatim-highlight()
f:verbatim-numbered()
f:verbatim-style()
f:verbatim-trim-leading()
f:verbatim-trim-trailing()
fp:fix-text()
fp:iso690()
fp:optional-sep()
fp:group-index()
fp:group-label()
fp:nearest-section()
fp:nearest-section-id()
fp:primary()
fp:scope()
fp:secondary()
fp:tertiary()
f:chunk()
f:chunk-filename()
fp:chunk-exclude()
fp:chunk-include()
fp:chunk-navigation()
fp:matches-expr()
fp:root-base-uri()
fp:trim-common-parts()
fp:trim-common-prefix()
f:css-length()
f:css-property()
f:mediaobject-amend-uri()
f:mediaobject-input-base-uri()
f:mediaobject-type()
f:mediaobject-viewport()
f:object-align()
f:object-contentheight()
f:object-contentwidth()
f:object-height()
f:object-properties()
f:object-properties()
f:object-scale()
f:object-scalefit()
f:object-valign()
f:object-width()
f:in-scope-language()
f:languages()
fp:localization()
fp:localization-list()
fp:localization-template()
fp:lookup-localization-list()
fp:lookup-localization-template()
fp:footnote-mark()
fp:footnote-number()
fp:resolve-persistent-toc()
fp:resolve-persistent-toc-prefix()
fp:run-transforms()
fp:run-transforms()
f:cals-colsep()
f:cals-rowsep()
fp:align-char-pad()
fcals:align()
fcals:align-colspec()
fcals:align-spanspec()
fcals:cell()
fcals:cell-decoration()
fcals:cell-overhang()
fcals:char()
fcals:char-colspec()
fcals:char-spanspec()
fcals:colsep()
fcals:colsep-colspec()
fcals:colsep-spanspec()
fcals:colspan()
fcals:colspec()
fcals:colspec-column-number()
fcals:colspec-for-column()
fcals:column-number()
fcals:decrement-overhang()
fcals:empty-cell-colsep()
fcals:empty-cell-rowsep()
fcals:next-empty-cell()
fcals:overhang()
fcals:overhang-into-row()
fcals:rowsep()
fcals:rowsep-colspec()
fcals:rowsep-spanspec()
fcals:rowspan()
fcals:spanspec()
fcals:table-columns()
fcals:tgroup()
fcals:valign()
fcals:zeros()
fp:colspec-for-colnum()
fp:only-initial-pis()
fp:number()
fp:collapse-years()
fp:collapse-years()
fp:syntax-highlight()
fp:syntax-highlight()
f:syntax-highlight()
f:syntax-highlight()
f:syntax-highlight()
fp:construct-templates()
fp:pick-template()
f:template()
fp:find-xlink-nodes()
fp:pmuj()
fp:pmuj-enabled()
fp:xlink-sources()
fp:xlink-targets()
fp:xlink-xmlns-scheme()
fp:xlink-xpath-scheme()
f:xlink-style()
f:xpointer-idref()
f:chunk-title()
fp:chunk-output-filename()
fp:footnote-mark()
fp:footnote-number()
fp:navigable()
fp:relative-link()
fp:relative-uri()
fp:root-base-uri()
fp:trim-common-parts()
fp:trim-common-prefix()

docbook.xsl

1 import

main.xsl

46 imports

param.xsl

2 variables (2 used only in one other module), 201 params (1 unused)

Instructions
Param $additional-languages
Param $align-char-default as xs:string
Param $align-char-pad
Param $align-char-width
Param $allow-eval as xs:string
Param $annotate-toc
Param $annotation-collection as xs:string
Param $annotation-placement
Param $annotation-style
Param $annotations-js
Param $auto-toc as xs:string
Param $bibliography-collection as xs:string
Param $bibliography-style as xs:string
Param $callout-default-column
Param $chunk-exclude as xs:string*
Param $chunk-include as xs:string*
Param $chunk-nav as xs:string
Param $chunk-nav-js as xs:string
Param $chunk-output-base-uri as xs:string
Param $chunk-renumber-footnotes
Param $chunk-section-depth
Param $classsynopsis-indent
Param $component-numbers as xs:string
Param $component-numbers-inherit as xs:string
Param $control-js as xs:string
Param $copyright-collapse-years
Param $copyright-year-range-separator
Param $dc-metadata as xs:string
Param $debug as xs:string [static]
Param $default-float-style
Param $default-length-magnitude
Param $default-length-unit
Param $personal-name-style
Param $default-theme as xs:string
Param $division-numbers as xs:string
Param $division-numbers-inherit as xs:string
Param $docbook-transclusion
Param $dynamic-profile-error
Param $dynamic-profiles as xs:string
Param $experimental-pmuj
Param $mediaobject-details-placement
Param $formalgroup-nested-object-title-placement
Param $funcsynopsis-default-style
Param $funcsynopsis-table-threshold
Param $generate-html-page as xs:string
Param $generate-index
Param $generate-nested-toc as xs:string
Param $generate-toc as xs:string
Param $generate-trivial-toc as xs:string
Param $generated-id-root
Param $generated-id-sep
Param $generator-metadata as xs:string
Param $glossary-collection as xs:string
Param $glossary-sort-entries
Param $image-property-warning
Param $index-show-entries
Param $indexed-section-groups
Param $lists-of-equations as xs:string
Param $lists-of-examples as xs:string
Param $lists-of-figures as xs:string
Param $lists-of-procedures as xs:string
Param $lists-of-tables as xs:string
Param $local-conventions as xs:string?
Param $mathml-js
Param $mediaobject-accessibility as xs:string
Param $mediaobject-exclude-extensions as xs:string
Param $mediaobject-input-base-uri as xs:string?
Param $mediaobject-grouped-by-type as xs:string
Param $mediaobject-output-paths as xs:string
Param $mediaobject-video-element as xs:string
Param $number-single-appendix
Param $orderedlist-item-numeration
Param $othername-in-middle
Param $output-media
Unused
Param $oxy-markup
Param $pagetoc-dynamic
Param $pagetoc-js
Param $page-style as xs:string
Param $paper-size as xs:string?
Param $persistent-toc-css
Param $persistent-toc-filename as xs:string?
Param $persistent-toc-js
Param $pixels-per-inch
Param $procedure-step-numeration
Param $productionset-lhs-rhs-separator
Param $profile-arch
Param $profile-audience
Param $profile-condition
Param $profile-conformance
Param $profile-lang
Param $profile-os
Param $profile-outputformat
Param $profile-revision
Param $profile-revisionflag
Param $profile-role
Param $profile-security
Param $profile-separator
Param $profile-userlevel
Param $profile-vendor
Param $profile-wordsize
Param $theme-picker as xs:string
Param $transclusion-id-fixup as xs:string
Param $transclusion-prefix-separator as xs:string
Param $transclusion-suffix as xs:string
Param $qandadiv-default-toc
Param $relax-ng-grammar as xs:string?
Param $refentry-generate-name
Param $refentry-generate-title
Param $revhistory-style
Param $section-numbers as xs:string
Param $section-numbers-inherit
Param $segmentedlist-style
Param $show-remarks
Param $sidebar-as-aside
Param $sort-collation
Param $table-accessibility as xs:string
Param $use-docbook-css as xs:string
Param $use-minified-css as xs:string
Param $variablelist-termlength-threshold
Param $verbatim-callouts as xs:string
Param $verbatim-number-every-nth
Param $verbatim-number-first-line
Param $verbatim-number-minlines
Param $verbatim-numbered-elements
Param $verbatim-plain-style as xs:string
Param $verbatim-style-default
Param $verbatim-syntax-highlight-css
Param $verbatim-syntax-highlight-languages
Param $verbatim-trim-leading-blank-lines
Param $verbatim-trim-trailing-blank-lines
Param $xspec as xs:string
Param $transform-original
Param $transform-before
Param $transform-after
Param $dynamic-profile-variables as map(xs:QName, item()*)?
Param $warn-about-missing-localizations as xs:string
Param $sets-number-from as xs:string
Param $books-number-from as xs:string
Param $divisions-number-from as xs:string
Param $components-number-from as xs:string
Param $sections-number-from as xs:string
Param $formal-objects-number-from as xs:string
Param $sets-inherit-from as xs:string
Param $books-inherit-from as xs:string
Param $divisions-inherit-from as xs:string
Param $components-inherit-from as xs:string
Param $sections-inherit-from as xs:string
Param $formal-objects-inherit-from as xs:string
Param $unwrap-paragraphs as xs:string
Param $copy-verbatim-js
Param $translate-suppress-elements
Param $varlistentry-separate-terms
Param $presentation-mode
Param $presentation-js
Param $presentation-css
Variable $vp:static-parameters as map(xs:QName, item()*)
Uses: $debug
Used in: «root»
Variable $vp:dynamic-parameters as map(xs:QName, item()*)
Uses: $additional-languages, $align-char-default, $align-char-pad, $align-char-width, $allow-eval, $annotate-toc, $annotation-collection, $annotation-mark, $annotation-placement, $annotation-style, $annotations-js, $auto-toc, $bibliography-collection, $bibliography-style, $books-inherit-from, $books-number-from, $callout-default-column, $callout-unicode-start, $chunk, $chunk-exclude, $chunk-include, $chunk-nav, $chunk-nav-js, $chunk-output-base-uri, $chunk-renumber-footnotes, $chunk-section-depth, $classsynopsis-indent, $component-numbers, $component-numbers-inherit, $components-inherit-from, $components-number-from, $control-js, $copy-verbatim-js, $copyright-collapse-years, $copyright-year-range-separator, $copyright-year-separator, $date-date-format, $date-dateTime-format, $dc-metadata, $default-float-style, $default-language, $default-length-magnitude, $default-length-unit, $default-theme, $division-numbers, $division-numbers-inherit, $divisions-inherit-from, $divisions-number-from, $docbook-transclusion, $dynamic-profile-error, $dynamic-profile-variables, $dynamic-profiles, $experimental-pmuj, $fallback-js, $footnote-numeration, $formal-object-title-placement, $formal-objects-inherit-from, $formal-objects-number-from, $formalgroup-nested-object-title-placement, $funcsynopsis-default-style, $funcsynopsis-table-threshold, $funcsynopsis-trailing-punctuation, $generate-html-page, $generate-index, $generate-nested-toc, $generate-toc, $generate-trivial-toc, $generated-id-root, $generated-id-sep, $generator-metadata, $gentext-language, $glossary-collection, $glossary-sort-entries, $html-extension, $image-ignore-scaling, $image-nominal-height, $image-nominal-width, $image-property-warning, $index-on-role, $index-on-type, $index-show-entries, $indexed-section-groups, $lists-of-equations, $lists-of-examples, $lists-of-figures, $lists-of-procedures, $lists-of-tables, $local-conventions, $mathml-js, $mediaobject-accessibility, $mediaobject-details-placement, $mediaobject-exclude-extensions, $mediaobject-grouped-by-type, $mediaobject-input-base-uri, $mediaobject-output-base-uri, $mediaobject-output-paths, $mediaobject-video-element, $message-level, $nominal-page-width, $number-single-appendix, $olink-databases, $orderedlist-item-numeration, $othername-in-middle, $output-media, $oxy-markup, $page-style, $pagetoc-dynamic, $pagetoc-elements, $pagetoc-js, $paper-size, $persistent-toc, $persistent-toc-css, $persistent-toc-filename, $persistent-toc-js, $persistent-toc-search, $personal-name-style, $pixels-per-inch, $presentation-css, $presentation-js, $presentation-mode, $procedure-step-numeration, $productionset-lhs-rhs-separator, $profile-arch, $profile-audience, $profile-condition, $profile-conformance, $profile-lang, $profile-os, $profile-outputformat, $profile-revision, $profile-revisionflag, $profile-role, $profile-security, $profile-separator, $profile-userlevel, $profile-vendor, $profile-wordsize, $qandadiv-default-toc, $qandaset-default-label, $qandaset-default-toc, $refentry-generate-name, $refentry-generate-title, $relax-ng-grammar, $resource-base-uri, $revhistory-style, $section-numbers, $section-numbers-inherit, $section-toc-depth, $sections-inherit-from, $sections-number-from, $segmentedlist-style, $sets-inherit-from, $sets-number-from, $show-remarks, $sidebar-as-aside, $sort-collation, $table-accessibility, $table-footnote-numeration, $theme-picker, $transclusion-id-fixup, $transclusion-link-scope, $transclusion-prefix-separator, $transclusion-suffix, $transform-after, $transform-before, $transform-original, $translate-suppress-elements, $unwrap-paragraphs, $use-docbook-css, $use-minified-css, $user-css-links, $variablelist-termlength-threshold, $varlistentry-separate-terms, $verbatim-callouts, $verbatim-line-style, $verbatim-number-every-nth, $verbatim-number-first-line, $verbatim-number-minlines, $verbatim-number-separator, $verbatim-numbered-elements, $verbatim-plain-style, $verbatim-space, $verbatim-style-default, $verbatim-syntax-highlight-css, $verbatim-syntax-highlight-languages, $verbatim-syntax-highlighter, $verbatim-table-style, $verbatim-trim-leading-blank-lines, $verbatim-trim-trailing-blank-lines, $warn-about-missing-localizations, $xlink-arclist-after, $xlink-arclist-before, $xlink-arclist-sep, $xlink-arclist-titlesep, $xlink-icon-closed, $xlink-icon-open, $xlink-js, $xlink-style, $xlink-style-default, $xspec
Used in: «root»
Source code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns="http://www.w3.org/1999/xhtml"
                 xmlns:db="http://docbook.org/ns/docbook"
                 xmlns:ext="http://docbook.org/extensions/xslt"
                 xmlns:f="http://docbook.org/ns/docbook/functions"
                 xmlns:m="http://docbook.org/ns/docbook/modes"
                 xmlns:v="http://docbook.org/ns/docbook/variables"
                 xmlns:vp="http://docbook.org/ns/docbook/variables/private"
                 xmlns:xs="http://www.w3.org/2001/XMLSchema"
                 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                 default-mode="m:docbook"
                 exclude-result-prefixes="#all"
                 version="3.0">

<!-- **********************************************************************
     This file is generated automatically from the parameters
     reference in the guide. Do not edit this file by hand.
     ********************************************************************** -->

<!-- Note: Some of these parameters are initialized using content
     instead of a select attribute in order to make the reference page
     in the Guide work better. -->

<!-- Many of these parameters are shadowed by variables (see
     variable.xsl) for use in the stylesheets. Often, they're defined
     as strings here and as more useful data types in the variables. -->
   <xsl:param name="additional-languages" select="()"/>
   <xsl:param name="align-char-default" as="xs:string" select="'.'"/>
   <xsl:param name="align-char-pad" select="' '"/>
   <xsl:param name="align-char-width" select="2"/>
   <xsl:param name="allow-eval" as="xs:string" select="'true'"/>
   <xsl:param name="annotate-toc" select="'true'"/>
   <xsl:param name="annotation-collection" as="xs:string" select="''"/>
   <xsl:param name="annotation-mark">
      <sup>⌖</sup>
   </xsl:param>
   <xsl:param name="annotation-placement" select="'after'"/>
   <xsl:param name="annotation-style" select="'javascript'"/>
   <xsl:param name="annotations-js" select="'js/annotations.js'"/>
   <xsl:param name="auto-toc" as="xs:string" select="'true'"/>
   <xsl:param name="bibliography-collection" as="xs:string" select="''"/>
   <xsl:param name="bibliography-style" as="xs:string" select="'default'"/>
   <xsl:param name="callout-default-column" select="60"/>
   <xsl:param name="callout-unicode-start" select="9311"/>
   <xsl:param name="chunk" as="xs:string?" select="()"/>
   <xsl:param name="chunk-exclude"
               as="xs:string*"
               select="('self::db:partintro',&#xA; 'self::*[ancestor::db:partintro]',&#xA; 'self::db:annotation',&#xA; 'self::db:section[not(preceding-sibling::db:section)]',&#xA; 'self::db:sect1[not(preceding-sibling::db:sect1)]',&#xA; 'self::db:toc')"/>
   <xsl:param name="chunk-include"
               as="xs:string*"
               select="('parent::db:set',&#xA; 'parent::db:book',&#xA; 'parent::db:part',&#xA; 'parent::db:reference',&#xA; 'self::db:refentry',&#xA; 'self::db:section',&#xA; 'self::db:sect1')"/>
   <xsl:param name="chunk-nav" as="xs:string" select="'true'"/>
   <xsl:param name="chunk-nav-js" as="xs:string" select="'js/chunk-nav.js'"/>
   <xsl:param name="chunk-output-base-uri" as="xs:string">
      <xsl:choose>
         <xsl:when test="not($v:chunk)">
    <!-- it doesn't actually matter -->
            <xsl:sequence select="''"/>
         </xsl:when>
         <xsl:when use-when="function-available('ext:cwd')" test="true()">
            <xsl:sequence select="ext:cwd()"/>
         </xsl:when>
         <xsl:otherwise>
            <xsl:message terminate="yes" select="'You must specify the $chunk-output-base-uri'"/>
         </xsl:otherwise>
      </xsl:choose>
   </xsl:param>
   <xsl:param name="chunk-renumber-footnotes" select="'true'"/>
   <xsl:param name="chunk-section-depth" select="1"/>
   <xsl:param name="classsynopsis-indent" select="'  '"/>
   <xsl:param name="component-numbers" as="xs:string" select="'true'"/>
   <xsl:param name="component-numbers-inherit" as="xs:string" select="'false'"/>
   <xsl:param name="control-js" as="xs:string" select="'js/controls.js'"/>
   <xsl:param name="copyright-collapse-years" select="true()"/>
   <xsl:param name="copyright-year-range-separator" select="'–'"/>
   <xsl:param name="copyright-year-separator" select="', '"/>
   <xsl:param name="date-date-format" select="'[D01] [MNn,*-3] [Y0001]'"/>
   <xsl:param name="date-dateTime-format"
               select="'[H01]:[m01] [D01] [MNn,*-3] [Y0001]'"/>
   <xsl:param name="dc-metadata" as="xs:string" select="'true'"/>
   <xsl:param name="debug" static="yes" as="xs:string" select="''"/>
   <xsl:param name="default-float-style" select="'left'"/>
   <xsl:param name="default-language" select="'en'"/>
   <xsl:param name="default-length-magnitude" select="25.0"/>
   <xsl:param name="default-length-unit" select="'%'"/>
   <xsl:param name="personal-name-style" select="()"/>
   <xsl:param name="default-theme" as="xs:string" select="''"/>
   <xsl:param name="division-numbers" as="xs:string" select="'true'"/>
   <xsl:param name="division-numbers-inherit" as="xs:string" select="'false'"/>
   <xsl:param name="docbook-transclusion" select="'false'"/>
   <xsl:param name="dynamic-profile-error" select="'ignore'"/>
   <xsl:param name="dynamic-profiles" as="xs:string" select="'false'"/>
   <xsl:param name="experimental-pmuj" select="'false'"/>
   <xsl:param name="footnote-numeration" select="('1')"/>
   <xsl:param name="formal-object-title-placement"
               select="'after table:before formalgroup:before'"/>
   <xsl:param name="mediaobject-details-placement" select="'before'"/>
   <xsl:param name="formalgroup-nested-object-title-placement" select="'after'"/>
   <xsl:param name="funcsynopsis-default-style" select="'kr'"/>
   <xsl:param name="funcsynopsis-table-threshold" select="40"/>
   <xsl:param name="funcsynopsis-trailing-punctuation" select="';'"/>
   <xsl:param name="generate-html-page" as="xs:string" select="'true'"/>
   <xsl:param name="generate-index" select="'true'"/>
   <xsl:param name="generate-nested-toc"
               as="xs:string"
               select="'not(f:section(.))&#xA;or (f:section(.) and f:section-depth(.) le $vp:section-toc-depth)'"/>
   <xsl:param name="generate-toc"
               as="xs:string"
               select="'(empty(parent::*) and self::db:article)&#xA;or self::db:set or self::db:book&#xA;or self::db:part or self::db:reference'"/>
   <xsl:param name="generate-trivial-toc" as="xs:string" select="'false'"/>
   <xsl:param name="generated-id-root" select="'R'"/>
   <xsl:param name="generated-id-sep" select="'_'"/>
   <xsl:param name="generator-metadata" as="xs:string" select="'true'"/>
   <xsl:param name="gentext-language" select="()"/>
   <xsl:param name="glossary-collection" as="xs:string" select="''"/>
   <xsl:param name="glossary-sort-entries" select="true()"/>
   <xsl:param name="html-extension" select="'.html'"/>
   <xsl:param name="image-ignore-scaling" as="xs:boolean" select="false()"/>
   <xsl:param name="image-nominal-height" select="'4in'"/>
   <xsl:param name="image-nominal-width" select="$nominal-page-width"/>
   <xsl:param name="image-property-warning" select="true()"/>
   <xsl:param name="index-on-type" select="'true'"/>
   <xsl:param name="index-on-role" select="'true'"/>
   <xsl:param name="index-show-entries" select="()"/>
   <xsl:param name="indexed-section-groups" select="'true'"/>
   <xsl:param name="lists-of-equations" as="xs:string" select="'false'"/>
   <xsl:param name="lists-of-examples" as="xs:string" select="'true'"/>
   <xsl:param name="lists-of-figures" as="xs:string" select="'true'"/>
   <xsl:param name="lists-of-procedures" as="xs:string" select="'false'"/>
   <xsl:param name="lists-of-tables" as="xs:string" select="'true'"/>
   <xsl:param name="local-conventions" as="xs:string?" select="()"/>
   <xsl:param name="mathml-js"
               select="'https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=MML_CHTML'"/>
   <xsl:param name="mediaobject-accessibility"
               as="xs:string"
               select="'summary details'"/>
   <xsl:param name="mediaobject-exclude-extensions"
               as="xs:string"
               select="&#34;.eps .ps .pdf&#34;"/>
   <xsl:param name="mediaobject-input-base-uri" as="xs:string?" select="()"/>
   <xsl:param name="mediaobject-grouped-by-type" as="xs:string" select="'false'"/>
   <xsl:param name="mediaobject-output-base-uri" as="xs:string?" select="()"/>
   <xsl:param name="mediaobject-output-paths" as="xs:string" select="'true'"/>
   <xsl:param name="mediaobject-video-element" as="xs:string" select="'video'"/>
   <xsl:param name="nominal-page-width" select="'6in'"/>
   <xsl:param name="number-single-appendix" select="'true'"/>
   <xsl:param name="olink-databases" as="xs:string" select="''"/>
   <xsl:param name="orderedlist-item-numeration" select="'1aiAI'"/>
   <xsl:param name="othername-in-middle" select="'true'"/>
   <xsl:param name="output-media" select="'screen'"/>
   <xsl:param name="oxy-markup" select="'false'"/>
   <xsl:param name="pagetoc-elements" select="''"/>
   <xsl:param name="pagetoc-dynamic" select="'true'"/>
   <xsl:param name="pagetoc-js" select="'js/pagetoc.js'"/>
   <xsl:param name="page-style" as="xs:string" select="'article'"/>
   <xsl:param name="paper-size" as="xs:string?" select="()"/>
   <xsl:param name="persistent-toc" select="'false'"/>
   <xsl:param name="persistent-toc-css" select="'css/docbook-toc.css'"/>
   <xsl:param name="persistent-toc-filename"
               as="xs:string?"
               select="'persistent-toc.html'"/>
   <xsl:param name="persistent-toc-js" select="'js/persistent-toc.js'"/>
   <xsl:param name="persistent-toc-search" select="'true'"/>
   <xsl:param name="pixels-per-inch" select="96.0"/>
   <xsl:param name="procedure-step-numeration" select="'1aiAI'"/>
   <xsl:param name="productionset-lhs-rhs-separator" select="':='"/>
   <xsl:param name="profile-arch" select="''"/>
   <xsl:param name="profile-audience" select="''"/>
   <xsl:param name="profile-condition" select="''"/>
   <xsl:param name="profile-conformance" select="''"/>
   <xsl:param name="profile-lang" select="''"/>
   <xsl:param name="profile-os" select="''"/>
   <xsl:param name="profile-outputformat" select="''"/>
   <xsl:param name="profile-revision" select="''"/>
   <xsl:param name="profile-revisionflag" select="''"/>
   <xsl:param name="profile-role" select="''"/>
   <xsl:param name="profile-security" select="''"/>
   <xsl:param name="profile-separator" select="';'"/>
   <xsl:param name="profile-userlevel" select="''"/>
   <xsl:param name="profile-vendor" select="''"/>
   <xsl:param name="profile-wordsize" select="''"/>
   <xsl:param name="theme-picker" as="xs:string" select="'false'"/>
   <xsl:param name="transclusion-id-fixup" as="xs:string" select="'none'"/>
   <xsl:param name="transclusion-link-scope" as="xs:string" select="'global'"/>
   <xsl:param name="transclusion-prefix-separator" as="xs:string" select="'---'"/>
   <xsl:param name="transclusion-suffix" as="xs:string" select="''"/>
   <xsl:param name="qandadiv-default-toc" select="$qandaset-default-toc"/>
   <xsl:param name="qandaset-default-label" select="'number'"/>
   <xsl:param name="qandaset-default-toc" select="'true'"/>
   <xsl:param name="relax-ng-grammar" as="xs:string?" select="()"/>
   <xsl:param name="refentry-generate-name" select="true()"/>
   <xsl:param name="refentry-generate-title" select="true()"/>
   <xsl:param name="resource-base-uri" select="'./'"/>
   <xsl:param name="revhistory-style" select="'table'"/>
   <xsl:param name="section-numbers" as="xs:string" select="'true'"/>
   <xsl:param name="section-numbers-inherit" select="'true'"/>
   <xsl:param name="section-toc-depth" select="'unbounded'"/>
   <xsl:param name="segmentedlist-style" select="'table'"/>
   <xsl:param name="show-remarks" select="'false'"/>
   <xsl:param name="sidebar-as-aside" select="false()"/>
   <xsl:param name="sort-collation"
               select="'http://www.w3.org/2005/xpath-functions/collation/html-ascii-case-insensitive'"/>
   <xsl:param name="table-accessibility"
               as="xs:string"
               select="'summary details'"/>
   <xsl:param name="table-footnote-numeration" select="('a')"/>
   <xsl:param name="use-docbook-css" as="xs:string" select="'true'"/>
   <xsl:param name="use-minified-css" as="xs:string" select="'false'"/>
   <xsl:param name="user-css-links" select="()"/>
   <xsl:param name="variablelist-termlength-threshold" select="20"/>
   <xsl:param name="verbatim-callouts"
               as="xs:string"
               select="'linecolumn lines lineranges-first'"/>
   <xsl:param name="verbatim-line-style"
               select="'programlisting programlistingco&#xA; screen screenco synopsis'"/>
   <xsl:param name="verbatim-number-every-nth" select="5"/>
   <xsl:param name="verbatim-number-first-line" select="'true'"/>
   <xsl:param name="verbatim-number-minlines" select="'5'"/>
   <xsl:param name="verbatim-number-separator" select="'|'"/>
   <xsl:param name="verbatim-numbered-elements"
               select="'programlisting programlistingco'"/>
   <xsl:param name="verbatim-plain-style"
               as="xs:string"
               select="'address literallayout funcsynopsisinfo classsynopsisinfo'"/>
   <xsl:param name="verbatim-space" select="' '"/>
   <xsl:param name="verbatim-style-default" select="'lines'"/>
   <xsl:param name="verbatim-syntax-highlight-css" select="'css/pygments.css'"/>
   <xsl:param name="verbatim-syntax-highlight-languages"
               select="'python perl html xml xslt xquery javascript json css'"/>
   <xsl:param name="verbatim-syntax-highlighter"
               as="xs:string"
               select="'pygments'"/>
   <xsl:param name="verbatim-table-style" select="''"/>
   <xsl:param name="verbatim-trim-leading-blank-lines" select="'false'"/>
   <xsl:param name="verbatim-trim-trailing-blank-lines" select="'true'"/>
   <xsl:param name="xlink-arclist-before" select="' ['"/>
   <xsl:param name="xlink-arclist-after" select="'] '"/>
   <xsl:param name="xlink-arclist-titlesep" select="': '"/>
   <xsl:param name="xlink-arclist-sep" select="', '"/>
   <xsl:param name="xlink-icon-closed" select="()"/>
   <xsl:param name="xlink-icon-open" select="()"/>
   <xsl:param name="xlink-js" select="'js/xlink.js'"/>
   <xsl:param name="xlink-style" select="'document'"/>
   <xsl:param name="xlink-style-default" select="'inline'"/>
   <xsl:param name="xspec" as="xs:string" select="'false'"/>
   <xsl:param name="transform-original" select="()"/>
   <xsl:param name="transform-before" select="()"/>
   <xsl:param name="transform-after" select="()"/>
   <xsl:param name="dynamic-profile-variables"
               as="map(xs:QName, item()*)?"
               select="()"/>
   <xsl:param name="warn-about-missing-localizations"
               as="xs:string"
               select="'true'"/>
   <xsl:param name="sets-number-from" as="xs:string" select="'set'"/>
   <xsl:param name="books-number-from" as="xs:string" select="'set'"/>
   <xsl:param name="divisions-number-from" as="xs:string" select="'book'"/>
   <xsl:param name="components-number-from" as="xs:string" select="'book'"/>
   <xsl:param name="sections-number-from" as="xs:string" select="'component'"/>
   <xsl:param name="formal-objects-number-from"
               as="xs:string"
               select="'component'"/>
   <xsl:param name="sets-inherit-from" as="xs:string" select="''"/>
   <xsl:param name="books-inherit-from" as="xs:string" select="''"/>
   <xsl:param name="divisions-inherit-from" as="xs:string" select="''"/>
   <xsl:param name="components-inherit-from" as="xs:string" select="''"/>
   <xsl:param name="sections-inherit-from" as="xs:string" select="'section'"/>
   <xsl:param name="formal-objects-inherit-from"
               as="xs:string"
               select="'component'"/>
   <xsl:param name="unwrap-paragraphs" as="xs:string" select="'false'"/>
   <xsl:param name="fallback-js" select="'js/fallback.js'"/>
   <xsl:param name="message-level" as="xs:integer" select="1"/>
   <xsl:param name="copy-verbatim-js" select="'js/copy-verbatim.js'"/>
   <xsl:param name="translate-suppress-elements" select="''"/>
   <xsl:param name="varlistentry-separate-terms" select="'false'"/>
   <xsl:param name="presentation-mode" select="'false'"/>
   <xsl:param name="presentation-js" select="'js/presentation.js'"/>
   <xsl:param name="presentation-css" select="'css/presentation.css'"/>
   <xsl:variable name="vp:static-parameters" as="map(xs:QName, item()*)">
      <xsl:map>
         <xsl:map-entry key="QName('', 'debug')" select="$debug"/>
      </xsl:map>
   </xsl:variable>
   <xsl:variable name="vp:dynamic-parameters" as="map(xs:QName, item()*)">
      <xsl:map>
         <xsl:map-entry key="QName('', 'additional-languages')" select="$additional-languages"/>
         <xsl:map-entry key="QName('', 'align-char-default')" select="$align-char-default"/>
         <xsl:map-entry key="QName('', 'align-char-pad')" select="$align-char-pad"/>
         <xsl:map-entry key="QName('', 'align-char-width')" select="$align-char-width"/>
         <xsl:map-entry key="QName('', 'allow-eval')" select="$allow-eval"/>
         <xsl:map-entry key="QName('', 'annotate-toc')" select="$annotate-toc"/>
         <xsl:map-entry key="QName('', 'annotation-collection')"
                         select="$annotation-collection"/>
         <xsl:map-entry key="QName('', 'annotation-mark')" select="$annotation-mark"/>
         <xsl:map-entry key="QName('', 'annotation-placement')" select="$annotation-placement"/>
         <xsl:map-entry key="QName('', 'annotation-style')" select="$annotation-style"/>
         <xsl:map-entry key="QName('', 'annotations-js')" select="$annotations-js"/>
         <xsl:map-entry key="QName('', 'auto-toc')" select="$auto-toc"/>
         <xsl:map-entry key="QName('', 'bibliography-collection')"
                         select="$bibliography-collection"/>
         <xsl:map-entry key="QName('', 'bibliography-style')" select="$bibliography-style"/>
         <xsl:map-entry key="QName('', 'callout-default-column')"
                         select="$callout-default-column"/>
         <xsl:map-entry key="QName('', 'callout-unicode-start')"
                         select="$callout-unicode-start"/>
         <xsl:map-entry key="QName('', 'chunk')" select="$chunk"/>
         <xsl:map-entry key="QName('', 'chunk-exclude')" select="$chunk-exclude"/>
         <xsl:map-entry key="QName('', 'chunk-include')" select="$chunk-include"/>
         <xsl:map-entry key="QName('', 'chunk-nav')" select="$chunk-nav"/>
         <xsl:map-entry key="QName('', 'chunk-nav-js')" select="$chunk-nav-js"/>
         <xsl:map-entry key="QName('', 'chunk-output-base-uri')"
                         select="$chunk-output-base-uri"/>
         <xsl:map-entry key="QName('', 'chunk-renumber-footnotes')"
                         select="$chunk-renumber-footnotes"/>
         <xsl:map-entry key="QName('', 'chunk-section-depth')" select="$chunk-section-depth"/>
         <xsl:map-entry key="QName('', 'classsynopsis-indent')" select="$classsynopsis-indent"/>
         <xsl:map-entry key="QName('', 'component-numbers')" select="$component-numbers"/>
         <xsl:map-entry key="QName('', 'component-numbers-inherit')"
                         select="$component-numbers-inherit"/>
         <xsl:map-entry key="QName('', 'control-js')" select="$control-js"/>
         <xsl:map-entry key="QName('', 'copyright-collapse-years')"
                         select="$copyright-collapse-years"/>
         <xsl:map-entry key="QName('', 'copyright-year-range-separator')"
                         select="$copyright-year-range-separator"/>
         <xsl:map-entry key="QName('', 'copyright-year-separator')"
                         select="$copyright-year-separator"/>
         <xsl:map-entry key="QName('', 'date-date-format')" select="$date-date-format"/>
         <xsl:map-entry key="QName('', 'date-dateTime-format')" select="$date-dateTime-format"/>
         <xsl:map-entry key="QName('', 'dc-metadata')" select="$dc-metadata"/>
         <xsl:map-entry key="QName('', 'default-float-style')" select="$default-float-style"/>
         <xsl:map-entry key="QName('', 'default-language')" select="$default-language"/>
         <xsl:map-entry key="QName('', 'default-length-magnitude')"
                         select="$default-length-magnitude"/>
         <xsl:map-entry key="QName('', 'default-length-unit')" select="$default-length-unit"/>
         <xsl:map-entry key="QName('', 'personal-name-style')" select="$personal-name-style"/>
         <xsl:map-entry key="QName('', 'default-theme')" select="$default-theme"/>
         <xsl:map-entry key="QName('', 'division-numbers')" select="$division-numbers"/>
         <xsl:map-entry key="QName('', 'division-numbers-inherit')"
                         select="$division-numbers-inherit"/>
         <xsl:map-entry key="QName('', 'docbook-transclusion')" select="$docbook-transclusion"/>
         <xsl:map-entry key="QName('', 'dynamic-profile-error')"
                         select="$dynamic-profile-error"/>
         <xsl:map-entry key="QName('', 'dynamic-profiles')" select="$dynamic-profiles"/>
         <xsl:map-entry key="QName('', 'experimental-pmuj')" select="$experimental-pmuj"/>
         <xsl:map-entry key="QName('', 'footnote-numeration')" select="$footnote-numeration"/>
         <xsl:map-entry key="QName('', 'formal-object-title-placement')"
                         select="$formal-object-title-placement"/>
         <xsl:map-entry key="QName('', 'mediaobject-details-placement')"
                         select="$mediaobject-details-placement"/>
         <xsl:map-entry key="QName('', 'formalgroup-nested-object-title-placement')"
                         select="$formalgroup-nested-object-title-placement"/>
         <xsl:map-entry key="QName('', 'funcsynopsis-default-style')"
                         select="$funcsynopsis-default-style"/>
         <xsl:map-entry key="QName('', 'funcsynopsis-table-threshold')"
                         select="$funcsynopsis-table-threshold"/>
         <xsl:map-entry key="QName('', 'funcsynopsis-trailing-punctuation')"
                         select="$funcsynopsis-trailing-punctuation"/>
         <xsl:map-entry key="QName('', 'generate-html-page')" select="$generate-html-page"/>
         <xsl:map-entry key="QName('', 'generate-index')" select="$generate-index"/>
         <xsl:map-entry key="QName('', 'generate-nested-toc')" select="$generate-nested-toc"/>
         <xsl:map-entry key="QName('', 'generate-toc')" select="$generate-toc"/>
         <xsl:map-entry key="QName('', 'generate-trivial-toc')" select="$generate-trivial-toc"/>
         <xsl:map-entry key="QName('', 'generated-id-root')" select="$generated-id-root"/>
         <xsl:map-entry key="QName('', 'generated-id-sep')" select="$generated-id-sep"/>
         <xsl:map-entry key="QName('', 'generator-metadata')" select="$generator-metadata"/>
         <xsl:map-entry key="QName('', 'gentext-language')" select="$gentext-language"/>
         <xsl:map-entry key="QName('', 'glossary-collection')" select="$glossary-collection"/>
         <xsl:map-entry key="QName('', 'glossary-sort-entries')"
                         select="$glossary-sort-entries"/>
         <xsl:map-entry key="QName('', 'html-extension')" select="$html-extension"/>
         <xsl:map-entry key="QName('', 'image-ignore-scaling')" select="$image-ignore-scaling"/>
         <xsl:map-entry key="QName('', 'image-nominal-height')" select="$image-nominal-height"/>
         <xsl:map-entry key="QName('', 'image-nominal-width')" select="$image-nominal-width"/>
         <xsl:map-entry key="QName('', 'image-property-warning')"
                         select="$image-property-warning"/>
         <xsl:map-entry key="QName('', 'index-on-type')" select="$index-on-type"/>
         <xsl:map-entry key="QName('', 'index-on-role')" select="$index-on-role"/>
         <xsl:map-entry key="QName('', 'index-show-entries')" select="$index-show-entries"/>
         <xsl:map-entry key="QName('', 'indexed-section-groups')"
                         select="$indexed-section-groups"/>
         <xsl:map-entry key="QName('', 'lists-of-equations')" select="$lists-of-equations"/>
         <xsl:map-entry key="QName('', 'lists-of-examples')" select="$lists-of-examples"/>
         <xsl:map-entry key="QName('', 'lists-of-figures')" select="$lists-of-figures"/>
         <xsl:map-entry key="QName('', 'lists-of-procedures')" select="$lists-of-procedures"/>
         <xsl:map-entry key="QName('', 'lists-of-tables')" select="$lists-of-tables"/>
         <xsl:map-entry key="QName('', 'local-conventions')" select="$local-conventions"/>
         <xsl:map-entry key="QName('', 'mathml-js')" select="$mathml-js"/>
         <xsl:map-entry key="QName('', 'mediaobject-accessibility')"
                         select="$mediaobject-accessibility"/>
         <xsl:map-entry key="QName('', 'mediaobject-exclude-extensions')"
                         select="$mediaobject-exclude-extensions"/>
         <xsl:map-entry key="QName('', 'mediaobject-input-base-uri')"
                         select="$mediaobject-input-base-uri"/>
         <xsl:map-entry key="QName('', 'mediaobject-grouped-by-type')"
                         select="$mediaobject-grouped-by-type"/>
         <xsl:map-entry key="QName('', 'mediaobject-output-base-uri')"
                         select="$mediaobject-output-base-uri"/>
         <xsl:map-entry key="QName('', 'mediaobject-output-paths')"
                         select="$mediaobject-output-paths"/>
         <xsl:map-entry key="QName('', 'mediaobject-video-element')"
                         select="$mediaobject-video-element"/>
         <xsl:map-entry key="QName('', 'nominal-page-width')" select="$nominal-page-width"/>
         <xsl:map-entry key="QName('', 'number-single-appendix')"
                         select="$number-single-appendix"/>
         <xsl:map-entry key="QName('', 'olink-databases')" select="$olink-databases"/>
         <xsl:map-entry key="QName('', 'orderedlist-item-numeration')"
                         select="$orderedlist-item-numeration"/>
         <xsl:map-entry key="QName('', 'othername-in-middle')" select="$othername-in-middle"/>
         <xsl:map-entry key="QName('', 'output-media')" select="$output-media"/>
         <xsl:map-entry key="QName('', 'oxy-markup')" select="$oxy-markup"/>
         <xsl:map-entry key="QName('', 'pagetoc-elements')" select="$pagetoc-elements"/>
         <xsl:map-entry key="QName('', 'pagetoc-dynamic')" select="$pagetoc-dynamic"/>
         <xsl:map-entry key="QName('', 'pagetoc-js')" select="$pagetoc-js"/>
         <xsl:map-entry key="QName('', 'page-style')" select="$page-style"/>
         <xsl:map-entry key="QName('', 'paper-size')" select="$paper-size"/>
         <xsl:map-entry key="QName('', 'persistent-toc')" select="$persistent-toc"/>
         <xsl:map-entry key="QName('', 'persistent-toc-css')" select="$persistent-toc-css"/>
         <xsl:map-entry key="QName('', 'persistent-toc-filename')"
                         select="$persistent-toc-filename"/>
         <xsl:map-entry key="QName('', 'persistent-toc-js')" select="$persistent-toc-js"/>
         <xsl:map-entry key="QName('', 'persistent-toc-search')"
                         select="$persistent-toc-search"/>
         <xsl:map-entry key="QName('', 'pixels-per-inch')" select="$pixels-per-inch"/>
         <xsl:map-entry key="QName('', 'procedure-step-numeration')"
                         select="$procedure-step-numeration"/>
         <xsl:map-entry key="QName('', 'productionset-lhs-rhs-separator')"
                         select="$productionset-lhs-rhs-separator"/>
         <xsl:map-entry key="QName('', 'profile-arch')" select="$profile-arch"/>
         <xsl:map-entry key="QName('', 'profile-audience')" select="$profile-audience"/>
         <xsl:map-entry key="QName('', 'profile-condition')" select="$profile-condition"/>
         <xsl:map-entry key="QName('', 'profile-conformance')" select="$profile-conformance"/>
         <xsl:map-entry key="QName('', 'profile-lang')" select="$profile-lang"/>
         <xsl:map-entry key="QName('', 'profile-os')" select="$profile-os"/>
         <xsl:map-entry key="QName('', 'profile-outputformat')" select="$profile-outputformat"/>
         <xsl:map-entry key="QName('', 'profile-revision')" select="$profile-revision"/>
         <xsl:map-entry key="QName('', 'profile-revisionflag')" select="$profile-revisionflag"/>
         <xsl:map-entry key="QName('', 'profile-role')" select="$profile-role"/>
         <xsl:map-entry key="QName('', 'profile-security')" select="$profile-security"/>
         <xsl:map-entry key="QName('', 'profile-separator')" select="$profile-separator"/>
         <xsl:map-entry key="QName('', 'profile-userlevel')" select="$profile-userlevel"/>
         <xsl:map-entry key="QName('', 'profile-vendor')" select="$profile-vendor"/>
         <xsl:map-entry key="QName('', 'profile-wordsize')" select="$profile-wordsize"/>
         <xsl:map-entry key="QName('', 'theme-picker')" select="$theme-picker"/>
         <xsl:map-entry key="QName('', 'transclusion-id-fixup')"
                         select="$transclusion-id-fixup"/>
         <xsl:map-entry key="QName('', 'transclusion-link-scope')"
                         select="$transclusion-link-scope"/>
         <xsl:map-entry key="QName('', 'transclusion-prefix-separator')"
                         select="$transclusion-prefix-separator"/>
         <xsl:map-entry key="QName('', 'transclusion-suffix')" select="$transclusion-suffix"/>
         <xsl:map-entry key="QName('', 'qandadiv-default-toc')" select="$qandadiv-default-toc"/>
         <xsl:map-entry key="QName('', 'qandaset-default-label')"
                         select="$qandaset-default-label"/>
         <xsl:map-entry key="QName('', 'qandaset-default-toc')" select="$qandaset-default-toc"/>
         <xsl:map-entry key="QName('', 'relax-ng-grammar')" select="$relax-ng-grammar"/>
         <xsl:map-entry key="QName('', 'refentry-generate-name')"
                         select="$refentry-generate-name"/>
         <xsl:map-entry key="QName('', 'refentry-generate-title')"
                         select="$refentry-generate-title"/>
         <xsl:map-entry key="QName('', 'resource-base-uri')" select="$resource-base-uri"/>
         <xsl:map-entry key="QName('', 'revhistory-style')" select="$revhistory-style"/>
         <xsl:map-entry key="QName('', 'section-numbers')" select="$section-numbers"/>
         <xsl:map-entry key="QName('', 'section-numbers-inherit')"
                         select="$section-numbers-inherit"/>
         <xsl:map-entry key="QName('', 'section-toc-depth')" select="$section-toc-depth"/>
         <xsl:map-entry key="QName('', 'segmentedlist-style')" select="$segmentedlist-style"/>
         <xsl:map-entry key="QName('', 'show-remarks')" select="$show-remarks"/>
         <xsl:map-entry key="QName('', 'sidebar-as-aside')" select="$sidebar-as-aside"/>
         <xsl:map-entry key="QName('', 'sort-collation')" select="$sort-collation"/>
         <xsl:map-entry key="QName('', 'table-accessibility')" select="$table-accessibility"/>
         <xsl:map-entry key="QName('', 'table-footnote-numeration')"
                         select="$table-footnote-numeration"/>
         <xsl:map-entry key="QName('', 'use-docbook-css')" select="$use-docbook-css"/>
         <xsl:map-entry key="QName('', 'use-minified-css')" select="$use-minified-css"/>
         <xsl:map-entry key="QName('', 'user-css-links')" select="$user-css-links"/>
         <xsl:map-entry key="QName('', 'variablelist-termlength-threshold')"
                         select="$variablelist-termlength-threshold"/>
         <xsl:map-entry key="QName('', 'verbatim-callouts')" select="$verbatim-callouts"/>
         <xsl:map-entry key="QName('', 'verbatim-line-style')" select="$verbatim-line-style"/>
         <xsl:map-entry key="QName('', 'verbatim-number-every-nth')"
                         select="$verbatim-number-every-nth"/>
         <xsl:map-entry key="QName('', 'verbatim-number-first-line')"
                         select="$verbatim-number-first-line"/>
         <xsl:map-entry key="QName('', 'verbatim-number-minlines')"
                         select="$verbatim-number-minlines"/>
         <xsl:map-entry key="QName('', 'verbatim-number-separator')"
                         select="$verbatim-number-separator"/>
         <xsl:map-entry key="QName('', 'verbatim-numbered-elements')"
                         select="$verbatim-numbered-elements"/>
         <xsl:map-entry key="QName('', 'verbatim-plain-style')" select="$verbatim-plain-style"/>
         <xsl:map-entry key="QName('', 'verbatim-space')" select="$verbatim-space"/>
         <xsl:map-entry key="QName('', 'verbatim-style-default')"
                         select="$verbatim-style-default"/>
         <xsl:map-entry key="QName('', 'verbatim-syntax-highlight-css')"
                         select="$verbatim-syntax-highlight-css"/>
         <xsl:map-entry key="QName('', 'verbatim-syntax-highlight-languages')"
                         select="$verbatim-syntax-highlight-languages"/>
         <xsl:map-entry key="QName('', 'verbatim-syntax-highlighter')"
                         select="$verbatim-syntax-highlighter"/>
         <xsl:map-entry key="QName('', 'verbatim-table-style')" select="$verbatim-table-style"/>
         <xsl:map-entry key="QName('', 'verbatim-trim-leading-blank-lines')"
                         select="$verbatim-trim-leading-blank-lines"/>
         <xsl:map-entry key="QName('', 'verbatim-trim-trailing-blank-lines')"
                         select="$verbatim-trim-trailing-blank-lines"/>
         <xsl:map-entry key="QName('', 'xlink-arclist-before')" select="$xlink-arclist-before"/>
         <xsl:map-entry key="QName('', 'xlink-arclist-after')" select="$xlink-arclist-after"/>
         <xsl:map-entry key="QName('', 'xlink-arclist-titlesep')"
                         select="$xlink-arclist-titlesep"/>
         <xsl:map-entry key="QName('', 'xlink-arclist-sep')" select="$xlink-arclist-sep"/>
         <xsl:map-entry key="QName('', 'xlink-icon-closed')" select="$xlink-icon-closed"/>
         <xsl:map-entry key="QName('', 'xlink-icon-open')" select="$xlink-icon-open"/>
         <xsl:map-entry key="QName('', 'xlink-js')" select="$xlink-js"/>
         <xsl:map-entry key="QName('', 'xlink-style')" select="$xlink-style"/>
         <xsl:map-entry key="QName('', 'xlink-style-default')" select="$xlink-style-default"/>
         <xsl:map-entry key="QName('', 'xspec')" select="$xspec"/>
         <xsl:map-entry key="QName('', 'transform-original')" select="$transform-original"/>
         <xsl:map-entry key="QName('', 'transform-before')" select="$transform-before"/>
         <xsl:map-entry key="QName('', 'transform-after')" select="$transform-after"/>
         <xsl:map-entry key="QName('', 'dynamic-profile-variables')"
                         select="$dynamic-profile-variables"/>
         <xsl:map-entry key="QName('', 'warn-about-missing-localizations')"
                         select="$warn-about-missing-localizations"/>
         <xsl:map-entry key="QName('', 'sets-number-from')" select="$sets-number-from"/>
         <xsl:map-entry key="QName('', 'books-number-from')" select="$books-number-from"/>
         <xsl:map-entry key="QName('', 'divisions-number-from')"
                         select="$divisions-number-from"/>
         <xsl:map-entry key="QName('', 'components-number-from')"
                         select="$components-number-from"/>
         <xsl:map-entry key="QName('', 'sections-number-from')" select="$sections-number-from"/>
         <xsl:map-entry key="QName('', 'formal-objects-number-from')"
                         select="$formal-objects-number-from"/>
         <xsl:map-entry key="QName('', 'sets-inherit-from')" select="$sets-inherit-from"/>
         <xsl:map-entry key="QName('', 'books-inherit-from')" select="$books-inherit-from"/>
         <xsl:map-entry key="QName('', 'divisions-inherit-from')"
                         select="$divisions-inherit-from"/>
         <xsl:map-entry key="QName('', 'components-inherit-from')"
                         select="$components-inherit-from"/>
         <xsl:map-entry key="QName('', 'sections-inherit-from')"
                         select="$sections-inherit-from"/>
         <xsl:map-entry key="QName('', 'formal-objects-inherit-from')"
                         select="$formal-objects-inherit-from"/>
         <xsl:map-entry key="QName('', 'unwrap-paragraphs')" select="$unwrap-paragraphs"/>
         <xsl:map-entry key="QName('', 'fallback-js')" select="$fallback-js"/>
         <xsl:map-entry key="QName('', 'message-level')" select="$message-level"/>
         <xsl:map-entry key="QName('', 'copy-verbatim-js')" select="$copy-verbatim-js"/>
         <xsl:map-entry key="QName('', 'translate-suppress-elements')"
                         select="$translate-suppress-elements"/>
         <xsl:map-entry key="QName('', 'varlistentry-separate-terms')"
                         select="$varlistentry-separate-terms"/>
         <xsl:map-entry key="QName('', 'presentation-mode')" select="$presentation-mode"/>
         <xsl:map-entry key="QName('', 'presentation-js')" select="$presentation-js"/>
         <xsl:map-entry key="QName('', 'presentation-css')" select="$presentation-css"/>
      </xsl:map>
   </xsl:variable>
</xsl:stylesheet>

VERSION.xsl

2 variables (1 used only in one other module)

Instructions
Variable $v:VERSION
Variable $v:VERSION-ID
Used by: template
Used in: modules/head.xsl
Source code
1
2
3
4
5
6
7
<xsl:stylesheet xmlns:v="http://docbook.org/ns/docbook/variables"
                 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                 version="3.0">
   <xsl:variable name="v:VERSION" select="'2.1.6'"/>
   <xsl:variable name="v:VERSION-ID" select="'cf0b935'"/>
</xsl:stylesheet>

variable.xsl

60 variables (1 unused, 50 used only in one other module)

Instructions
Variable $v:as-xml
Used by: template
Variable $v:custom-localizations as document-node()?
Variable $v:localization-base-uri
Variable $vp:section-toc-depth as xs:integer
Variable $v:verbatim-table-style
Variable $v:verbatim-line-style
Variable $v:verbatim-plain-style as xs:string*
Variable $v:verbatim-space as node()
Variable $v:verbatim-numbered-elements as xs:string*
Variable $v:verbatim-number-minlines
Variable $v:verbatim-number-every-nth
Variable $v:verbatim-number-first-line
Variable $v:verbatim-callouts as xs:string*
Variable $v:verbatim-syntax-highlight-languages
Variable $v:verbatim-syntax-highlight-options
Variable $v:verbatim-syntax-highlight-pygments-options
Variable $v:mediaobject-output-base-uri as xs:string?
Variable $v:mediaobject-exclude-extensions
Variable $vp:mediaobject-accessibility
Variable $vp:table-accessibility
Variable $v:personal-name-styles
Used by: template
Used in: modules/info.xsl
Variable $v:formal-object-title-placement as map(xs:string,xs:string)
Variable $v:formalgroup-nested-object-title-placement as map(xs:string,xs:string)
Variable $v:mediaobject-details-placement as map(xs:string,xs:string)
Variable $v:arg-choice-opt-open-str
Variable $v:arg-choice-opt-close-str
Variable $v:arg-choice-req-open-str
Variable $v:arg-choice-req-close-str
Variable $v:arg-choice-plain-open-str
Variable $v:arg-choice-plain-close-str
Variable $v:arg-choice-def-open-str
Variable $v:arg-choice-def-close-str
Variable $v:arg-rep-repeat-str
Variable $v:arg-rep-norepeat-str
Variable $v:arg-rep-def-str
Variable $v:arg-or-sep
Used by: template
Variable $v:chunk-renumber-footnotes as xs:boolean
Variable $v:chunk-filter-namespaces as namespace-node()*
Variable $v:admonition-icons
Used by: template
Variable $v:annotation-close as element()
Used by: template
Used in: main.xsl
Variable $v:nominal-page-width
Variable $v:image-nominal-width
Variable $v:image-nominal-height
Variable $v:toc-open as element()
Variable $v:toc-close as element()
Variable $vp:pagetoc-elements as xs:string*
Variable $vp:olinkdb
Used by: template
Used in: modules/titles.xsl
Variable $v:theme-list as element()*
Variable $vp:random-prefix as xs:string
Variable $vp:js-controls as element()*
Variable $v:highlight-js-head-elements as element()*
Variable $v:prism-js-head-elements as element()*
Variable $v:media-type-default as xs:string
Used by: template
Variable $v:media-type-map as map(xs:string, xs:string)
Source code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:db="http://docbook.org/ns/docbook"
                xmlns:ext="http://docbook.org/extensions/xslt"
                xmlns:f="http://docbook.org/ns/docbook/functions"
                xmlns:fp="http://docbook.org/ns/docbook/functions/private"
                xmlns:h="http://www.w3.org/1999/xhtml"
                xmlns:ls="http://docbook.org/ns/docbook/l10n/source"
                xmlns:m="http://docbook.org/ns/docbook/modes"
                xmlns:v="http://docbook.org/ns/docbook/variables"
                xmlns:vp="http://docbook.org/ns/docbook/variables/private"
                xmlns:xs="http://www.w3.org/2001/XMLSchema"
                xmlns="http://www.w3.org/1999/xhtml"
                default-mode="m:docbook"
                exclude-result-prefixes="#all"
                version="3.0">

<!-- Note: These are variables used by the stylesheet. Many are
     initialized by parsing parameters defined in param.xsl. They're
     in a separate stylesheet to make the pipelines cleaner. -->

<!-- Some them are initialized using content instead of a select
     attribute in order to make the reference page in the Guide work
     better. -->

<xsl:variable name="v:as-json" select="map {'method':'json','indent':true()}"/>
<xsl:variable name="v:as-xml" select="map {'method':'xml','indent':true()}"/>

<xsl:variable name="v:custom-localizations" as="document-node()?"
              select="()"/>

<xsl:variable name="v:localization-base-uri"
              select="resolve-uri('../locale/', static-base-uri())"/>

<xsl:variable name="v:chunk" as="xs:boolean"
              select="not(normalize-space($chunk) = '')"/>

<xsl:variable name="vp:section-toc-depth" as="xs:integer">
  <xsl:choose>
    <xsl:when test="$section-toc-depth instance of xs:integer">
      <xsl:sequence select="max((0, $section-toc-depth))"/>
    </xsl:when>
    <xsl:when test="$section-toc-depth castable as xs:integer">
      <xsl:sequence select="max((0, xs:integer($section-toc-depth)))"/>
    </xsl:when>
    <xsl:when test="string($section-toc-depth) = 'unbounded'">
      <xsl:sequence select="2147483647"/> <!-- 0x7fffffff -->
    </xsl:when>
    <xsl:otherwise>
      <xsl:sequence select="0"/>
    </xsl:otherwise>
  </xsl:choose>
</xsl:variable>

<xsl:variable name="v:debug" static="yes" as="xs:string*"
              select="tokenize($debug, '[,\s]+') ! normalize-space(.)"/>

<xsl:variable name="v:verbatim-table-style"
              select="tokenize($verbatim-table-style, '\s+')"/>

<xsl:variable name="v:verbatim-line-style"
              select="tokenize($verbatim-line-style, '\s+')"/>

<xsl:variable name="v:verbatim-plain-style" as="xs:string*"
              select="tokenize($verbatim-plain-style, '\s+')"/>

<xsl:variable name="v:verbatim-space" as="node()">
  <xsl:value-of select="substring($verbatim-space || ' ', 1, 1)"/>
</xsl:variable>

<xsl:variable name="v:verbatim-numbered-elements" as="xs:string*"
              select="tokenize($verbatim-numbered-elements, '\s+')"/>

<xsl:variable name="v:verbatim-number-minlines"
              select="xs:integer($verbatim-number-minlines)"/>

<xsl:variable name="v:verbatim-number-every-nth"
              select="xs:integer($verbatim-number-every-nth)"/>

<xsl:variable name="v:verbatim-number-first-line"
              select="f:is-true($verbatim-number-first-line)"/>

<xsl:variable name="v:verbatim-callouts" as="xs:string*"
              select="tokenize($verbatim-callouts, '\s+')"/>

<xsl:variable name="v:verbatim-syntax-highlight-languages"
              select="tokenize($verbatim-syntax-highlight-languages, '\s+')"/>
<xsl:variable name="v:verbatim-syntax-highlight-options"
           select="map { }"/>
<xsl:variable name="v:verbatim-syntax-highlight-pygments-options"
           select="map { }"/>

<xsl:variable name="v:mediaobject-output-base-uri" as="xs:string?">
  <xsl:message use-when="'mediaobject-uris' = $v:debug"
               select="'Mediaobject out. base URI:',
                       if (empty($mediaobject-output-base-uri))
                       then ()
                       else if (ends-with($mediaobject-output-base-uri, '/'))
                            then $mediaobject-output-base-uri
                            else $mediaobject-output-base-uri || '/'"/>
  <xsl:sequence select="if (empty($mediaobject-output-base-uri))
                        then ()
                        else if (ends-with($mediaobject-output-base-uri, '/'))
                             then $mediaobject-output-base-uri
                             else $mediaobject-output-base-uri || '/'"/>
</xsl:variable>

<xsl:variable name="v:mediaobject-exclude-extensions"
              select="tokenize($mediaobject-exclude-extensions, '\s+')"/>

<xsl:variable name="vp:mediaobject-accessibility"
              select="tokenize($mediaobject-accessibility, '\s+')"/>

<xsl:variable name="vp:table-accessibility"
              select="tokenize($table-accessibility, '\s+')"/>

<xsl:variable name="v:personal-name-styles"
              select="('first-last', 'last-first', 'FAMILY-given')"/>

<xsl:variable name="v:formal-object-title-placement" as="map(xs:string,xs:string)"
              select="fp:parse-key-value-pairs(
                        tokenize($formal-object-title-placement, '\s+'))"/>

<xsl:variable name="v:formalgroup-nested-object-title-placement" as="map(xs:string,xs:string)"
              select="fp:parse-key-value-pairs(
                        tokenize($formal-object-title-placement, '\s+'))"/>

<xsl:variable name="v:mediaobject-details-placement" as="map(xs:string,xs:string)"
              select="fp:parse-key-value-pairs(
                        tokenize($mediaobject-details-placement, '\s+'))"/>

<xsl:variable name="v:arg-choice-opt-open-str"><span class="cmdpunct">[</span></xsl:variable>
<xsl:variable name="v:arg-choice-opt-close-str"><span class="cmdpunct">]</span></xsl:variable>
<xsl:variable name="v:arg-choice-req-open-str"><span class="cmdpunct">{</span></xsl:variable>
<xsl:variable name="v:arg-choice-req-close-str"><span class="cmdpunct">}</span></xsl:variable>
<xsl:variable name="v:arg-choice-plain-open-str"><xsl:text></xsl:text></xsl:variable>
<xsl:variable name="v:arg-choice-plain-close-str"><xsl:text></xsl:text></xsl:variable>
<xsl:variable name="v:arg-choice-def-open-str"><span class="cmdpunct">[</span></xsl:variable>
<xsl:variable name="v:arg-choice-def-close-str"><span class="cmdpunct">]</span></xsl:variable>
<xsl:variable name="v:arg-rep-repeat-str"><span class="cmdpunct">…</span></xsl:variable>
<xsl:variable name="v:arg-rep-norepeat-str"><xsl:text></xsl:text></xsl:variable>
<xsl:variable name="v:arg-rep-def-str"><xsl:text></xsl:text></xsl:variable>
<xsl:variable name="v:arg-or-sep"><span class="cmdpunct"> | </span></xsl:variable>

<xsl:variable name="vp:user-css-links"
              select="tokenize(normalize-space($user-css-links), '\s+')"/>

<xsl:variable name="v:chunk-renumber-footnotes" as="xs:boolean"
              select="f:is-true($chunk-renumber-footnotes)"/>

<xsl:variable name="v:chunk-filter-namespaces" as="namespace-node()*">
  <xsl:namespace name="db" select="'http://docbook.org/ns/docbook'"/>
</xsl:variable>

<!-- Make sure we've resolved it so that file:///, file://, file:/, etc.
     get normalized because later on we're going to want to compare
     the prefix of this base URI with the prefix of another URI. -->
<xsl:variable name="vp:chunk-output-base-uri" as="xs:anyURI?">
  <xsl:choose>
    <xsl:when use-when="function-available('ext:cwd')"
              test="true()">
      <xsl:if test="'chunks' = $v:debug">
        <xsl:message select="'Chunk output base uri:',
                             resolve-uri($chunk-output-base-uri, ext:cwd())"/>
      </xsl:if>
      <xsl:sequence select="resolve-uri($chunk-output-base-uri, ext:cwd())"/>
    </xsl:when>
    <xsl:when test="$v:chunk">
      <xsl:if test="'chunks' = $v:debug">
        <xsl:message select="'Chunk output base uri:', $chunk-output-base-uri"/>
      </xsl:if>
      <xsl:sequence select="xs:anyURI($chunk-output-base-uri)"/>
    </xsl:when>
    <xsl:otherwise>
      <xsl:sequence select="xs:anyURI($chunk-output-base-uri)"/>
    </xsl:otherwise>
  </xsl:choose>
</xsl:variable>

<!-- I tinkered a bit to find images that would display across
     a variety of devices. YMMV. Beware: Pygmentize on Windows
     doesn't use UTF-8 by default, so bad can happen. -->
<xsl:variable name="v:admonition-icons">
  <db:tip>☞</db:tip>
  <db:note>ⓘ</db:note>
  <db:important>☝</db:important>
  <db:caution>⚠</db:caution>
  <db:warning>🛑</db:warning>
  <db:danger>⚡</db:danger>
</xsl:variable>

<xsl:variable name="v:annotation-close" as="element()">
  <span>╳</span>
</xsl:variable>

<xsl:variable name="v:nominal-page-width"
              select="f:parse-length($nominal-page-width)"/>
<xsl:variable name="v:image-nominal-width"
              select="f:parse-length($image-nominal-width)"/>
<xsl:variable name="v:image-nominal-height"
              select="f:parse-length($image-nominal-height)"/>

<xsl:variable name="v:toc-open" as="element()">
  <img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAQCAYAAAAWGF8bAAAACXBIWXMAABYlAAAWJQFJUiTwAAABDklEQVQ4je2UUW3EMAyGv0wDUAhlkDBIyuAYXCEclEJoGZRBUgYOgzJoGHgPW6o7rWq35+2TIkWW9duW7N+oKuM46jiOGGMAaNsW5xzee5xzn8EvRESXZUFEWNcVAFWl73v6vjcGUIAYIyEEANZ1RUSY55lSCo/HA4BhGGiahtvthnOOtm0BSCnRdd1eVAGNMeoR27aptVattbpt22FOjFGrzjsX1I7q/4q3y4xf8i/4FwT3Pcw5Y4zBWvujfQMopZBzJuf8XbCeVyWEgHOO+/2+x0SEaZpIKSEih0X2Wz6jdlxKuezaqL7qpZS0lLKbw/M4ANba3RyapiGE8OJGqOrpizGq916999VATvM/AGFn1sxsVjL5AAAAAElFTkSuQmCC"
       alt="[toc]"/>
</xsl:variable>

<xsl:variable name="v:toc-close" as="element()">
  <img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAACXBIWXMAABYlAAAWJQFJUiTwAAAAtklEQVQ4jaWT0Q3DIAxEz52AEbyB2cDZhBEY3SNcPyqqBEwqpZaQAHNP5jBCEiJCPAiSIgAeiUe8zoveO9x9e9jd0XtfKwHA1hpHtNY49rO8u59zn4mqMiJSyFkcEVTVFQCAtdYFMotrrXN111JnyA/xCsggN2JeXmGEmaGU8l2XUmBm29fZuh0RW2PTK2SGZcamADPb3nmGmNkKOI7j1rAzJG2kcWhqkstQ1QX+/2ciKU/FJOUN6JFZYWpmK3sAAAAASUVORK5CYII="
       alt="X"/>
</xsl:variable>

<xsl:variable name="vp:pagetoc-elements" as="xs:string*"
              select="tokenize($pagetoc-elements, '\s+')"/>

<xsl:variable name="vp:olinkdb" select="false()"/>

<xsl:variable name="v:olink-databases" as="element(h:targetdb)*">
  <xsl:if test="normalize-space($olink-databases) != ''">
    <xsl:for-each select="tokenize($olink-databases, ',\s*') ! normalize-space(.)">
      <xsl:variable name="db" select="."/>
      <xsl:try>
        <xsl:variable name="olinkdb" select="doc($db)/h:targetdb"/>
        <xsl:if test="empty($olinkdb)">
          <xsl:message select="'No targets in olinkdb:', $db"/>
        </xsl:if>
        <xsl:sequence select="$olinkdb"/>
        <xsl:catch>
          <xsl:message select="'Failed to load olinkdb:', $db"/>
        </xsl:catch>
      </xsl:try>
    </xsl:for-each>
  </xsl:if>
</xsl:variable>

<xsl:variable name="v:theme-list" as="element()*">
  <theme name="Materials dark" id="materials-dark" dark="true"/>
  <theme name="Materials light" id="materials-light" dark="false"/>
</xsl:variable>

<xsl:variable name="vp:random-prefix" as="xs:string">
  <xsl:variable name="chars"
                select="('a','b','c','d','e','f','_','_','_','1','2','3','4','5','6')"/>
  <xsl:sequence select="string-join(random-number-generator()?permute($chars), '')"/>
</xsl:variable>

<xsl:variable name="vp:js-controls" as="element()*">
  <xsl:variable name="random" select="$vp:random-prefix"/>
  <span class="controls-open">☰</span>
  <div class="js-controls-wrapper">
    <xsl:if test="$v:theme-list[@dark='true']">
      <xsl:attribute name="db-dark-theme"
                     select="($v:theme-list[@dark='true'])[1]/@id"/>
    </xsl:if>
    <div class="js-controls-body">
      <div class="js-controls-header">
        <div class="js-controls-close">╳</div>
        <div class="js-controls-title">
          <xsl:text>Settings</xsl:text>
        </div>
      </div>
      <div class="js-controls-content">
        <fieldset db-random="{$random}" class="js-controls-toggles">
          <legend>Select options:</legend>
          <input id="db-js-annotations_{$random}" type="checkbox" value="js" />
          <label for="db-js-annotations_{$random}">JavaScript annotations</label><br/>
          <input id="db-js-xlinks_{$random}" type="checkbox" value="js" />
          <label for="db-js-xlinks_{$random}">JavaScript extended links</label><br/>
        </fieldset>
        <div id="db-js-controls-reload_{$random}" class="js-controls-reload"></div>
        <fieldset>
          <legend>Choose a theme:</legend>
          <input id="db-default-theme_{$random}" type="radio" name="db-theme" value="default" />
          <label for="db-default-theme_{$random}">Default</label><br/>
          <xsl:for-each select="$v:theme-list">
            <input id="db-theme-{@id}-{$random}"
                   type="radio" name="db-theme" value="{@id}" />
            <label for="db-theme-{@id}-{$random}">
              <xsl:sequence select="@name/string()"/>
            </label>
            <br/>
          </xsl:for-each>
        </fieldset>
      </div>
      <div class="js-controls-buttons">
        <button id="js-controls-cancel">✗</button>
        <xsl:text> </xsl:text>
        <button id="js-controls-ok">✓</button>
      </div>
    </div>
  </div>
</xsl:variable>

<!-- N.B. There's a bit of a hack in the variables below. We put the
     link and script elements in the same variable, but we use them in
     two different places so that the h:link element(s) precede the
     DocBook CSS files (in order to support overrides with cascade).
     -->

<xsl:variable name="v:highlight-js-head-elements" as="element()*">
  <link rel="stylesheet"
        href="{$resource-base-uri}css/highlight-11.6.0.min.css" />
  <script src="{$resource-base-uri}js/highlight-11.6.0.min.js"></script>
  <script>hljs.highlightAll();</script>
</xsl:variable>

<xsl:variable name="v:prism-js-head-elements" as="element()*">
  <link rel="stylesheet" href="{$resource-base-uri}css/prism.css"/>
  <script src="{$resource-base-uri}js/prism.js"></script>
</xsl:variable>

<!-- ============================================================ -->

<xsl:variable name="v:media-type-default" as="xs:string"
              select="'application/octet-stream'"/>

  <!-- Credit: https://developer.mozilla.org/en-US/docs/Web/HTTP/\
       Basics_of_HTTP/MIME_types/Common_types -->
  <!-- I left out the .3gp and .3g2 extensions because they're either audio or
       video depending on what they actually contain and that's more complicated
       than just an extension lookup
       I added .text, .mov, .m3u8, .wmv
  -->
<xsl:variable name="v:media-type-map" as="map(xs:string, xs:string)">
  <xsl:map>
    <xsl:map-entry key="'.aac'" select="'audio/aac'"/>
    <xsl:map-entry key="'.abw'" select="'application/x-abiword'"/>
    <xsl:map-entry key="'.arc'" select="'application/x-freearc'"/>
    <xsl:map-entry key="'.avif'" select="'image/avif'"/>
    <xsl:map-entry key="'.avi'" select="'video/x-msvideo'"/>
    <xsl:map-entry key="'.azw'" select="'application/vnd.amazon.ebook'"/>
    <xsl:map-entry key="'.bin'" select="'application/octet-stream'"/>
    <xsl:map-entry key="'.bmp'" select="'image/bmp'"/>
    <xsl:map-entry key="'.bz'" select="'application/x-bzip'"/>
    <xsl:map-entry key="'.bz2'" select="'application/x-bzip2'"/>
    <xsl:map-entry key="'.cda'" select="'application/x-cdf'"/>
    <xsl:map-entry key="'.csh'" select="'application/x-csh'"/>
    <xsl:map-entry key="'.css'" select="'text/css'"/>
    <xsl:map-entry key="'.csv'" select="'text/csv'"/>
    <xsl:map-entry key="'.doc'" select="'application/msword'"/>
    <xsl:map-entry key="'.docx'"
                   select="'application/vnd.openxmlformats-officedocument.wordprocessingml.document'"/>
    <xsl:map-entry key="'.eot'" select="'application/vnd.ms-fontobject'"/>
    <xsl:map-entry key="'.epub'" select="'application/epub+zip'"/>
    <xsl:map-entry key="'.gz'" select="'application/gzip'"/>
    <xsl:map-entry key="'.gif'" select="'image/gif'"/>
    <xsl:map-entry key="'.htm'" select="'text/html'"/>
    <xsl:map-entry key="'.html'" select="'text/html'"/>
    <xsl:map-entry key="'.ico'" select="'image/vnd.microsoft.icon'"/>
    <xsl:map-entry key="'.ics'" select="'text/calendar'"/>
    <xsl:map-entry key="'.jar'" select="'application/java-archive'"/>
    <xsl:map-entry key="'.jpeg'" select="'image/jpeg'"/>
    <xsl:map-entry key="'.jpg'" select="'image/jpeg'"/>
    <xsl:map-entry key="'.js'" select="'text/javascript'"/>
    <xsl:map-entry key="'.json'" select="'application/json'"/>
    <xsl:map-entry key="'.jsonld'" select="'application/ld+json'"/>
    <xsl:map-entry key="'.mid'" select="'audio/midi'"/>
    <xsl:map-entry key="'.midi'" select="'audio/midi'"/>
    <xsl:map-entry key="'.mjs'" select="'text/javascript'"/>
    <xsl:map-entry key="'.m3u8'" select="'application/x-mpegURL'"/>
    <xsl:map-entry key="'.mp3'" select="'audio/mpeg'"/>
    <xsl:map-entry key="'.mp4'" select="'video/mp4'"/>
    <xsl:map-entry key="'.mpeg'" select="'video/mpeg'"/>
    <xsl:map-entry key="'.mpkg'" select="'application/vnd.apple.installer+xml'"/>
    <xsl:map-entry key="'.mov'" select="'video/quicktime'"/>
    <xsl:map-entry key="'.odp'" select="'application/vnd.oasis.opendocument.presentation'"/>
    <xsl:map-entry key="'.ods'" select="'application/vnd.oasis.opendocument.spreadsheet'"/>
    <xsl:map-entry key="'.odt'" select="'application/vnd.oasis.opendocument.text'"/>
    <xsl:map-entry key="'.oga'" select="'audio/ogg'"/>
    <xsl:map-entry key="'.ogv'" select="'video/ogg'"/>
    <xsl:map-entry key="'.ogx'" select="'application/ogg'"/>
    <xsl:map-entry key="'.opus'" select="'audio/opus'"/>
    <xsl:map-entry key="'.otf'" select="'font/otf'"/>
    <xsl:map-entry key="'.png'" select="'image/png'"/>
    <xsl:map-entry key="'.pdf'" select="'application/pdf'"/>
    <xsl:map-entry key="'.php'" select="'application/x-httpd-php'"/>
    <xsl:map-entry key="'.ppt'" select="'application/vnd.ms-powerpoint'"/>
    <xsl:map-entry key="'.pptx'"
                   select="'application/vnd.openxmlformats-officedocument.presentationml.presentation'"/>
    <xsl:map-entry key="'.rar'" select="'application/vnd.rar'"/>
    <xsl:map-entry key="'.rtf'" select="'application/rtf'"/>
    <xsl:map-entry key="'.sh'" select="'application/x-sh'"/>
    <xsl:map-entry key="'.svg'" select="'image/svg'"/>          <!-- not image/svg+xml for epub -->
    <xsl:map-entry key="'.tar'" select="'application/x-tar'"/>
    <xsl:map-entry key="'.tif'" select="'image/tiff'"/>
    <xsl:map-entry key="'.tiff'" select="'image/tiff'"/>
    <xsl:map-entry key="'.ts'" select="'video/mp2t'"/>
    <xsl:map-entry key="'.ttf'" select="'font/ttf'"/>
    <xsl:map-entry key="'.txt'" select="'text/plain'"/>
    <xsl:map-entry key="'.text'" select="'text/plain'"/>
    <xsl:map-entry key="'.vsd'" select="'application/vnd.visio'"/>
    <xsl:map-entry key="'.wav'" select="'audio/wav'"/>
    <xsl:map-entry key="'.weba'" select="'audio/webm'"/>
    <xsl:map-entry key="'.webm'" select="'video/webm'"/>
    <xsl:map-entry key="'.webp'" select="'image/webp'"/>
    <xsl:map-entry key="'.wmv'" select="'video/x-ms-wmv'"/>
    <xsl:map-entry key="'.woff'" select="'font/woff'"/>
    <xsl:map-entry key="'.woff2'" select="'font/woff2'"/>
    <xsl:map-entry key="'.xhtml'" select="'application/xhtml+xml'"/>
    <xsl:map-entry key="'.xls'" select="'application/vnd.ms-excel'"/>
    <xsl:map-entry key="'.xlsx'"
                   select="'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'"/>
    <xsl:map-entry key="'.xml'" select="'application/xml'"/>
    <xsl:map-entry key="'.xul'" select="'application/vnd.mozilla.xul+xml'"/>
    <xsl:map-entry key="'.zip'" select="'application/zip'"/>
    <xsl:map-entry key="'.7z'" select="'application/x-7z-compressed'"/>
  </xsl:map>
</xsl:variable>

</xsl:stylesheet>

space.xsl

Instructions
Source code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:db="http://docbook.org/ns/docbook"
                xmlns:m="http://docbook.org/ns/docbook/modes"
                xmlns:xs="http://www.w3.org/2001/XMLSchema"
                xmlns="http://www.w3.org/1999/xhtml"
                default-mode="m:docbook"
                exclude-result-prefixes="db m xs"
                version="3.0">

<xsl:preserve-space elements="*"/>

<xsl:strip-space elements="
db:abstract
db:affiliation
db:anchor
db:answer
db:appendix
db:area
db:areaset
db:areaspec
db:artheader
db:article
db:audiodata
db:audioobject
db:author
db:authorblurb
db:authorgroup
db:beginpage
db:bibliodiv
db:biblioentry
db:bibliography
db:biblioset
db:blockquote
db:book
db:bookbiblio
db:bookinfo
db:callout
db:calloutlist
db:caption
db:caution
db:chapter
db:citerefentry
db:classsynopsis
db:cmdsynopsis
db:co
db:colgroup
db:collab
db:colophon
db:colspec
db:confgroup
db:constructorsynopsis
db:copyright
db:danger
db:dedication
db:destructorsynopsis
db:docinfo
db:editor
db:entrytbl
db:epigraph
db:equation
db:example
db:fieldsynopsis
db:figure
db:footnote
db:formalgroup
db:formalpara
db:funcprototype
db:funcsynopsis
db:glossary
db:glossdef
db:glossdiv
db:glossentry
db:glosslist
db:graphicco
db:group
db:highlights
db:imagedata
db:imageobject
db:imageobjectco
db:important
db:index
db:indexdiv
db:indexentry
db:indexterm
db:info
db:informalequation
db:informalexample
db:informalfigure
db:informaltable
db:inlineequation
db:inlinemediaobject
db:itemizedlist
db:itermset
db:keycombo
db:keywordset
db:legalnotice
db:listitem
db:lot
db:mediaobject
db:mediaobjectco
db:menuchoice
db:methodparam
db:methodsynopsis
db:msg
db:msgentry
db:msgexplan
db:msginfo
db:msgmain
db:msgrel
db:msgset
db:msgsub
db:msgtext
db:note
db:objectinfo
db:ooclass
db:ooexception
db:oointerface
db:orderedlist
db:othercredit
db:part
db:partintro
db:preface
db:printhistory
db:procedure
db:productionset
db:programlistingco
db:publisher
db:qandadiv
db:qandaentry
db:qandaset
db:question
db:refentry
db:reference
db:refmeta
db:refnamediv
db:refsect1
db:refsect1info
db:refsect2
db:refsect2info
db:refsect3
db:refsect3info
db:refsynopsisdiv
db:refsynopsisdivinfo
db:revhistory
db:revision
db:row
db:sbr
db:screenco
db:screenshot
db:sect1
db:sect1info
db:sect2
db:sect2info
db:sect3
db:sect3info
db:sect4
db:sect4info
db:sect5
db:sect5info
db:section
db:sectioninfo
db:seglistitem
db:segmentedlist
db:seriesinfo
db:set
db:setindex
db:setinfo
db:shortcut
db:sidebar
db:simplelist
db:simplemsgentry
db:simplesect
db:spanspec
db:step
db:subject
db:subjectset
db:subjectset
db:substeps
db:synopfragment
db:table
db:tr
db:tbody
db:textobject
db:tfoot
db:tgroup
db:thead
db:tip
db:toc
db:tocchap
db:toclevel1
db:toclevel2
db:toclevel3
db:toclevel4
db:toclevel5
db:tocpart
db:varargs
db:variablelist
db:varlistentry
db:videodata
db:videoobject
db:void
db:warning

db:dialogue
db:poetry
db:linegroup
db:speaker
db:person
"/>

</xsl:stylesheet>

unhandled.xsl

2 templates

Instructions
Template match ≅ *
Mode: m:docbook
Matches: *
Template match ≅ h:*
Mode: m:docbook
Matches: h:*
Source code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:f="http://docbook.org/ns/docbook/functions"
                xmlns:m="http://docbook.org/ns/docbook/modes"
                xmlns:xs="http://www.w3.org/2001/XMLSchema"
                xmlns="http://www.w3.org/1999/xhtml"
                default-mode="m:docbook"
                exclude-result-prefixes="f m xs"
                version="3.0">

<xsl:template match="*">
  <xsl:message terminate="yes"
      select="'No template for ' || node-name(.) || ': ' || f:generate-id(.)"/>
  <xsl:variable name="inline-style"
                select="'font: monospace;
                         color: yellow;
                         background-color: red;
                         font-weight: bold;'"/>
  <xsl:variable name="block-style"
                select="'font: monospace;
                         color: yellow;
                         width: 100%;
                         background-color: red;
                         font-weight: bold;'"/>

  <xsl:variable name="inline"
                select="normalize-space(string-join(text(),'')) != ''"/>

  <xsl:element namespace="http://www.w3.org/1999/xhtml"
               name="{if ($inline) then 'span' else 'div'}">

    <xsl:element namespace="http://www.w3.org/1999/xhtml"
                 name="{if ($inline) then 'span' else 'div'}">
      <xsl:attribute name="style"
                     select="if ($inline) then $inline-style else $block-style"/>
      <xsl:text>&lt;</xsl:text>
      <xsl:value-of select="node-name(.)"/>
      <xsl:text>&gt;</xsl:text>
    </xsl:element>

    <xsl:apply-templates/>

    <xsl:element namespace="http://www.w3.org/1999/xhtml"
                 name="{if ($inline) then 'span' else 'div'}">
      <xsl:attribute name="style"
                     select="if ($inline) then $inline-style else $block-style"/>
      <xsl:text>&lt;/</xsl:text>
      <xsl:value-of select="node-name(.)"/>
      <xsl:text>&gt;</xsl:text>
    </xsl:element>
  </xsl:element>

  <!--
    <xsl:message>
      <xsl:text>Unhandled element: </xsl:text>
      <xsl:value-of select="node-name(.)"/>
    </xsl:message>
  -->
</xsl:template>

<xsl:template xmlns:h="http://www.w3.org/1999/xhtml"
              match="h:*">
  <xsl:element name="{local-name(.)}" namespace="http://www.w3.org/1999/xhtml">
    <xsl:copy-of select="@*"/>
    <xsl:apply-templates select="node()"/>
  </xsl:element>
</xsl:template>

</xsl:stylesheet>

errors.xsl

14 variables (3 unused, 11 used only in one other module)

Instructions
Variable $dbe:INVALID-CALS
Variable $dbe:INVALID-AREAREFS
Used by: template
Used in: modules/lists.xsl
Variable $dbe:INVALID-PRODUCTIONRECAP
Used by: template
Variable $dbe:INVALID-CONSTRAINT
Used by: template
Variable $dbe:INVALID-TEMPLATE
Used by: template
Variable $dbe:INTERNAL-RENUMBER-ERROR
Variable $dbe:INTERNAL-HIGHLIGHT-ERROR
Variable $dbe:INVALID-NAME-STYLE
Used by: t:person-name
Used in: modules/info.xsl
Variable $dbe:DYNAMIC-PROFILE-SYNTAX-ERROR
Unused
Variable $dbe:DYNAMIC-PROFILE-EVAL-ERROR
Unused
Variable $dbe:INVALID-DYNAMIC-PROFILE-ERROR
Unused
Variable $dbe:INVALID-TRANSFORM
Used in: «root»
Variable $dbe:INVALID-RESULTS-REQUESTED
Used by: t:docbook
Used in: «root»
Source code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:db="http://docbook.org/ns/docbook"
                xmlns:dbe="http://docbook.org/ns/docbook/errors"
                xmlns:f="http://docbook.org/ns/docbook/functions"
                xmlns:m="http://docbook.org/ns/docbook/modes"
                xmlns:xs="http://www.w3.org/2001/XMLSchema"
                xmlns="http://www.w3.org/1999/xhtml"
                default-mode="m:docbook"
                exclude-result-prefixes="db dbe f m xs"
                version="3.0">

<xsl:variable name="dbe:INVALID-INJECT" select="xs:QName('dbe:INVALID-INJECT')"/>
<xsl:variable name="dbe:INVALID-CALS" select="xs:QName('dbe:INVALID-CALS')"/>
<xsl:variable name="dbe:INVALID-AREAREFS" select="xs:QName('dbe:INVALID-AREAREFS')"/>
<xsl:variable name="dbe:INVALID-PRODUCTIONRECAP"
              select="xs:QName('dbe:INVALID-PRODUCTIONRECAP')"/>
<xsl:variable name="dbe:INVALID-CONSTRAINT"
              select="xs:QName('dbe:INVALID-CONSTRAINT')"/>
<xsl:variable name="dbe:INVALID-TEMPLATE"
              select="xs:QName('dbe:INVALID-TEMPLATE')"/>
<xsl:variable name="dbe:INTERNAL-RENUMBER-ERROR"
              select="xs:QName('dbe:INTERNAL-RENUMBER-ERROR')"/>
<xsl:variable name="dbe:INTERNAL-HIGHLIGHT-ERROR"
              select="xs:QName('dbe:INTERNAL-HIGHLIGHT-ERROR')"/>
<xsl:variable name="dbe:INVALID-NAME-STYLE"
              select="xs:QName('dbe:INVALID-NAME-STYLE')"/>
<xsl:variable name="dbe:DYNAMIC-PROFILE-SYNTAX-ERROR"
              select="xs:QName('dbe:DYNAMIC-PROFILE-SYNTAX-ERROR')"/>
<xsl:variable name="dbe:DYNAMIC-PROFILE-EVAL-ERROR"
              select="xs:QName('dbe:DYNAMIC-PROFILE-EVAL-ERROR')"/>
<xsl:variable name="dbe:INVALID-DYNAMIC-PROFILE-ERROR"
              select="xs:QName('dbe:INVALID-DYNAMIC-PROFILE-ERROR')"/>
<xsl:variable name="dbe:INVALID-TRANSFORM"
              select="xs:QName('dbe:INVALID-TRANSFORM')"/>
<xsl:variable name="dbe:INVALID-RESULTS-REQUESTED"
              select="xs:QName('dbe:INVALID-RESULTS-REQUESTED')"/>

</xsl:stylesheet>

head.xsl

12 templates, 1 function

Instructions
Template match ≅ db:keywordset
Mode: m:html-head
Matches: db:keywordset
Template match ≅ db:subjectset
Mode: m:html-head
Matches: db:subjectset
Template match ≅ db:meta
Mode: m:html-head
Matches: db:meta
Template match ≅ h:*
Mode: m:html-head
Matches: h:*
Template match ≅ *
Mode: mp:html-head-meta
Matches: *
Template match ≅ *
Mode: m:html-head-script
Matches: *
Template match ≅ *
Function fp:minified-css($css as xs:string) as xs:string
Template match ≅ *
Mode: m:html-head-links
Matches: *
Template match ≅ *
Mode: m:html-head-last
Matches: *
Template match ≅ *
Mode: m:html-body-script
Matches: *
Source code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:db="http://docbook.org/ns/docbook"
                xmlns:f="http://docbook.org/ns/docbook/functions"
                xmlns:fp="http://docbook.org/ns/docbook/functions/private"
                xmlns:h="http://www.w3.org/1999/xhtml"
                xmlns:m="http://docbook.org/ns/docbook/modes"
                xmlns:mp="http://docbook.org/ns/docbook/modes/private"
                xmlns:t="http://docbook.org/ns/docbook/templates"
                xmlns:tp="http://docbook.org/ns/docbook/templates/private"
                xmlns:v="http://docbook.org/ns/docbook/variables"
                xmlns:vp="http://docbook.org/ns/docbook/variables/private"
                xmlns:xs="http://www.w3.org/2001/XMLSchema"
                xmlns="http://www.w3.org/1999/xhtml"
                default-mode="m:docbook"
                exclude-result-prefixes="#all"
                version="3.0">

<xsl:mode name="m:html-head" on-no-match="shallow-copy"/>

<xsl:template match="*" mode="m:html-head" as="element(h:head)">
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title>
      <xsl:variable name="title">
        <xsl:apply-templates select="/*" mode="m:headline-title"/>
      </xsl:variable>
      <xsl:value-of select="$title"/>
    </title>

    <xsl:apply-templates select="db:keywordset|db:subjectset|db:meta"
                         mode="m:html-head"/>

    <xsl:choose>
      <xsl:when test="$verbatim-syntax-highlighter = 'highlight.js'">
        <xsl:sequence select="$v:highlight-js-head-elements/self::h:link"/>
      </xsl:when>
      <xsl:when test="$verbatim-syntax-highlighter = ('prism', 'prism.js')">
        <xsl:sequence select="$v:prism-js-head-elements/self::h:link"/>
      </xsl:when>
      <xsl:otherwise>
        <!-- nop -->
      </xsl:otherwise>
    </xsl:choose>

    <xsl:if test="exists($v:verbatim-syntax-highlight-languages)
                  and normalize-space($verbatim-syntax-highlight-css) != ''">
      <link rel="stylesheet"
            href="{$resource-base-uri}{$verbatim-syntax-highlight-css}"/>
    </xsl:if>

    <xsl:apply-templates select="." mode="mp:html-head-meta"/>
    <xsl:apply-templates select="." mode="mp:html-head-script"/>
    <xsl:apply-templates select="." mode="m:html-head-script"/>
    <xsl:apply-templates select="." mode="mp:html-head-links"/>
    <xsl:apply-templates select="." mode="m:html-head-links"/>
    <xsl:apply-templates select="h:*" mode="m:html-head"/>

    <xsl:for-each select="$vp:user-css-links">
      <link rel="stylesheet" href="{$resource-base-uri}{.}"/>
    </xsl:for-each>

    <xsl:apply-templates select="." mode="m:html-head-last"/>
  </head>
</xsl:template>

<xsl:template match="db:keywordset" mode="m:html-head">
  <xsl:variable name="keywords" as="xs:string*">
    <xsl:for-each select="db:keyword">
      <xsl:sort select="normalize-space(.)"/>
      <xsl:sequence select="normalize-space(.)"/>
    </xsl:for-each>
  </xsl:variable>

  <meta name="keywords" content="{string-join($keywords,',')}"/>
</xsl:template>

<xsl:template match="db:subjectset" mode="m:html-head">
  <xsl:variable name="keywords" as="xs:string*">
    <xsl:for-each select="db:subject/db:subjectterm">
      <xsl:sort select="normalize-space(.)"/>
      <xsl:sequence select="normalize-space(.)"/>
    </xsl:for-each>
  </xsl:variable>

  <meta name="keywords" content="{string-join($keywords,',')}"/>
</xsl:template>

<xsl:template match="db:meta" mode="m:html-head">
  <xsl:if test="@name and @content">
    <meta name="{@name}" content="{@content}"/>
  </xsl:if>
</xsl:template>

<xsl:template match="h:*" mode="m:html-head">
  <xsl:element name="{local-name(.)}" namespace="http://www.w3.org/1999/xhtml">
    <xsl:apply-templates select="@*,node()" mode="m:html-head"/>
  </xsl:element>
</xsl:template>

<!-- ============================================================ -->

<xsl:template match="*" mode="mp:html-head-meta">
  <xsl:variable name="Z" select="xs:dayTimeDuration('PT0H')"/>

  <meta name="viewport" content="width=device-width, initial-scale=1.0"/>

  <xsl:if test="f:is-true($dc-metadata)">
    <link rel="schema.dc" href="https://purl.org/dc/elements/1.1/"/>
    <meta name="dc.modified"
          content="{format-dateTime(
                      adjust-dateTime-to-timezone(current-dateTime(), $Z),
                      '[Y0001]-[M01]-[D01]T[H01]:[m01]:[s01]Z')}"/>
    <xsl:choose>
      <xsl:when test="empty(/*/db:info/db:pubdate)"/>
      <xsl:when test="empty(/*/db:info/db:pubdate/node())">
        <meta name="dc.created"
              content="{format-dateTime(
                         adjust-dateTime-to-timezone(current-dateTime(), $Z),
                         '[Y0001]-[M01]-[D01]T[H01]:[m01]:[s01]Z')}"/>
      </xsl:when>
      <xsl:when test="/*/db:info/db:pubdate/string() castable as xs:dateTime">
        <xsl:variable name="date"
                      select="xs:dateTime(/*/db:info/db:pubdate/string())"/>
        <meta name="dc.created"
              content="{format-dateTime(
                         adjust-dateTime-to-timezone($date, $Z),
                         '[Y0001]-[M01]-[D01]T[H01]:[m01]:[s01]Z')}"/>
      </xsl:when>
      <xsl:when test="/*/db:info/db:pubdate/string() castable as xs:date">
        <xsl:variable name="date"
                      select="xs:date(/*/db:info/db:pubdate/string())"/>
        <meta name="dc.created"
              content="{format-date($date, '[Y0001]-[M01]-[D01]')}"/>
      </xsl:when>
      <xsl:otherwise>
        <meta name="dc.created" content="{string(/*/db:info/db:pubdate)}"/>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:if>

  <xsl:if test="f:is-true($generator-metadata)">
    <meta name="generator"
          content="{'DocBook xslTNG version ' || $v:VERSION
                    || ' / ' || $v:VERSION-ID
                    || ' / ' || system-property('xsl:product-name')
                    || ' ' || system-property('xsl:product-version')}"/>
  </xsl:if>
</xsl:template>

<xsl:template match="*" mode="mp:html-head-script">
  <xsl:if test="f:is-true($persistent-toc)">
    <link rel="stylesheet"
          href="{$resource-base-uri}{fp:minified-css($persistent-toc-css)}"/>
  </xsl:if>

  <xsl:choose>
    <xsl:when test="$verbatim-syntax-highlighter = ('', 'none')"/>
    <xsl:when test="$verbatim-syntax-highlighter = 'pygments'"/>
    <xsl:when test="$verbatim-syntax-highlighter = 'highlight.js'">
      <xsl:sequence select="$v:highlight-js-head-elements/self::*
                            except $v:highlight-js-head-elements/self::h:link"/>
    </xsl:when>
    <xsl:when test="$verbatim-syntax-highlighter = ('prism', 'prism.js')">
      <xsl:sequence select="$v:prism-js-head-elements/self::*
                            except $v:prism-js-head-elements/self::h:link"/>
    </xsl:when>
    <xsl:otherwise>
      <xsl:message select="'Unrecognized syntax highlighter:', $verbatim-syntax-highlighter"/>
    </xsl:otherwise>
  </xsl:choose>

  <xsl:if test="f:is-true($presentation-mode)">
    <script src="{$presentation-js}" defer="defer"/>
  </xsl:if>
</xsl:template>

<xsl:template match="*" mode="m:html-head-script">
</xsl:template>

<xsl:template match="*" mode="mp:html-head-links">
  <xsl:if test="f:is-true($use-docbook-css)">
    <link href="{$resource-base-uri}{fp:minified-css('css/docbook.css')}"
          rel="stylesheet" media="screen"/>
    <!-- This stylesheet was made conditional in 2.1.0 because modern
         browsers generate a lot of warnings for print-specific features. -->
    <xsl:if test="$output-media = 'print'">
      <link href="{$resource-base-uri}{fp:minified-css('css/docbook-paged.css')}"
            rel="stylesheet" media="print"/>
    </xsl:if>
  </xsl:if>

  <xsl:if test="f:is-true($presentation-mode)">
    <link rel="stylesheet"
          href="{$presentation-css}"/>
  </xsl:if>
</xsl:template>

<xsl:function name="fp:minified-css" as="xs:string">
  <xsl:param name="css" as="xs:string"/>
  <xsl:sequence select="if (f:is-true($use-minified-css))
                        then replace($css, '\.css$', '.min.css')
                        else $css"/>
</xsl:function>

<xsl:template match="*" mode="m:html-head-links">
</xsl:template>

<xsl:template match="*" mode="m:html-head-last">
</xsl:template>

<xsl:template match="*" mode="m:html-body-script">
  <xsl:param name="rootbaseuri" as="xs:anyURI" required="yes"/>
  <xsl:param name="chunkbaseuri" as="xs:anyURI" required="yes"/>
</xsl:template>

</xsl:stylesheet>

titles.xsl

37 templates, 2 functions (1 unused), 2 variables

Instructions
Variable $v:user-title-groups as element()*
Function fp:title-properties($this as element()) as element()?
Template match ≅ * as item()*
Mode: mp:compute-headline-label
Matches: *
Template match ≅ *
Mode: m:headline
Matches: *
Template match ≅ *
Mode: m:headline-label
Matches: *
Template match ≅ db:appendix
Mode: m:headline-label
Matches: db:appendix
Template match ≅ db:qandaentry
Mode: m:headline-label
Matches: db:qandaentry
Template match ≅ db:question
Mode: m:headline-label
Matches: db:question
Template match ≅ db:answer
Mode: m:headline-label
Matches: db:answer
Template match ≅ * as item()*
Mode: m:headline-number
Matches: *
Template match ≅ db:orderedlist/db:listitem as item()*
Mode: m:headline-number
Matches: db:orderedlist/db:listitem
Template match ≅ db:step as item()*
Mode: m:headline-number
Matches: db:step
Template match ≅ db:qandadiv as item()*
Mode: m:headline-number
Matches: db:qandadiv
Template match ≅ db:equation|db:example|db:figu… as item()*
Mode: m:headline-number
Matches: db:equation, db:example, db:figure, db:formalgroup, db:procedure, db:qandaset, db:table
Template match ≅ db:sect1|db:sect2|db:sect3|db:… as item()*
Mode: m:headline-number
Matches: db:sect1, db:sect2, db:sect3, db:sect4, db:sect5, db:section
Template match ≅ db:acknowledgements|db:appendi… as item()*
Mode: m:headline-number
Matches: db:acknowledgements, db:appendix, db:article, db:bibliography, db:chapter, db:colophon, db:dedication, db:glossary, db:index, db:partintro, db:preface, db:setindex
Template match ≅ db:part|db:reference as item()*
Mode: m:headline-number
Matches: db:part, db:reference
Template match ≅ db:book as item()*
Mode: m:headline-number
Matches: db:book
Template match ≅ db:set as item()*
Mode: m:headline-number
Matches: db:set
Template match ≅ db:equation|db:example|db:figu…
Mode: mp:format-headline-number
Matches: db:equation, db:example, db:figure, db:table
Template match ≅ *
Mode: mp:format-headline-number
Matches: *
Template tp:format-number match ≅ as item()*
Used by: template
Mode: m:docbook
Template match ≅ * as item()*
Mode: mp:headline-number-prefix
Matches: *
Template match ≅ db:sect1|db:sect2|db:sect3|db:… as item()*
Mode: mp:headline-number-prefix
Matches: db:sect1, db:sect2, db:sect3, db:sect4, db:sect5, db:section
Template match ≅ db:acknowledgements|db:appendi… as item()*
Mode: mp:headline-number-prefix
Matches: db:acknowledgements, db:appendix, db:article, db:bibliography, db:chapter, db:colophon, db:dedication, db:glossary, db:index, db:partintro, db:preface, db:setindex
Template match ≅ db:part|db:reference as item()*
Mode: mp:headline-number-prefix
Matches: db:part, db:reference
Template match ≅ db:book as item()*
Mode: mp:headline-number-prefix
Matches: db:book
Template match ≅ db:set as item()*
Mode: mp:headline-number-prefix
Matches: db:set
Function fp:nearest-relevant-ancestor($elem as element()) as element()
Template match ≅ *
Mode: m:headline-title
Matches: *
Template match ≅ db:refentry
Mode: m:headline-title
Matches: db:refentry
Template match ≅ db:refmeta
Mode: m:headline-title
Matches: db:refmeta
Template match ≅ db:refnamediv
Mode: m:headline-title
Matches: db:refnamediv
Template match ≅ db:refname
Mode: m:headline-title
Matches: db:refname
Template match ≅ db:question
Mode: m:headline-title
Matches: db:question
Template match ≅ db:title|db:titleabbrev
Mode: m:title
Matches: db:title, db:titleabbrev
Template match ≅ h:db-annotation|h:db-footnote
Mode: mp:strip-links
Matches: h:db-annotation, h:db-footnote
Template match ≅ h:a
Mode: mp:strip-links
Matches: h:a
Template match ≅ element()
Mode: mp:strip-links
Matches: element()
Template match ≅ attribute()|comment()|processi…
Mode: mp:strip-links
Matches: attribute(), comment(), processing-instruction(), text()
Source code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:db="http://docbook.org/ns/docbook"
                xmlns:dbe="http://docbook.org/ns/docbook/errors"
                xmlns:f="http://docbook.org/ns/docbook/functions"
                xmlns:fp="http://docbook.org/ns/docbook/functions/private"
                xmlns:l="http://docbook.org/ns/docbook/l10n"
                xmlns:lt="http://docbook.org/ns/docbook/l10n/templates"
                xmlns:m="http://docbook.org/ns/docbook/modes"
                xmlns:map="http://www.w3.org/2005/xpath-functions/map"
                xmlns:mp="http://docbook.org/ns/docbook/modes/private"
                xmlns:tp="http://docbook.org/ns/docbook/templates/private"
                xmlns:v="http://docbook.org/ns/docbook/variables"
                xmlns:vp="http://docbook.org/ns/docbook/variables/private"
                xmlns:xs="http://www.w3.org/2001/XMLSchema"
                xmlns="http://www.w3.org/1999/xhtml"
                default-mode="m:docbook"
                exclude-result-prefixes="#all"
                version="3.0">

<xsl:variable name="v:user-title-groups" as="element()*"/>

<xsl:variable name="v:title-groups" as="element()+"
              xmlns:db="http://docbook.org/ns/docbook">
  <xsl:sequence select="$v:user-title-groups"/>

  <title xpath="self::db:section|self::db:sect1
                |self::db:sect2|self::db:sect3|self::db:sect4|self::db:sect5
                |self::db:refsection|self::db:refsect1|self::db:refsect2|self::db:refsect3"
         group="{if (f:is-true($section-numbers))
                 then 'title-numbered'
                 else 'title-unnumbered'}"/>

  <title xpath="self::db:article|self::db:preface|self::db:chapter|self::db:appendix"
         group="{if (f:is-true($component-numbers))
                 then 'title-numbered'
                 else 'title-unnumbered'}"/>

  <title xpath="self::db:set" group="title-unnumbered"/>

  <title xpath="self::db:book|self::db:part|self::db:reference"
         group="{if (f:is-true($division-numbers))
                 then 'title-numbered'
                 else 'title-unnumbered'}"/>

  <title xpath="self::db:figure[parent::db:formalgroup]
                |self::db:table[parent::db:formalgroup]
                |self::db:equation[parent::db:formalgroup]
                |self::db:example[parent::db:formalgroup]"
         group="subfigure-title"/>

  <title xpath="self::db:figure|self::db:table|self::db:equation|self::db:example|self::db:procedure"
         group="title-numbered"/>

  <title xpath="self::db:formalgroup"
         group="title-numbered"/>

  <title xpath="self::db:step|self::db:listitem[parent::db:orderedlist]"
         group="title-unnumbered"/>

  <title xpath="self::db:glosssee|self::db:glossseealso"
         group="title-unnumbered"/>

  <title xpath="self::db:see|self::db:seealso"
         group="title-unnumbered"/>

  <title xpath="self::db:question|self::db:answer"
         group="title-numbered"/>

  <title xpath="self::*"
         group="title-unnumbered"/>
</xsl:variable>

<!-- ============================================================ -->

<xsl:function name="fp:title-properties" as="element()?" cache="yes">
  <xsl:param name="this" as="element()"/>

  <xsl:iterate select="$v:title-groups">
    <xsl:variable name="test" as="element()*">
      <xsl:evaluate context-item="$this" xpath="@xpath"/>
    </xsl:variable>

    <xsl:choose>
      <xsl:when test="$test">
        <xsl:sequence select="."/>
        <xsl:break/>
      </xsl:when>
      <xsl:otherwise>
        <xsl:next-iteration/>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:iterate>
</xsl:function>

<xsl:template match="*" mode="mp:compute-headline-label" as="item()*">
  <xsl:param name="purpose" as="xs:string" required="yes"/>

  <xsl:variable name="prop" select="fp:title-properties(.)"/>

  <xsl:variable name="template"
                select="if ($purpose = 'lot')
                        then fp:localization-template(., 'list-of-titles')
                        else fp:localization-template(., $prop/@group)"/>

  <xsl:if test="$template/lt:label">
    <xsl:apply-templates select="." mode="m:headline-label">
      <xsl:with-param name="purpose" select="$purpose"/>
    </xsl:apply-templates>
  </xsl:if>
</xsl:template>

<!-- ============================================================ -->

<xsl:template match="*" mode="m:headline">
  <xsl:param name="purpose" as="xs:string" required="yes"/>

  <xsl:variable name="prop" select="fp:title-properties(.)"/>

  <!-- There's a little bit of a hack here. Turning off numbers
       (e.g., $division-numbers, $component-numbers, or $section-numbers)
       should (usually) effect the list-of-titles as well. But it
       doesn't unless you also override the list-of-titles templates in
       the localization, and that's more work. Surely the flags should
       apply?

       So to support that, if the property group contains 'unnumbered',
       we look for list-of-titles-unnumbered, otherwise we look for
       'list-of-titles'. It's a bit of a hack, but...those boolean
       params are arguably the hack, so...
   -->
  <!--
  <xsl:message select="local-name(.), $purpose, $prop/@group/string()"/>
  <xsl:message select="$prop"/>
  -->

  <xsl:variable name="template" as="element(l:template)">
    <xsl:choose>
      <xsl:when test="$purpose = 'lot' and contains($prop/@group, 'unnumbered')">
        <xsl:sequence select="fp:localization-template(., 'list-of-titles-unnumbered')"/>
      </xsl:when>
      <xsl:when test="$purpose = 'lot'">
        <xsl:sequence select="fp:localization-template(., 'list-of-titles')"/>
      </xsl:when>
      <xsl:otherwise>
        <xsl:sequence select="fp:localization-template(., $prop/@group)"/>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:variable>

  <!--
  <xsl:message select="local-name(.), $purpose, $template"/>
  -->

  <xsl:variable name="label" as="item()*">
    <xsl:apply-templates select="." mode="mp:compute-headline-label">
      <xsl:with-param name="purpose" select="$purpose"/>
    </xsl:apply-templates>
  </xsl:variable>

  <xsl:if test="$vp:olinkdb">
    <xsl:attribute name="db-label" select="$label"/>
  </xsl:if>

  <xsl:variable name="title" as="node()*">
    <xsl:if test="$template/lt:content">
      <xsl:apply-templates select="." mode="m:headline-title">
        <xsl:with-param name="purpose" select="$purpose"/>
      </xsl:apply-templates>
    </xsl:if>
  </xsl:variable>

  <xsl:apply-templates select="$template" mode="mp:localization">
    <xsl:with-param name="context" select="."/>
    <xsl:with-param name="label" select="$label"/>
    <xsl:with-param name="content" select="$title"/>
  </xsl:apply-templates>
</xsl:template>

<!-- ============================================================ -->

<xsl:template match="*" mode="m:headline-label">
  <xsl:param name="purpose" as="xs:string" required="yes"/>
  <xsl:apply-templates select="." mode="m:headline-number">
    <xsl:with-param name="purpose" select="$purpose"/>
  </xsl:apply-templates>
</xsl:template>

<xsl:template match="db:appendix" mode="m:headline-label">
  <xsl:param name="purpose" as="xs:string" required="yes"/>
  <xsl:choose>
    <xsl:when test="not(f:is-true($number-single-appendix))
                    and empty(preceding-sibling::db:appendix)
                    and empty(following-sibling::db:appendix)">
      <xsl:sequence select="()"/>
    </xsl:when>
    <xsl:otherwise>
      <xsl:next-match>
        <xsl:with-param name="purpose" select="$purpose"/>
      </xsl:next-match>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

<xsl:template match="db:qandaentry" mode="m:headline-label">
  <xsl:param name="purpose" as="xs:string" required="yes"/>
  <xsl:apply-templates select="db:question" mode="m:headline-label">
    <xsl:with-param name="purpose" select="$purpose"/>
  </xsl:apply-templates>
</xsl:template>

<xsl:template match="db:question" mode="m:headline-label">
  <xsl:param name="purpose" as="xs:string" required="yes"/>

  <xsl:variable name="label"
                select="ancestor::db:qandaset[@defaultlabel][1]/@defaultlabel/string()"/>
  <xsl:variable name="label"
                select="if ($label)
                        then $label
                        else $qandaset-default-label"/>

  <xsl:choose>
    <xsl:when test="db:label">
      <xsl:apply-templates select="db:label"/>
    </xsl:when>
    <xsl:when test="$label = 'none'"/>
    <xsl:when test="$label = 'number'">
      <xsl:number from="db:qandaset" level="multiple" select=".."
                  count="db:qandaentry|db:qandadiv"/>
    </xsl:when>
    <xsl:otherwise>
      <xsl:if test="$label != 'qanda'">
        <xsl:message
            select="'Unexpected qandaset label: ' || $label || ', using qanda'"/>
      </xsl:if>

      <xsl:sequence select="f:l10n-token(., 'question')"/>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

<xsl:template match="db:answer" mode="m:headline-label">
  <xsl:param name="purpose" as="xs:string" required="yes"/>

  <xsl:variable name="label"
                select="ancestor::db:qandaset[@defaultlabel][1]/@defaultlabel/string()"/>
  <xsl:variable name="label"
                select="if ($label)
                        then $label
                        else $qandaset-default-label"/>

  <xsl:choose>
    <xsl:when test="db:label">
      <xsl:apply-templates select="db:label"/>
    </xsl:when>
    <xsl:when test="$label = 'none' or $label='number'"/>
    <xsl:when test="$label = 'qanda'">
      <xsl:text>A:</xsl:text>
    </xsl:when>
    <xsl:otherwise>
      <xsl:message
          select="'Unexpected qandaset label: ' || $label || ', using qanda'"/>
      <xsl:text>A:</xsl:text>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

<!-- ============================================================ -->

<xsl:template match="*" as="item()*" mode="m:headline-number">
  <xsl:param name="purpose" as="xs:string" required="yes"/>
  <xsl:message use-when="$v:debug = 'numeration'"
               select="'No headline number for', local-name(.)"/>
  <!-- just a default... -->
  <xsl:number level="single"/>
</xsl:template>

<xsl:template match="db:orderedlist/db:listitem" as="item()*"
              mode="m:headline-number">
  <xsl:param name="purpose" as="xs:string" required="yes"/>

  <xsl:variable name="prefix" as="item()*">
    <xsl:apply-templates select="parent::*/ancestor::db:listitem[parent::db:orderedlist][1]"
                         mode="m:headline-number">
      <xsl:with-param name="purpose" select="$purpose"/>
    </xsl:apply-templates>
  </xsl:variable>

  <xsl:variable name="number" as="xs:integer"
                select="f:orderedlist-item-number(.)[last()]"/>

  <xsl:variable name="format"
                select="f:orderedlist-item-numeration(.)"/>

  <xsl:variable name="formatted-number" as="xs:string?">
    <xsl:if test="exists($format)">
      <xsl:number value="$number" format="{$format}"/>
    </xsl:if>
  </xsl:variable>

  <xsl:if test="exists($formatted-number)">
    <xsl:if test="exists($prefix)">
      <xsl:sequence select="$prefix"/>
      <span class="sep">
        <xsl:apply-templates select="." mode="m:gentext">
          <xsl:with-param name="group" select="'number-separator'"/>
        </xsl:apply-templates>
      </span>
    </xsl:if>
    <xsl:sequence select="$formatted-number"/>
  </xsl:if>
</xsl:template>

<xsl:template match="db:step" as="item()*"
              mode="m:headline-number">
  <xsl:param name="purpose" as="xs:string" required="yes"/>

  <xsl:variable name="prefix" as="item()*">
    <xsl:apply-templates select="ancestor::db:step[1]"
                         mode="m:headline-number">
      <xsl:with-param name="purpose" select="$purpose"/>
    </xsl:apply-templates>
  </xsl:variable>

  <xsl:variable name="formatted-number" as="item()*">
    <xsl:number value="fp:number(.)" format="{f:step-numeration(.)}"/>
  </xsl:variable>

  <xsl:if test="exists($formatted-number)">
    <xsl:if test="exists($prefix)">
      <xsl:sequence select="$prefix"/>
      <span class="sep">
        <xsl:apply-templates select="." mode="m:gentext">
          <xsl:with-param name="group" select="'number-separator'"/>
        </xsl:apply-templates>
      </span>
    </xsl:if>
    <xsl:sequence select="$formatted-number"/>
  </xsl:if>
</xsl:template>

<xsl:template match="db:qandadiv" as="item()*"
              mode="m:headline-number">
  <xsl:param name="purpose" as="xs:string" required="yes"/>

  <xsl:variable name="prefix" as="item()*">
    <xsl:apply-templates select="parent::*"
                         mode="m:headline-number">
      <xsl:with-param name="purpose" select="$purpose"/>
    </xsl:apply-templates>
  </xsl:variable>

  <xsl:variable name="number" select="fp:number(.)"/>

  <xsl:variable name="format">
    <xsl:apply-templates select="." mode="m:gentext">
      <xsl:with-param name="group" select="'number-format'"/>
    </xsl:apply-templates>
  </xsl:variable>

  <xsl:if test="exists($number) and exists($format)">
    <xsl:if test="exists($prefix)">
      <xsl:sequence select="$prefix"/>
      <span class="sep">
        <xsl:apply-templates select="." mode="m:gentext">
          <xsl:with-param name="group" select="'number-separator'"/>
        </xsl:apply-templates>
      </span>
    </xsl:if>
    <xsl:number value="$number" format="{$format}"/>
  </xsl:if>
</xsl:template>

<xsl:template match="db:figure[not(parent::db:formal-group)]
                     |db:example[not(parent::db:formal-group)]
                     |db:table[not(parent::db:formal-group)]
                     |db:equation[not(parent::db:formal-group)]
                     |db:procedure
                     |db:qandaset
                     |db:formalgroup"
              as="item()*"
              mode="m:headline-number">
  <xsl:param name="purpose" as="xs:string" required="yes"/>
  <xsl:param name="inherit-from" select="tokenize($formal-objects-inherit-from, '\s+')"/>

  <xsl:apply-templates select="."
                       mode="mp:format-headline-number">
    <xsl:with-param name="purpose" select="$purpose"/>
    <xsl:with-param name="inherit-from" select="$inherit-from"/>
  </xsl:apply-templates>
</xsl:template>

<xsl:template match="db:section|db:sect1|db:sect2|db:sect3|db:sect4|db:sect5"
              as="item()*"
              mode="m:headline-number">
  <xsl:param name="purpose" as="xs:string" required="yes"/>
  <xsl:param name="inherit-from" select="tokenize($sections-inherit-from, '\s+')"/>

  <xsl:apply-templates select="."
                       mode="mp:format-headline-number">
    <xsl:with-param name="purpose" select="$purpose"/>
    <xsl:with-param name="inherit-from" select="$inherit-from"/>
  </xsl:apply-templates>
</xsl:template>

<xsl:template match="db:preface|db:chapter|db:appendix|db:partintro
                     |db:dedication|db:colophon|db:acknowledgements
                     |db:article
                     |db:glossary|db:bibliography
                     |db:index|db:setindex"
              mode="m:headline-number"
              as="item()*">
  <xsl:param name="purpose" as="xs:string" required="yes"/>
  <xsl:param name="inherit-from" select="tokenize($components-inherit-from, '\s+')"/>

  <!--
  <xsl:message select="local-name(.), $inherit-from,
                       '============================================================'"/>
  -->

  <xsl:apply-templates select="."
                       mode="mp:format-headline-number">
    <xsl:with-param name="purpose" select="$purpose"/>
    <xsl:with-param name="inherit-from" select="$inherit-from"/>
  </xsl:apply-templates>
</xsl:template>

<xsl:template match="db:part|db:reference" as="item()*"
              mode="m:headline-number">
  <xsl:param name="purpose" as="xs:string" required="yes"/>
  <xsl:param name="inherit-from" select="tokenize($divisions-inherit-from, '\s+')"/>

  <xsl:apply-templates select="."
                       mode="mp:format-headline-number">
    <xsl:with-param name="purpose" select="$purpose"/>
    <xsl:with-param name="inherit-from" select="$inherit-from"/>
  </xsl:apply-templates>
</xsl:template>

<xsl:template match="db:book" as="item()*"
              mode="m:headline-number">
  <xsl:param name="purpose" as="xs:string" required="yes"/>
  <xsl:param name="inherit-from" select="tokenize($books-inherit-from, '\s+')"/>
  <xsl:apply-templates select="."
                       mode="mp:format-headline-number">
    <xsl:with-param name="purpose" select="$purpose"/>
    <xsl:with-param name="inherit-from" select="$inherit-from"/>
  </xsl:apply-templates>
</xsl:template>

<xsl:template match="db:set" as="item()*"
              mode="m:headline-number">
  <xsl:param name="purpose" as="xs:string" required="yes"/>
  <xsl:param name="inherit-from" select="tokenize($sets-inherit-from, '\s+')"/>
  <xsl:apply-templates select="."
                       mode="mp:format-headline-number">
    <xsl:with-param name="purpose" select="$purpose"/>
    <xsl:with-param name="inherit-from" select="$inherit-from"/>
  </xsl:apply-templates>
</xsl:template>

<xsl:template match="db:figure[parent::db:formalgroup]
                     |db:table[parent::db:formalgroup]
                     |db:example[parent::db:formalgroup]
                     |db:equation[parent::db:formalgroup]"
              mode="mp:format-headline-number">
  <xsl:param name="purpose" as="xs:string" required="yes"/>
  <xsl:param name="inherit-from" as="xs:string*"/>

  <xsl:variable name="prefix" as="item()*">
    <xsl:apply-templates select=".." mode="mp:format-headline-number">
      <xsl:with-param name="purpose" select="$purpose"/>
      <xsl:with-param name="inherit-from" select="$inherit-from"/>
    </xsl:apply-templates>
  </xsl:variable>

  <xsl:variable name="number" as="item()*"
                select="fp:number(.)"/>

  <xsl:variable name="format">
    <xsl:apply-templates select="." mode="m:gentext">
      <xsl:with-param name="group" select="'number-format'"/>
    </xsl:apply-templates>
  </xsl:variable>

  <xsl:if test="exists($number) and exists($format)">
    <xsl:if test="exists($prefix)">
      <xsl:sequence select="$prefix"/>
      <span class="sep">
        <xsl:apply-templates select="." mode="m:gentext">
          <xsl:with-param name="group" select="'number-separator'"/>
        </xsl:apply-templates>
      </span>
    </xsl:if>
    <xsl:number value="$number" format="{$format}"/>
  </xsl:if>
</xsl:template>

<xsl:template match="*" mode="mp:format-headline-number">
  <xsl:param name="purpose" as="xs:string" required="yes"/>
  <xsl:param name="inherit-from" as="xs:string*"/>

  <xsl:variable name="from" as="element()?">
    <xsl:choose>
      <xsl:when test="$inherit-from = 'section'
                      and (ancestor::db:section|ancestor::db:sect1|ancestor::db:sect2
                           |ancestor::db:sect3|ancestor::db:sect4|ancestor::db:sect5)">
        <xsl:sequence
            select="(ancestor::db:section|ancestor::db:sect1|ancestor::db:sect2
                     |ancestor::db:sect3|ancestor::db:sect4|ancestor::db:sect5)[last()]"/>
      </xsl:when>
      <xsl:when test="$inherit-from = 'component'
                      and (ancestor::db:preface|ancestor::db:chapter
                           |ancestor::db:appendix|ancestor::db:partintro
                           |ancestor::db:dedication|ancestor::db:colophon
                           |ancestor::db:acknowledgements
                           |ancestor::db:article|ancestor::db:refentry
                           |ancestor::db:glossary|ancestor::db:bibliography
                           |ancestor::db:index|ancestor::db:setindex)">
        <xsl:sequence select="(ancestor::db:preface|ancestor::db:chapter
                               |ancestor::db:appendix|ancestor::db:partintro
                               |ancestor::db:dedication|ancestor::db:colophon
                               |ancestor::db:acknowledgements
                               |ancestor::db:article|ancestor::db:refentry
                               |ancestor::db:glossary|ancestor::db:bibliography
                               |ancestor::db:index|ancestor::db:setindex)[last()]"/>
      </xsl:when>
      <xsl:when test="$inherit-from = 'division'
                      and (ancestor::db:part|ancestor::db:reference)">
        <xsl:sequence select="(ancestor::db:part|ancestor::db:reference)[last()]"/>
      </xsl:when>
      <xsl:when test="$inherit-from = 'book' and ancestor::db:book">
        <xsl:sequence select="ancestor::db:book[1]"/>
      </xsl:when>
      <xsl:when test="$inherit-from = 'set' and ancestor::db:set">
        <xsl:sequence select="ancestor::db:set[1]"/>
      </xsl:when>
      <xsl:otherwise>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:variable>

  <xsl:variable name="label" as="item()*">
    <xsl:apply-templates select="$from" mode="mp:compute-headline-label">
      <xsl:with-param name="purpose" select="$purpose"/>
    </xsl:apply-templates>
  </xsl:variable>

  <xsl:variable name="prefix" as="item()*">
    <xsl:apply-templates select="$from" mode="mp:format-headline-number">
      <xsl:with-param name="purpose" select="$purpose"/>
      <xsl:with-param name="inherit-from" select="$inherit-from"/>
    </xsl:apply-templates>
  </xsl:variable>

  <xsl:variable name="number" as="item()*"
                select="fp:number(.)"/>

  <!--
  <xsl:message select="'FHN:', local-name(.), 'F:&quot;'||local-name($from)||'&quot;', 
                       'L:&quot;'||string-join($label, ' ')|| '&quot;',
                       'P:', $prefix, ' N:', $number, ':', $inherit-from"/>
  -->

  <xsl:variable name="format">
    <xsl:apply-templates select="." mode="m:gentext">
      <xsl:with-param name="group" select="'number-format'"/>
    </xsl:apply-templates>
  </xsl:variable>

  <xsl:if test="exists($number) and exists($format)">
    <xsl:if test="exists($label) and exists($prefix)">
      <xsl:sequence select="$prefix"/>
      <span class="sep">
        <xsl:apply-templates select="." mode="m:gentext">
          <xsl:with-param name="group" select="'number-separator'"/>
        </xsl:apply-templates>
      </span>
    </xsl:if>
    <xsl:number value="$number" format="{$format}"/>
  </xsl:if>
</xsl:template>

<xsl:template name="tp:format-number" as="item()*">
  <xsl:param name="prefix" as="item()*"/>

  <xsl:variable name="number" select="fp:number(.)"/>

  <xsl:variable name="format">
    <xsl:apply-templates select="." mode="m:gentext">
      <xsl:with-param name="group" select="'number-format'"/>
    </xsl:apply-templates>
  </xsl:variable>

  <xsl:if test="exists($prefix) and exists($number)">
    <xsl:sequence select="$prefix"/>
    <span class="sep">
      <xsl:apply-templates select="." mode="m:gentext">
        <xsl:with-param name="group" select="'number-separator'"/>
      </xsl:apply-templates>
    </span>
  </xsl:if>

  <xsl:if test="exists($number) and exists($format)">
    <xsl:number value="$number" format="{$format}"/>
  </xsl:if>
</xsl:template>

<!-- ============================================================ -->

<xsl:template match="*" as="item()*"
              mode="mp:headline-number-prefix">
  <xsl:param name="inherit-from" select="()"/>
  <xsl:message>No headline number prefix for <xsl:value-of select="local-name(.)"/></xsl:message>
  <xsl:sequence select="()"/>
</xsl:template>

<xsl:template match="db:section|db:sect1|db:sect2|db:sect3|db:sect4|db:sect5"
              as="item()*" mode="mp:headline-number-prefix">
  <xsl:param name="inherit-from" select="$sections-inherit-from"/>
  <xsl:call-template name="tp:format-number">
    <xsl:with-param name="prefix" as="item()*">
      <xsl:if test="$inherit-from = ('section', 'component', 'division', 'book', 'set')">
        <xsl:apply-templates select="parent::*" mode="mp:headline-number-prefix">
          <xsl:with-param name="inherit-from" select="$inherit-from"/>
        </xsl:apply-templates>
      </xsl:if>
    </xsl:with-param>
  </xsl:call-template>
</xsl:template>

<xsl:template match="db:preface|db:chapter|db:appendix|db:partintro
                     |db:dedication|db:colophon|db:acknowledgements
                     |db:article
                     |db:glossary|db:bibliography
                     |db:index|db:setindex"
              mode="mp:headline-number-prefix"
              as="item()*">
  <xsl:param name="inherit-from" select="$components-inherit-from"/>
  <xsl:if test="$inherit-from = ('component', 'division', 'book', 'set')">
    <xsl:apply-templates select="parent::*" mode="mp:headline-number-prefix">
      <xsl:with-param name="inherit-from" select="$inherit-from"/>
    </xsl:apply-templates>
    <xsl:value-of select="fp:number(.)"/>
  </xsl:if>
</xsl:template>

<xsl:template match="db:part|db:reference"
              mode="mp:headline-number-prefix"
              as="item()*">
  <xsl:param name="inherit-from" select="$divisions-inherit-from"/>
  <xsl:if test="$inherit-from = ('division', 'book', 'set')">
    <xsl:apply-templates select="parent::*" mode="mp:headline-number-prefix">
      <xsl:with-param name="inherit-from" select="$inherit-from"/>
    </xsl:apply-templates>
    <xsl:value-of select="fp:number(.)"/>
  </xsl:if>
</xsl:template>

<xsl:template match="db:book"
              mode="mp:headline-number-prefix"
              as="item()*">
  <xsl:param name="inherit-from" select="$divisions-inherit-from"/>
  <xsl:if test="$inherit-from = ('book', 'set')">
    <xsl:apply-templates select="parent::*" mode="mp:headline-number-prefix">
      <xsl:with-param name="inherit-from" select="$inherit-from"/>
    </xsl:apply-templates>
    <xsl:value-of select="fp:number(.)"/>
  </xsl:if>
</xsl:template>

<xsl:template match="db:set"
              mode="mp:headline-number-prefix"
              as="item()*">
  <xsl:param name="inherit-from" select="$divisions-inherit-from"/>
  <xsl:if test="$inherit-from = ('set')">
    <xsl:apply-templates select="parent::*" mode="mp:headline-number-prefix">
      <xsl:with-param name="inherit-from" select="$inherit-from"/>
    </xsl:apply-templates>
    <xsl:value-of select="fp:number(.)"/>
  </xsl:if>
</xsl:template>

<!-- ============================================================ -->

<!-- Is there a clever XPath I'm overlooking? -->
<xsl:function name="fp:nearest-relevant-ancestor" as="element()">
  <xsl:param name="elem" as="element()"/>
  <xsl:choose>
    <xsl:when test="$elem/self::db:chapter|$elem/self::db:appendix
                    |$elem/self::db:sect1|$elem/self::db:sect2|$elem/self::db:sect3
                    |$elem/self::db:sect4|$elem/self::db:sect5|$elem/self::db:section">
      <xsl:sequence select="$elem"/>
    </xsl:when>
    <xsl:when test="empty($elem/parent::*)">
      <xsl:sequence select="$elem"/>
    </xsl:when>
    <xsl:otherwise>
      <xsl:sequence select="fp:nearest-relevant-ancestor($elem/parent::*)"/>
    </xsl:otherwise>
  </xsl:choose>
</xsl:function>

<!-- ============================================================ -->

<xsl:template match="*" mode="m:headline-title">
  <xsl:param name="purpose" as="xs:string" select="'title'"/>

  <xsl:choose>
    <xsl:when test="$purpose = 'title' or not(db:info/db:titleabbrev)">
      <xsl:apply-templates select="db:info/db:title" mode="m:title">
        <xsl:with-param name="purpose" select="$purpose"/>
      </xsl:apply-templates>
    </xsl:when>
    <xsl:otherwise>
      <xsl:apply-templates select="db:info/db:titleabbrev" mode="m:title">
        <xsl:with-param name="purpose" select="$purpose"/>
      </xsl:apply-templates>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

<xsl:template match="db:refentry" mode="m:headline-title">
  <xsl:param name="purpose" as="xs:string" select="'title'"/>
  <xsl:choose>
    <xsl:when test="db:refmeta">
      <xsl:apply-templates select="db:refmeta" mode="m:headline-title">
        <xsl:with-param name="purpose" select="$purpose"/>
      </xsl:apply-templates>
    </xsl:when>
    <xsl:otherwise>
      <xsl:apply-templates select="db:refnamediv/db:refname[1]" mode="m:headline-title">
        <xsl:with-param name="purpose" select="$purpose"/>
      </xsl:apply-templates>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

<xsl:template match="db:refmeta" mode="m:headline-title">
  <xsl:param name="purpose" as="xs:string" select="'title'"/>
  <xsl:apply-templates select="db:refentrytitle/node()"/>
  <xsl:apply-templates select="db:manvolnum"/>
</xsl:template>

<xsl:template match="db:refnamediv" mode="m:headline-title">
  <xsl:param name="purpose" as="xs:string" select="'title'"/>
  <xsl:apply-templates select="db:refname[1]" mode="m:headline-title">
    <xsl:with-param name="purpose" select="$purpose"/>
  </xsl:apply-templates>
</xsl:template>

<xsl:template match="db:refname" mode="m:headline-title">
  <xsl:param name="purpose" as="xs:string" select="'title'"/>
  <xsl:apply-templates mode="m:title">
    <xsl:with-param name="purpose" select="$purpose"/>
  </xsl:apply-templates>
</xsl:template>

<xsl:template match="db:question" mode="m:headline-title">
  <xsl:param name="purpose" as="xs:string" select="'title'"/>
  <xsl:apply-templates mode="m:title"
      select="(* except (db:label|db:info|db:tip|db:note|db:danger|db:important
                         |db:caution|db:sidebar|db:figure|db:example
                         |db:procedure|db:table|db:equation)
              )[1]">
    <xsl:with-param name="purpose" select="$purpose"/>
  </xsl:apply-templates>
</xsl:template>

<!-- ============================================================ -->

<xsl:template match="db:title|db:titleabbrev" mode="m:title">
  <xsl:param name="purpose" as="xs:string" required="yes"/>

  <xsl:choose>
    <xsl:when test="$purpose = 'title'">
      <xsl:apply-templates/>
    </xsl:when>
    <xsl:otherwise>
      <xsl:variable name="title" as="item()*">
        <xsl:apply-templates/>
      </xsl:variable>
      <xsl:apply-templates select="$title" mode="mp:strip-links"/>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

<!-- ============================================================ -->

<xsl:template xmlns:h="http://www.w3.org/1999/xhtml"
              match="h:db-footnote|h:db-annotation" mode="mp:strip-links"/>

<xsl:template xmlns:h="http://www.w3.org/1999/xhtml"
              match="h:a" mode="mp:strip-links">
  <xsl:apply-templates/>
</xsl:template>

<xsl:template match="element()" mode="mp:strip-links">
  <xsl:copy>
    <xsl:apply-templates select="@*,node()" mode="mp:strip-links"/>
  </xsl:copy>
</xsl:template>

<xsl:template match="attribute()|text()|comment()|processing-instruction()"
              mode="mp:strip-links">
  <xsl:copy/>
</xsl:template>

</xsl:stylesheet>

numbers.xsl

21 templates, 1 function (1 used only in one other module)

Instructions
Function fp:number($node as element()) as xs:integer?
Template match ≅ *
Mode: mp:label-number
Matches: *
Template match ≅ db:set
Mode: mp:label-number
Matches: db:set
Template match ≅ db:book
Mode: mp:label-number
Matches: db:book
Template match ≅ db:part|db:reference
Mode: mp:label-number
Matches: db:part, db:reference
Template match ≅ db:acknowledgements|db:appendi…
Mode: mp:label-number
Matches: db:acknowledgements, db:appendix, db:article, db:bibliography, db:chapter, db:colophon, db:dedication, db:glossary, db:index, db:partintro, db:preface, db:setindex
Template match ≅ db:refentry|db:refsect1|db:ref…
Mode: mp:label-number
Matches: db:refentry, db:refsect1, db:refsect2, db:refsect3, db:refsection
Template match ≅ db:sect1|db:sect2|db:sect3|db:…
Mode: mp:label-number
Matches: db:sect1, db:sect2, db:sect3, db:sect4, db:sect5, db:section, db:simplesect
Template match ≅ db:figure|db:formalgroup
Mode: mp:label-number
Matches: db:figure, db:formalgroup
Template match ≅ db:formalgroup|db:table
Mode: mp:label-number
Matches: db:formalgroup, db:table
Template match ≅ db:example|db:formalgroup
Mode: mp:label-number
Matches: db:example, db:formalgroup
Template match ≅ db:equation|db:formalgroup
Mode: mp:label-number
Matches: db:equation, db:formalgroup
Template match ≅ db:equation|db:example|db:figu…
Mode: mp:label-number
Matches: db:equation, db:example, db:figure, db:table
Template match ≅ db:procedure
Mode: mp:label-number
Matches: db:procedure
Template match ≅ db:figure
Mode: mp:label-number
Priority: 10
Matches: db:figure
Template match ≅ db:table
Mode: mp:label-number
Priority: 10
Matches: db:table
Template match ≅ db:example
Mode: mp:label-number
Priority: 10
Matches: db:example
Template match ≅ db:equation
Mode: mp:label-number
Priority: 10
Matches: db:equation
Template match ≅ db:procedure
Mode: mp:label-number
Priority: 10
Matches: db:procedure
Template match ≅ db:step as xs:integer?
Mode: mp:label-number
Matches: db:step
Template match ≅ db:qandaset as xs:integer?
Mode: mp:label-number
Matches: db:qandaset
Template match ≅ db:qandadiv as xs:integer?
Mode: mp:label-number
Matches: db:qandadiv
Source code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:db="http://docbook.org/ns/docbook"
                xmlns:dbe="http://docbook.org/ns/docbook/errors"
                xmlns:f="http://docbook.org/ns/docbook/functions"
                xmlns:fp="http://docbook.org/ns/docbook/functions/private"
                xmlns:l="http://docbook.org/ns/docbook/l10n"
                xmlns:lt="http://docbook.org/ns/docbook/l10n/templates"
                xmlns:m="http://docbook.org/ns/docbook/modes"
                xmlns:map="http://www.w3.org/2005/xpath-functions/map"
                xmlns:mp="http://docbook.org/ns/docbook/modes/private"
                xmlns:v="http://docbook.org/ns/docbook/variables"
                xmlns:vp="http://docbook.org/ns/docbook/variables/private"
                xmlns:xs="http://www.w3.org/2001/XMLSchema"
                xmlns="http://www.w3.org/1999/xhtml"
                default-mode="m:docbook"
                exclude-result-prefixes="#all"
                version="3.0">

<!-- ============================================================ -->

<xsl:function name="fp:number" as="xs:integer?" cache="yes">
  <xsl:param name="node" as="element()"/>
  <xsl:apply-templates select="$node" mode="mp:label-number"/>
</xsl:function>

<xsl:template match="*" mode="mp:label-number">
  <xsl:message select="'Error: no numeration scheme for ' || local-name(.)"/>
  <xsl:sequence select="0"/>
</xsl:template>

<xsl:template match="db:set" mode="mp:label-number">
  <xsl:choose>
    <xsl:when test="$sets-number-from = 'set'
                    and ancestor::db:set">
      <xsl:number from="db:set" level="single"/>
    </xsl:when>
    <xsl:when test="$sets-number-from = ('set', 'root')">
      <xsl:number level="any"/>
    </xsl:when>
    <xsl:otherwise>
      <xsl:message select="'Error: sets-number-from='||$sets-number-from"/>
      <xsl:sequence select="0"/>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

<xsl:template match="db:book" mode="mp:label-number">
  <xsl:choose>
    <xsl:when test="$books-number-from = 'set'
                    and ancestor::db:set">
      <xsl:number from="db:set" level="any"/>
    </xsl:when>
    <xsl:when test="$books-number-from = ('set', 'root')">
      <xsl:number level="any"/>
    </xsl:when>
    <xsl:otherwise>
      <xsl:message select="'Error: books-number-from='||$books-number-from"/>
      <xsl:sequence select="0"/>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

<xsl:template match="db:part|db:reference" mode="mp:label-number">
  <xsl:choose>
    <xsl:when test="$divisions-number-from = 'set'
                    and ancestor::db:set">
      <xsl:number from="db:set" level="any"/>
    </xsl:when>
    <xsl:when test="$divisions-number-from = 'set'">
      <xsl:number level="any"/>
    </xsl:when>
    <xsl:when test="$divisions-number-from = 'book'
                    and ancestor::db:book">
      <xsl:number from="db:book" level="any"/>
    </xsl:when>
    <xsl:when test="$divisions-number-from = 'book'">
      <xsl:number level="any"/>
    </xsl:when>
    <xsl:when test="$divisions-number-from = 'root'">
      <xsl:number level="any"/>
    </xsl:when>
    <xsl:otherwise>
      <xsl:message select="'Error: divisions-number-from='||$divisions-number-from"/>
      <xsl:sequence select="0"/>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

<xsl:template match="db:preface|db:chapter|db:appendix|db:partintro
                     |db:dedication|db:colophon|db:acknowledgements
                     |db:article
                     |db:glossary|db:bibliography
                     |db:index|db:setindex" mode="mp:label-number">
  <xsl:choose>
    <xsl:when test="$components-number-from = 'set'
                    and ancestor::db:set">
      <xsl:number from="db:set" level="any"/>
    </xsl:when>
    <xsl:when test="$components-number-from = 'set'">
      <xsl:number level="any"/>
    </xsl:when>
    <xsl:when test="$components-number-from = 'book'
                    and ancestor::db:book">
      <xsl:number from="db:book" level="any"/>
    </xsl:when>
    <xsl:when test="$components-number-from = 'book'">
      <xsl:number level="any"/>
    </xsl:when>
    <xsl:when test="$components-number-from = 'division'
                    and ancestor::db:part">
      <xsl:number from="db:part" level="any"/>
    </xsl:when>
    <xsl:when test="$components-number-from = 'division'
                    and ancestor::db:book">
      <xsl:number from="db:book" level="single"/>
    </xsl:when>
    <xsl:when test="$components-number-from = 'division'">
      <xsl:number level="any"/>
    </xsl:when>
    <xsl:when test="$components-number-from = 'root'">
      <xsl:number level="any"/>
    </xsl:when>
    <xsl:otherwise>
      <xsl:message select="'Error: components-number-from='||$components-number-from"/>
      <xsl:sequence select="0"/>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

<xsl:template match="db:refentry|db:refsection|db:refsect1|db:refsect2|db:refsect3"
              mode="mp:label-number">
  <!-- not usually numbered -->
  <xsl:sequence select="()"/>
</xsl:template>

<xsl:template match="db:section|db:sect1|db:sect2|db:sect3|db:sect4|db:sect5
                     |db:simplesect"
              mode="mp:label-number">
  <xsl:choose>
    <xsl:when test="parent::db:section|parent::db:sect1|parent::db:sect2
                    | parent::db:sect3|parent::db:sect4|parent::db:sect5">
      <xsl:number from="db:section|db:sect1|db:sect2|db:sect3|db:sect4|db:sect5"
                  level="single"/>
    </xsl:when>
    <xsl:when test="$sections-number-from = 'set'
                    and ancestor::db:set">
      <xsl:number count="db:section[not(parent::db:section)]|db:sect1"
                  from="db:set" level="any"/>
    </xsl:when>
    <xsl:when test="$sections-number-from = 'set'">
      <xsl:number count="db:section[not(parent::db:section)]|db:sect1"
                  level="any"/>
    </xsl:when>
    <xsl:when test="$sections-number-from = 'book'
                    and ancestor::db:book">
      <xsl:number count="db:section[not(parent::db:section)]|db:sect1"
                  from="db:book" level="any"/>
    </xsl:when>
    <xsl:when test="$sections-number-from = 'book'">
      <xsl:number count="db:section[not(parent::db:section)]|db:sect1"
                  level="any"/>
    </xsl:when>
    <xsl:when test="$sections-number-from = 'division'
                    and ancestor::db:part">
      <xsl:number count="db:section[not(parent::db:section)]|db:sect1"
                  from="db:part" level="any"/>
    </xsl:when>
    <xsl:when test="$sections-number-from = 'division'">
      <xsl:number count="db:section[not(parent::db:section)
                                    and not(ancestor::db:part)]
                         |db:sect1[not(ancestor::db:part)]"
                  from="db:book" level="any"/>
    </xsl:when>
    <!-- bibliography and glossary are special because they can be either
         ancestors or preceding elements which impacts out level=any works -->
    <xsl:when test="$sections-number-from = 'component'
                    and (ancestor::db:glossary|ancestor::db:bibliography)">
      <xsl:number count="db:section[not(parent::db:section)]|db:sect1"
                  from="db:glossary|db:bibliography"
                  level="any"/>
    </xsl:when>
    <xsl:when test="$sections-number-from = 'component'
                    and (ancestor::db:preface|ancestor::db:chapter
                         |ancestor::db:appendix|ancestor::db:partintro
                         |ancestor::db:dedication|ancestor::db:colophon
                         |ancestor::db:acknowledgements
                         |ancestor::db:article|ancestor::db:refentry
                         |ancestor::db:index|ancestor::db:setindex)">
      <xsl:number count="db:section[not(parent::db:section)
                                    and not(ancestor::db:bibliography
                                            |ancestor::db:glossary)]
                         |db:sect1[not(ancestor::db:bibliography
                                       |ancestor::db:glossary)]"
                  from="db:preface|db:chapter|db:appendix|db:partintro
                        |db:dedication|db:colophon|db:acknowledgements
                        |db:article|db:refentry
                        |db:index|db:setindex"
                  level="any"/>
    </xsl:when>
    <xsl:when test="$sections-number-from = 'component'">
      <xsl:number count="db:section[not(parent::db:section)]|db:sect1"
                  from="db:book" level="any"/>
    </xsl:when>
    <xsl:when test="$sections-number-from = 'root'">
      <xsl:number count="db:section[not(parent::db:section)]|db:sect1"
                  level="any"/>
    </xsl:when>
    <xsl:otherwise>
      <xsl:message select="'Error: sections-number-from='||$sections-number-from"/>
      <xsl:sequence select="0"/>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

<xsl:template match="db:figure[not(parent::db:formalgroup)]|db:formalgroup[db:figure]"
              mode="mp:label-number">
  <xsl:choose>
    <xsl:when test="$formal-objects-number-from = 'set'
                    and ancestor::db:set">
      <xsl:number count="db:figure[not(ancestor::db:formalgroup)]
                         |db:formalgroup[db:figure]"
                  from="db:set" level="any"/>
    </xsl:when>
    <xsl:when test="$formal-objects-number-from = 'set'">
      <xsl:number count="db:figure[not(ancestor::db:formalgroup)]
                         |db:formalgroup[db:figure]"
                  level="any"/>
    </xsl:when>
    <xsl:when test="$formal-objects-number-from = 'book'
                    and ancestor::db:book">
      <xsl:number count="db:figure[not(ancestor::db:formalgroup)]
                         |db:formalgroup[db:figure]"
                  from="db:book" level="any"/>
    </xsl:when>
    <xsl:when test="$formal-objects-number-from = 'book'">
      <xsl:number count="db:figure[not(ancestor::db:formalgroup)]
                         |db:formalgroup[db:figure]"
                  level="any"/>
    </xsl:when>
    <xsl:when test="$formal-objects-number-from = 'division'
                    and (ancestor::db:part|ancestor::db:reference)">
      <xsl:number count="db:figure[not(ancestor::db:formalgroup)]
                         |db:formalgroup[db:figure]"
                  from="db:part|db:reference" level="any"/>
    </xsl:when>
    <xsl:when test="$formal-objects-number-from = 'division'">
      <xsl:number count="db:figure[not(ancestor::db:formalgroup)
                                   and not(ancestor::db:part|ancestor::db:reference)]
                         |db:formalgroup[db:figure
                                         and not(ancestor::db:part|ancestor::db:reference)]"
                  from="db:book" level="any"/>
    </xsl:when>
    <xsl:when test="$formal-objects-number-from = 'component'
                    and (ancestor::db:preface|ancestor::db:chapter
                         |ancestor::db:appendix|ancestor::db:partintro
                         |ancestor::db:dedication|ancestor::db:colophon
                         |ancestor::db:acknowledgements
                         |ancestor::db:article|ancestor::db:refentry
                         |ancestor::db:glossary|ancestor::db:bibliography
                         |ancestor::db:index|ancestor::db:setindex)">
      <xsl:number count="db:figure[not(ancestor::db:formalgroup)]
                         |db:formalgroup[db:figure]"
                  from="db:preface|db:chapter|db:appendix|db:partintro
                        |db:dedication|db:colophon|db:acknowledgements
                        |db:article|db:refentry
                        |db:glossary|db:bibliography
                        |db:index|db:setindex"
                  level="any"/>
    </xsl:when>
    <xsl:when test="$formal-objects-number-from = 'component'">
      <xsl:number count="db:figure[not(ancestor::db:formalgroup)]
                         |db:formalgroup[db:figure]"
                  from="db:book" level="any"/>
    </xsl:when>
    <xsl:when test="$formal-objects-number-from = 'section'
                    and (ancestor::db:section|ancestor::db:sect1
                         |ancestor::db:sect2|ancestor::db:sect3
                         |ancestor::db:sect4|ancestor::db:sect5)">
      <xsl:number count="db:figure[not(ancestor::db:formalgroup)]
                         |db:formalgroup[db:figure]"
                  from="db:section|db:sect1|db:sect2|db:sect3|db:sect4|db:sect5"
                  level="single"/>
    </xsl:when>
    <xsl:when test="$formal-objects-number-from = 'section'
                    and (ancestor::db:preface|ancestor::db:chapter
                         |ancestor::db:appendix|ancestor::db:partintro
                         |ancestor::db:dedication|ancestor::db:colophon
                         |ancestor::db:acknowledgements
                         |ancestor::db:article|ancestor::db:refentry
                         |ancestor::db:glossary|ancestor::db:bibliography
                         |ancestor::db:index|ancestor::db:setindex)">
      <xsl:number count="db:figure[not(ancestor::db:formalgroup)]
                         |db:formalgroup[db:figure]"
                  from="db:preface|db:chapter|db:appendix|db:partintro
                        |db:dedication|db:colophon|db:acknowledgements
                        |db:article|db:refentry
                        |db:glossary|db:bibliography
                        |db:index|db:setindex"
                  level="any"/>
    </xsl:when>
    <xsl:when test="$formal-objects-number-from = 'section'">
      <xsl:number count="db:figure[not(ancestor::db:formalgroup)]
                         |db:formalgroup[db:figure]"
                  from="db:book" level="any"/>
    </xsl:when>
    <xsl:when test="$formal-objects-number-from = 'root'">
      <xsl:number count="db:figure[not(ancestor::db:formalgroup)]
                         |db:formalgroup[db:figure]"
                  level="any"/>
    </xsl:when>
    <xsl:otherwise>
      <xsl:message select="'Error: formal-objects-number-from='||$formal-objects-number-from"/>
      <xsl:sequence select="0"/>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

<xsl:template match="db:table[not(parent::db:formalgroup)]|db:formalgroup[db:table]"
              mode="mp:label-number">
  <xsl:choose>
    <xsl:when test="$formal-objects-number-from = 'set'
                    and ancestor::db:set">
      <xsl:number count="db:table[not(ancestor::db:formalgroup)]
                         |db:formalgroup[db:table]"
                  from="db:set" level="any"/>
    </xsl:when>
    <xsl:when test="$formal-objects-number-from = 'set'">
      <xsl:number count="db:table[not(ancestor::db:formalgroup)]
                         |db:formalgroup[db:table]"
                  level="any"/>
    </xsl:when>
    <xsl:when test="$formal-objects-number-from = 'book'
                    and ancestor::db:book">
      <xsl:number count="db:table[not(ancestor::db:formalgroup)]
                         |db:formalgroup[db:table]"
                  from="db:book" level="any"/>
    </xsl:when>
    <xsl:when test="$formal-objects-number-from = 'book'">
      <xsl:number count="db:table[not(ancestor::db:formalgroup)]
                         |db:formalgroup[db:table]"
                  level="any"/>
    </xsl:when>
    <xsl:when test="$formal-objects-number-from = 'division'
                    and (ancestor::db:part|ancestor::db:reference)">
      <xsl:number count="db:table[not(ancestor::db:formalgroup)]
                         |db:formalgroup[db:table]"
                  from="db:part|db:reference" level="any"/>
    </xsl:when>
    <xsl:when test="$formal-objects-number-from = 'division'">
      <xsl:number count="db:table[not(ancestor::db:formalgroup)
                                   and not(ancestor::db:part|ancestor::db:reference)]
                         |db:formalgroup[db:table
                                         and not(ancestor::db:part|ancestor::db:reference)]"
                  from="db:book" level="any"/>
    </xsl:when>
    <xsl:when test="$formal-objects-number-from = 'component'
                    and (ancestor::db:preface|ancestor::db:chapter
                         |ancestor::db:appendix|ancestor::db:partintro
                         |ancestor::db:dedication|ancestor::db:colophon
                         |ancestor::db:acknowledgements
                         |ancestor::db:article|ancestor::db:refentry
                         |ancestor::db:glossary|ancestor::db:bibliography
                         |ancestor::db:index|ancestor::db:setindex)">
      <xsl:number count="db:table[not(ancestor::db:formalgroup)]
                         |db:formalgroup[db:table]"
                  from="db:preface|db:chapter|db:appendix|db:partintro
                        |db:dedication|db:colophon|db:acknowledgements
                        |db:article|db:refentry
                        |db:glossary|db:bibliography
                        |db:index|db:setindex"
                  level="any"/>
    </xsl:when>
    <xsl:when test="$formal-objects-number-from = 'component'">
      <xsl:number count="db:table[not(ancestor::db:formalgroup)]
                         |db:formalgroup[db:table]"
                  from="db:book" level="any"/>
    </xsl:when>
    <xsl:when test="$formal-objects-number-from = 'section'
                    and (ancestor::db:section|ancestor::db:sect1
                         |ancestor::db:sect2|ancestor::db:sect3
                         |ancestor::db:sect4|ancestor::db:sect5)">
      <xsl:number count="db:table[not(ancestor::db:formalgroup)]
                         |db:formalgroup[db:table]"
                  from="db:section|db:sect1|db:sect2|db:sect3|db:sect4|db:sect5"
                  level="single"/>
    </xsl:when>
    <xsl:when test="$formal-objects-number-from = 'section'
                    and (ancestor::db:preface|ancestor::db:chapter
                         |ancestor::db:appendix|ancestor::db:partintro
                         |ancestor::db:dedication|ancestor::db:colophon
                         |ancestor::db:acknowledgements
                         |ancestor::db:article|ancestor::db:refentry
                         |ancestor::db:glossary|ancestor::db:bibliography
                         |ancestor::db:index|ancestor::db:setindex)">
      <xsl:number count="db:table[not(ancestor::db:formalgroup)]
                         |db:formalgroup[db:table]"
                  from="db:preface|db:chapter|db:appendix|db:partintro
                        |db:dedication|db:colophon|db:acknowledgements
                        |db:article|db:refentry
                        |db:glossary|db:bibliography
                        |db:index|db:setindex"
                  level="any"/>
    </xsl:when>
    <xsl:when test="$formal-objects-number-from = 'section'">
      <xsl:number count="db:table[not(ancestor::db:formalgroup)]
                         |db:formalgroup[db:table]"
                  from="db:book" level="any"/>
    </xsl:when>
    <xsl:when test="$formal-objects-number-from = 'root'">
      <xsl:number count="db:table[not(ancestor::db:formalgroup)]
                         |db:formalgroup[db:table]"
                  level="any"/>
    </xsl:when>
    <xsl:otherwise>
      <xsl:message select="'Error: formal-objects-number-from='||$formal-objects-number-from"/>
      <xsl:sequence select="0"/>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

<xsl:template match="db:example[not(parent::db:formalgroup)]|db:formalgroup[db:example]"
              mode="mp:label-number">
  <xsl:choose>
    <xsl:when test="$formal-objects-number-from = 'set'
                    and ancestor::db:set">
      <xsl:number count="db:example[not(ancestor::db:formalgroup)]
                         |db:formalgroup[db:example]"
                  from="db:set" level="any"/>
    </xsl:when>
    <xsl:when test="$formal-objects-number-from = 'set'">
      <xsl:number count="db:example[not(ancestor::db:formalgroup)]
                         |db:formalgroup[db:example]"
                  level="any"/>
    </xsl:when>
    <xsl:when test="$formal-objects-number-from = 'book'
                    and ancestor::db:book">
      <xsl:number count="db:example[not(ancestor::db:formalgroup)]
                         |db:formalgroup[db:example]"
                  from="db:book" level="any"/>
    </xsl:when>
    <xsl:when test="$formal-objects-number-from = 'book'">
      <xsl:number count="db:example[not(ancestor::db:formalgroup)]
                         |db:formalgroup[db:example]"
                  level="any"/>
    </xsl:when>
    <xsl:when test="$formal-objects-number-from = 'division'
                    and (ancestor::db:part|ancestor::db:reference)">
      <xsl:number count="db:example[not(ancestor::db:formalgroup)]
                         |db:formalgroup[db:example]"
                  from="db:part|db:reference" level="any"/>
    </xsl:when>
    <xsl:when test="$formal-objects-number-from = 'division'">
      <xsl:number count="db:example[not(ancestor::db:formalgroup)
                                   and not(ancestor::db:part|ancestor::db:reference)]
                         |db:formalgroup[db:example
                                         and not(ancestor::db:part|ancestor::db:reference)]"
                  from="db:book" level="any"/>
    </xsl:when>
    <xsl:when test="$formal-objects-number-from = 'component'
                    and (ancestor::db:preface|ancestor::db:chapter
                         |ancestor::db:appendix|ancestor::db:partintro
                         |ancestor::db:dedication|ancestor::db:colophon
                         |ancestor::db:acknowledgements
                         |ancestor::db:article|ancestor::db:refentry
                         |ancestor::db:glossary|ancestor::db:bibliography
                         |ancestor::db:index|ancestor::db:setindex)">
      <xsl:number count="db:example[not(ancestor::db:formalgroup)]
                         |db:formalgroup[db:example]"
                  from="db:preface|db:chapter|db:appendix|db:partintro
                        |db:dedication|db:colophon|db:acknowledgements
                        |db:article|db:refentry
                        |db:glossary|db:bibliography
                        |db:index|db:setindex"
                  level="any"/>
    </xsl:when>
    <xsl:when test="$formal-objects-number-from = 'component'">
      <xsl:number count="db:example[not(ancestor::db:formalgroup)]
                         |db:formalgroup[db:example]"
                  from="db:book" level="any"/>
    </xsl:when>
    <xsl:when test="$formal-objects-number-from = 'section'
                    and (ancestor::db:section|ancestor::db:sect1
                         |ancestor::db:sect2|ancestor::db:sect3
                         |ancestor::db:sect4|ancestor::db:sect5)">
      <xsl:number count="db:example[not(ancestor::db:formalgroup)]
                         |db:formalgroup[db:example]"
                  from="db:section|db:sect1|db:sect2|db:sect3|db:sect4|db:sect5"
                  level="single"/>
    </xsl:when>
    <xsl:when test="$formal-objects-number-from = 'section'
                    and (ancestor::db:preface|ancestor::db:chapter
                         |ancestor::db:appendix|ancestor::db:partintro
                         |ancestor::db:dedication|ancestor::db:colophon
                         |ancestor::db:acknowledgements
                         |ancestor::db:article|ancestor::db:refentry
                         |ancestor::db:glossary|ancestor::db:bibliography
                         |ancestor::db:index|ancestor::db:setindex)">
      <xsl:number count="db:example[not(ancestor::db:formalgroup)]
                         |db:formalgroup[db:example]"
                  from="db:preface|db:chapter|db:appendix|db:partintro
                        |db:dedication|db:colophon|db:acknowledgements
                        |db:article|db:refentry
                        |db:glossary|db:bibliography
                        |db:index|db:setindex"
                  level="any"/>
    </xsl:when>
    <xsl:when test="$formal-objects-number-from = 'section'">
      <xsl:number count="db:example[not(ancestor::db:formalgroup)]
                         |db:formalgroup[db:example]"
                  from="db:book" level="any"/>
    </xsl:when>
    <xsl:when test="$formal-objects-number-from = 'root'">
      <xsl:number count="db:example[not(ancestor::db:formalgroup)]
                         |db:formalgroup[db:example]"
                  level="any"/>
    </xsl:when>
    <xsl:otherwise>
      <xsl:message select="'Error: formal-objects-number-from='||$formal-objects-number-from"/>
      <xsl:sequence select="0"/>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

<xsl:template match="db:equation[db:info/db:title and not(parent::db:formalgroup)]
                     |db:formalgroup[db:equation]"
              mode="mp:label-number">
  <xsl:choose>
    <xsl:when test="$formal-objects-number-from = 'set'
                    and ancestor::db:set">
      <xsl:number count="db:equation[db:info/db:title and not(ancestor::db:formalgroup)]
                         |db:formalgroup[db:equation]"
                  from="db:set" level="any"/>
    </xsl:when>
    <xsl:when test="$formal-objects-number-from = 'set'">
      <xsl:number count="db:equation[db:info/db:title and not(ancestor::db:formalgroup)]
                         |db:formalgroup[db:equation]"
                  level="any"/>
    </xsl:when>
    <xsl:when test="$formal-objects-number-from = 'book'
                    and ancestor::db:book">
      <xsl:number count="db:equation[db:info/db:title and not(ancestor::db:formalgroup)]
                         |db:formalgroup[db:equation]"
                  from="db:book" level="any"/>
    </xsl:when>
    <xsl:when test="$formal-objects-number-from = 'book'">
      <xsl:number count="db:equation[db:info/db:title and not(ancestor::db:formalgroup)]
                         |db:formalgroup[db:equation]"
                  level="any"/>
    </xsl:when>
    <xsl:when test="$formal-objects-number-from = 'division'
                    and (ancestor::db:part|ancestor::db:reference)">
      <xsl:number count="db:equation[db:info/db:title and not(ancestor::db:formalgroup)]
                         |db:formalgroup[db:equation]"
                  from="db:part|db:reference" level="any"/>
    </xsl:when>
    <xsl:when test="$formal-objects-number-from = 'division'">
      <xsl:number count="db:equation[db:info/db:title
                                      and not(ancestor::db:formalgroup)
                                      and not(ancestor::db:part|ancestor::db:reference)]
                         |db:formalgroup[db:equation
                                         and not(ancestor::db:part|ancestor::db:reference)]"
                  from="db:book" level="any"/>
    </xsl:when>
    <xsl:when test="$formal-objects-number-from = 'component'
                    and (ancestor::db:preface|ancestor::db:chapter
                         |ancestor::db:appendix|ancestor::db:partintro
                         |ancestor::db:dedication|ancestor::db:colophon
                         |ancestor::db:acknowledgements
                         |ancestor::db:article|ancestor::db:refentry
                         |ancestor::db:glossary|ancestor::db:bibliography
                         |ancestor::db:index|ancestor::db:setindex)">
      <xsl:number count="db:equation[db:info/db:title and not(ancestor::db:formalgroup)]
                         |db:formalgroup[db:equation]"
                  from="db:preface|db:chapter|db:appendix|db:partintro
                        |db:dedication|db:colophon|db:acknowledgements
                        |db:article|db:refentry
                        |db:glossary|db:bibliography
                        |db:index|db:setindex"
                  level="any"/>
    </xsl:when>
    <xsl:when test="$formal-objects-number-from = 'component'">
      <xsl:number count="db:equation[db:info/db:title and not(ancestor::db:formalgroup)]
                         |db:formalgroup[db:equation]"
                  from="db:book" level="any"/>
    </xsl:when>
    <xsl:when test="$formal-objects-number-from = 'section'
                    and (ancestor::db:section|ancestor::db:sect1
                         |ancestor::db:sect2|ancestor::db:sect3
                         |ancestor::db:sect4|ancestor::db:sect5)">
      <xsl:number count="db:equation[db:info/db:title and not(ancestor::db:formalgroup)]
                         |db:formalgroup[db:equation]"
                  from="db:section|db:sect1|db:sect2|db:sect3|db:sect4|db:sect5"
                  level="single"/>
    </xsl:when>
    <xsl:when test="$formal-objects-number-from = 'section'
                    and (ancestor::db:preface|ancestor::db:chapter
                         |ancestor::db:appendix|ancestor::db:partintro
                         |ancestor::db:dedication|ancestor::db:colophon
                         |ancestor::db:acknowledgements
                         |ancestor::db:article|ancestor::db:refentry
                         |ancestor::db:glossary|ancestor::db:bibliography
                         |ancestor::db:index|ancestor::db:setindex)">
      <xsl:number count="db:equation[db:info/db:title and not(ancestor::db:formalgroup)]
                         |db:formalgroup[db:equation]"
                  from="db:preface|db:chapter|db:appendix|db:partintro
                        |db:dedication|db:colophon|db:acknowledgements
                        |db:article|db:refentry
                        |db:glossary|db:bibliography
                        |db:index|db:setindex"
                  level="any"/>
    </xsl:when>
    <xsl:when test="$formal-objects-number-from = 'section'">
      <xsl:number count="db:equation[db:info/db:title and not(ancestor::db:formalgroup)]
                         |db:formalgroup[db:equation]"
                  from="db:book" level="any"/>
    </xsl:when>
    <xsl:when test="$formal-objects-number-from = 'root'">
      <xsl:number count="db:equation[db:info/db:title and not(ancestor::db:formalgroup)]
                         |db:formalgroup[db:equation]"
                  level="any"/>
    </xsl:when>
    <xsl:otherwise>
      <xsl:message select="'Error: formal-objects-number-from='||$formal-objects-number-from"/>
      <xsl:sequence select="0"/>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

<xsl:template match="db:figure[parent::db:formalgroup]
                     |db:table[parent::db:formalgroup]
                     |db:example[parent::db:formalgroup]
                     |db:equation[parent::db:formalgroup]"
              mode="mp:label-number">
  <xsl:number from="db:formalgroup"/>
</xsl:template>

<xsl:template match="db:procedure[db:info/db:title]"
              mode="mp:label-number">
  <xsl:choose>
    <xsl:when test="$formal-objects-number-from = 'set'
                    and ancestor::db:set">
      <xsl:number count="db:procedure[db:info/db:title]"
                  from="db:set" level="any"/>
    </xsl:when>
    <xsl:when test="$formal-objects-number-from = 'set'">
      <xsl:number count="db:procedure[db:info/db:title]"
                  level="any"/>
    </xsl:when>
    <xsl:when test="$formal-objects-number-from = 'book'
                    and ancestor::db:book">
      <xsl:number count="db:procedure[db:info/db:title]"
                  from="db:book" level="any"/>
    </xsl:when>
    <xsl:when test="$formal-objects-number-from = 'book'">
      <xsl:number count="db:procedure[db:info/db:title]"
                  level="any"/>
    </xsl:when>
    <xsl:when test="$formal-objects-number-from = 'division'
                    and (ancestor::db:part|ancestor::db:reference)">
      <xsl:number count="db:procedure[db:info/db:title]"
                  from="db:part|db:reference" level="any"/>
    </xsl:when>
    <xsl:when test="$formal-objects-number-from = 'division'">
      <xsl:number count="db:procedure[db:info/db:title
                                      and not(ancestor::db:part|ancestor::db:reference)]"
                  from="db:book" level="any"/>
    </xsl:when>
    <xsl:when test="$formal-objects-number-from = 'component'
                    and (ancestor::db:preface|ancestor::db:chapter
                         |ancestor::db:appendix|ancestor::db:partintro
                         |ancestor::db:dedication|ancestor::db:colophon
                         |ancestor::db:acknowledgements
                         |ancestor::db:article|ancestor::db:refentry
                         |ancestor::db:glossary|ancestor::db:bibliography
                         |ancestor::db:index|ancestor::db:setindex)">
      <xsl:number count="db:procedure[db:info/db:title]"
                  from="db:preface|db:chapter|db:appendix|db:partintro
                        |db:dedication|db:colophon|db:acknowledgements
                        |db:article|db:refentry
                        |db:glossary|db:bibliography
                        |db:index|db:setindex"
                  level="any"/>
    </xsl:when>
    <xsl:when test="$formal-objects-number-from = 'component'">
      <xsl:number count="db:procedure[db:info/db:title]"
                  from="db:book" level="any"/>
    </xsl:when>
    <xsl:when test="$formal-objects-number-from = 'section'
                    and (ancestor::db:section|ancestor::db:sect1
                         |ancestor::db:sect2|ancestor::db:sect3
                         |ancestor::db:sect4|ancestor::db:sect5)">
      <xsl:number count="db:procedure[db:info/db:title]"
                  from="db:section|db:sect1|db:sect2|db:sect3|db:sect4|db:sect5"
                  level="single"/>
    </xsl:when>
    <xsl:when test="$formal-objects-number-from = 'section'
                    and (ancestor::db:preface|ancestor::db:chapter
                         |ancestor::db:appendix|ancestor::db:partintro
                         |ancestor::db:dedication|ancestor::db:colophon
                         |ancestor::db:acknowledgements
                         |ancestor::db:article|ancestor::db:refentry
                         |ancestor::db:glossary|ancestor::db:bibliography
                         |ancestor::db:index|ancestor::db:setindex)">
      <xsl:number count="db:procedure[db:info/db:title]"
                  from="db:preface|db:chapter|db:appendix|db:partintro
                        |db:dedication|db:colophon|db:acknowledgements
                        |db:article|db:refentry
                        |db:glossary|db:bibliography
                        |db:index|db:setindex"
                  level="any"/>
    </xsl:when>
    <xsl:when test="$formal-objects-number-from = 'section'">
      <xsl:number count="db:procedure[db:info/db:title]"
                  from="db:book" level="any"/>
    </xsl:when>
    <xsl:when test="$formal-objects-number-from = 'root'">
      <xsl:number count="db:procedure[db:info/db:title]"
                  level="any"/>
    </xsl:when>
    <xsl:otherwise>
      <xsl:message select="'Error: formal-objects-number-from='||$formal-objects-number-from"/>
      <xsl:sequence select="0"/>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

<!-- These are for backwards compatibility without adding a bunch of
     new conditions for qandasets. -->
<xsl:template match="db:figure[not(parent::db:formalgroup) and ancestor::db:qandadiv]"
              mode="mp:label-number" priority="10">
  <xsl:number count="db:figure[not(ancestor::db:formalgroup)]
                     |db:formalgroup[db:figure]"
              from="db:qandadiv" level="any"/>
</xsl:template>

<xsl:template match="db:table[not(parent::db:formalgroup) and ancestor::db:qandadiv]"
              mode="mp:label-number" priority="10">
  <xsl:number count="db:table[not(ancestor::db:formalgroup)]
                     |db:formalgroup[db:table]"
              from="db:qandadiv" level="any"/>
</xsl:template>

<xsl:template match="db:example[not(parent::db:formalgroup) and ancestor::db:qandadiv]"
              mode="mp:label-number" priority="10">
  <xsl:number count="db:example[not(ancestor::db:formalgroup)]
                     |db:formalgroup[db:example]"
              from="db:qandadiv" level="any"/>
</xsl:template>

<xsl:template match="db:equation[db:info/db:title
                                 and not(parent::db:formalgroup)
                                 and ancestor::db:qandadiv]"
              mode="mp:label-number" priority="10">
  <xsl:number count="db:equation[db:info/db:title and not(ancestor::db:formalgroup)]
                     |db:formalgroup[db:equation]"
              from="db:qandadiv" level="any"/>
</xsl:template>

<xsl:template match="db:procedure[db:info/db:title and ancestor::db:qandadiv]"
              mode="mp:label-number" priority="10">
  <xsl:number count="db:procedure[db:info/db:title]"
              from="db:qandadiv" level="any"/>
</xsl:template>

<xsl:template match="db:step" mode="mp:label-number" as="xs:integer?">
  <xsl:number level="single"/>
</xsl:template>

<xsl:template match="db:qandaset" mode="mp:label-number" as="xs:integer?">
  <xsl:sequence select="()"/>
</xsl:template>

<xsl:template match="db:qandadiv" mode="mp:label-number" as="xs:integer?">
  <xsl:number level="single"/>
</xsl:template>

</xsl:stylesheet>

units.xsl

11 functions (3 unused, 3 used only in one other module), 4 variables (1 unused)

Instructions
Variable $v:unit-scale as map(*)
Variable $vp:length-regex
Variable $vp:percent-regex
Unused
Variable $vp:relative-regex
Function f:length-units($length as xs:string?) as xs:string?
Unused
Function f:absolute-length($length as map(*)) as xs:double
Function f:relative-length($length as map(*)) as xs:double
Function f:is-empty-length($length as map(*)?) as xs:boolean
Function f:equal-lengths($a as map(*)?, $b as map(*)?) as xs:boolean
Function f:make-length#1($relative as xs:double) as map(*)
Unused
Function f:make-length#2($magnitude as xs:double, $unit as xs:string) as map(*)
Function f:make-length#3($relative as xs:double, $magnitude as xs:double, $unit as xs:string) as map(*)
Function f:length-string($length as map(*)?) as xs:string?
Unused
Source code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:db="http://docbook.org/ns/docbook"
                xmlns:f="http://docbook.org/ns/docbook/functions"
                xmlns:v="http://docbook.org/ns/docbook/variables"
                xmlns:vp="http://docbook.org/ns/docbook/variables/private"
                xmlns:m="http://docbook.org/ns/docbook/modes"
                xmlns:map="http://www.w3.org/2005/xpath-functions/map"
                xmlns:xs="http://www.w3.org/2001/XMLSchema"
                xmlns="http://www.w3.org/1999/xhtml"
                default-mode="m:docbook"
                exclude-result-prefixes="db f m map v vp xs"
                version="3.0">

<xsl:variable name="v:unit-scale" as="map(*)">
  <xsl:map>
    <xsl:map-entry key="'px'" select="1.0"/>
    <xsl:map-entry key="'in'" select="$pixels-per-inch"/>
    <xsl:map-entry key="'m'" select="$pixels-per-inch div 2.54 * 100.0"/>
    <xsl:map-entry key="'cm'" select="$pixels-per-inch div 2.54"/>
    <xsl:map-entry key="'mm'" select="$pixels-per-inch div 25.4"/>
    <xsl:map-entry key="'pt'" select="$pixels-per-inch div 72.0"/>
    <xsl:map-entry key="'pc'" select="$pixels-per-inch div 6.0"/>
    <xsl:map-entry key="'em'" select="$pixels-per-inch div 6.0"/>
    <xsl:map-entry key="'barleycorn'" select="$pixels-per-inch div 3.0"/>
  </xsl:map>
</xsl:variable>

<xsl:variable name="vp:length-regex" select="'^(\d+(\.\d+)?)\s*(\S+)?$'"/>
<xsl:variable name="vp:percent-regex" select="'^(\d+(\.\d+)?)\s*%$'"/>
<xsl:variable name="vp:relative-regex" select="'^(\d+(\.\d+)?)\s*\*(\s*\+\s*(.*))?$'"/>

<xsl:function name="f:parse-length" as="map(*)">
  <xsl:param name="length" as="xs:string?"/>

  <xsl:choose>
    <xsl:when test="empty($length)">
      <xsl:sequence select="f:empty-length()"/>
    </xsl:when>
    <xsl:otherwise>
      <!--
      <xsl:variable name="x" select="'3*+0.25pt'"/>
      <xsl:message select="'matches: ' || $x, matches($x, $vp:relative-regex)"/>
      <xsl:message select="'matches: ', $vp:relative-regex"/>
      <xsl:message select="'matches: ' || $x,
                           matches($x, '^(\d+(\.\d+)?)\s*\*\s*(\+\s*(.*)$)')"/>
      -->

      <xsl:variable name="length" select="normalize-space($length)"/>

      <xsl:variable name="parsed"
                    select="if (matches($length, $vp:relative-regex))
                            then map { 'relative':
                                        xs:decimal(replace($length, $vp:relative-regex, '$1'))
                                     }
                            else map { 'relative': 0.0 }"/>

      <xsl:variable name="length"
                    select="if (matches($length, $vp:relative-regex))
                            then replace($length, $vp:relative-regex, '$4')
                            else $length"/>

      <xsl:choose>
        <xsl:when test="$parsed?relative and $length = ''">
          <xsl:sequence select="map:put($parsed, 'magnitude', 0)
                                => map:put('unit', 'px')"/>
        </xsl:when>
        <xsl:when test="matches($length, $vp:length-regex)">
          <xsl:variable name="mag"
                        select="xs:double(replace($length, $vp:length-regex, '$1'))"/>
          <xsl:variable name="unit"
                        select="replace($length, $vp:length-regex, '$3')"/>
          <xsl:variable name="unit"
                        select="if ($unit = '')
                                then 'px'
                                else $unit"/>

          <xsl:choose>
            <xsl:when test="map:contains($v:unit-scale, $unit) or $unit = '%'">
              <xsl:sequence select="map:put($parsed, 'magnitude', $mag)
                                    => map:put('unit', $unit)"/>
            </xsl:when>
            <xsl:otherwise>
              <xsl:message expand-text="yes"
                           >Unrecognized unit {$unit}, using default length</xsl:message>
              <xsl:sequence select="map:put($parsed, 'magnitude', $default-length-magnitude)
                                    => map:put('unit', $default-length-unit)"/>
            </xsl:otherwise>
          </xsl:choose>
        </xsl:when>
        <xsl:otherwise>
          <xsl:message expand-text="yes"
                       >Unparsable length {$length}, using default length</xsl:message>
          <xsl:sequence select="map:put($parsed, 'magnitude', $default-length-magnitude)
                                => map:put('unit', $default-length-unit)"/>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:otherwise>
  </xsl:choose>
</xsl:function>

<xsl:function name="f:length-units" as="xs:string?">
  <xsl:param name="length" as="xs:string?"/>
  <xsl:sequence select="if (exists($length))
                        then f:parse-length($length)?unit
                        else ()"/>
</xsl:function>

<xsl:function name="f:absolute-length" as="xs:double">
  <xsl:param name="length" as="map(*)"/>
  <xsl:choose>
    <xsl:when test="exists($length?magnitude) and exists($length?unit)
                    and map:contains($v:unit-scale, $length?unit)">
      <xsl:sequence select="round($length?magnitude * map:get($v:unit-scale, $length?unit))"/>
    </xsl:when>
    <xsl:otherwise>
      <!-- this should never happen, but ... -->
      <xsl:message>
        <xsl:text>Invalid length (</xsl:text>
        <xsl:value-of select="concat($length?magnitude, $length?unit)"/>
        <xsl:text>), returning 0 for absolute-length</xsl:text>
      </xsl:message>
      <xsl:sequence select="0"/>
    </xsl:otherwise>
  </xsl:choose>
</xsl:function>

<xsl:function name="f:relative-length" as="xs:double">
  <xsl:param name="length" as="map(*)"/>
  <xsl:sequence select="if ($length?relative)
                        then $length?relative
                        else 0.0"/>
</xsl:function>

<xsl:function name="f:empty-length" as="map(*)">
  <xsl:sequence select="map { }"/>
</xsl:function>

<xsl:function name="f:is-empty-length" as="xs:boolean">
  <xsl:param name="length" as="map(*)?"/>
  <xsl:sequence select="empty($length)
                        or (not($length?relative) and not($length?magnitude))"/>
</xsl:function>

<xsl:function name="f:equal-lengths" as="xs:boolean">
  <xsl:param name="a" as="map(*)?"/>
  <xsl:param name="b" as="map(*)?"/>
  <xsl:choose>
    <xsl:when test="f:is-empty-length($a) and f:is-empty-length($b)">
      <xsl:sequence select="true()"/>
    </xsl:when>
    <xsl:when test="f:is-empty-length($a) and not(f:is-empty-length($b))
                    or f:is-empty-length($b) and not(f:is-empty-length($a))">
      <xsl:sequence select="false()"/>
    </xsl:when>
    <xsl:otherwise>
      <xsl:sequence select="$a?relative eq $b?relative
                            and $a?magnitude eq $b?magnitude
                            and $a?unit eq $b?unit"/>
    </xsl:otherwise>
  </xsl:choose>
</xsl:function>

<xsl:function name="f:make-length" as="map(*)">
  <xsl:param name="relative" as="xs:double"/>
  <xsl:sequence select="map {
    'relative': $relative
    }"/>
</xsl:function>

<xsl:function name="f:make-length" as="map(*)">
  <xsl:param name="magnitude" as="xs:double"/>
  <xsl:param name="unit" as="xs:string"/>
  <xsl:sequence select="f:make-length(0.0, $magnitude, $unit)"/>
</xsl:function>

<xsl:function name="f:make-length" as="map(*)">
  <xsl:param name="relative" as="xs:double"/>
  <xsl:param name="magnitude" as="xs:double"/>
  <xsl:param name="unit" as="xs:string"/>
  <xsl:sequence select="map {
    'relative': 0.0,
    'magnitude': $magnitude,
    'unit': $unit
    }"/>
</xsl:function>

<xsl:function name="f:length-string" as="xs:string?">
  <xsl:param name="length" as="map(*)?"/>
  <xsl:if test="exists($length)">
    <xsl:variable name="rel"
                  select="if ($length?relative and $length?relative != 0.0)
                          then concat($length?relative, '*')
                          else ''"/>
    <xsl:sequence select="$rel || $length?magnitude || $length?unit"/>
  </xsl:if>
</xsl:function>

</xsl:stylesheet>

gentext.xsl

12 templates, 7 functions (2 unused, 1 used only in one other module)

Instructions
Function f:languages($context as document-node()) as xs:string+
Function f:in-scope-language($target as node()) as xs:string
Unused
Function fp:lookup-localization-template($node as element(), $lang as xs:string, $group as xs:string) as element(l:template)?
Function fp:localization-list($node as element(), $name as xs:string) as item()*
Function fp:lookup-localization-list($node as element(), $lang as xs:string, $name as xs:string) as element(l:list)?
Template match ≅ l:l10n
Mode: mp:merge-custom
Matches: l:l10n
Template match ≅ l:gentext
Mode: mp:merge-custom
Matches: l:gentext
Template match ≅ l:gentext/l:token
Mode: mp:merge-custom
Matches: l:gentext/l:token
Template match ≅ l:properties
Mode: mp:merge-custom
Matches: l:properties
Template match ≅ l:properties/l:property
Mode: mp:merge-custom
Matches: l:properties/l:property
Template match ≅ l:group
Mode: mp:merge-custom
Matches: l:group
Template match ≅ l:group/l:template
Mode: mp:merge-custom
Matches: l:group/l:template
Template match ≅ l:l10n/l:list
Mode: mp:merge-custom
Matches: l:l10n/l:list
Template match ≅ l:letters/l:l
Mode: mp:merge-custom
Matches: l:letters/l:l
Template match ≅ *
Mode: mp:merge-custom
Matches: *
Template match ≅ *
Mode: m:gentext
Matches: *
Template match ≅ db:answer|db:question
Mode: m:gentext
Matches: db:answer, db:question
Source code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:db="http://docbook.org/ns/docbook"
                xmlns:f="http://docbook.org/ns/docbook/functions"
                xmlns:fp="http://docbook.org/ns/docbook/functions/private"
                xmlns:l="http://docbook.org/ns/docbook/l10n"
                xmlns:ls="http://docbook.org/ns/docbook/l10n/source"
                xmlns:lt="http://docbook.org/ns/docbook/l10n/templates"
                xmlns:m="http://docbook.org/ns/docbook/modes"
                xmlns:map="http://www.w3.org/2005/xpath-functions/map"
                xmlns:mp="http://docbook.org/ns/docbook/modes/private"
                xmlns:n="http://docbook.org/ns/docbook/l10n/number"
                xmlns:t="http://docbook.org/ns/docbook/l10n/title"
                xmlns:v="http://docbook.org/ns/docbook/variables"
                xmlns:vp="http://docbook.org/ns/docbook/variables/private"
                xmlns:xs="http://www.w3.org/2001/XMLSchema"
                xmlns="http://www.w3.org/1999/xhtml"
                default-mode="m:docbook"
                exclude-result-prefixes="#all"
                version="3.0">

<xsl:function name="f:languages" as="xs:string+" cache="yes">
  <xsl:param name="context" as="document-node()"/>

  <xsl:variable name="always"
                select="('en', $default-language, $gentext-language)"/>

  <xsl:sequence
      select="if (exists($gentext-language))
              then distinct-values($always)
              else distinct-values(($always, $context//@xml:lang))"/>
</xsl:function>  

<xsl:function name="f:in-scope-language" as="xs:string" cache="yes">
  <xsl:param name="target" as="node()"/>
  <xsl:sequence select="($target/ancestor-or-self::*[@xml:lang][1]/@xml:lang,
                         $default-language)[1]"/>
</xsl:function>  

<!-- ============================================================ -->

<xsl:function name="fp:localization" as="element(l:l10n)" cache="yes">
  <xsl:param name="language" as="xs:string"/>

  <xsl:variable name="fn-region" select="lower-case($language) =&gt; replace('-', '_')"/>
  <xsl:variable name="fn" select="if (contains($fn-region, '_'))
                                  then substring-before($fn-region, '_')
                                  else ()"/>

  <xsl:variable name="base-locale" as="element(l:l10n)">
    <xsl:choose>
      <xsl:when test="doc-available('../locale/' || $fn-region || '.xml')">
        <xsl:sequence select="doc('../locale/' || $fn-region || '.xml')/l:l10n"/>
      </xsl:when>
      <xsl:when test="exists($fn) and doc-available('../locale/' || $fn || '.xml')">
        <xsl:sequence select="doc('../locale/' || $fn || '.xml')/l:l10n"/>
      </xsl:when>
      <xsl:when test="$language != $default-language">
        <xsl:sequence select="fp:localization($default-language)"/>
      </xsl:when>
      <xsl:when test="doc-available('../locale/en.xml')">
        <xsl:sequence select="doc('../locale/en.xml')/l:l10n"/>
      </xsl:when>
      <xsl:otherwise>
        <xsl:message terminate="yes"
                     select="'Failed to load localization or fallback localization'"/>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:variable>

  <xsl:choose>
    <xsl:when test="$v:custom-localizations/ls:locale[@language = $base-locale/@language]">
      <xsl:variable name="custom" as="element(l:l10n)">
        <xsl:apply-templates
            select="$v:custom-localizations/ls:locale[@language = $base-locale/@language]"
            mode="mp:transform-locale"/>
      </xsl:variable>
      <xsl:apply-templates select="$base-locale" mode="mp:merge-custom">
        <xsl:with-param name="custom" as="element(l:l10n)" tunnel="yes"
                        select="$custom"/>
      </xsl:apply-templates>
    </xsl:when>
    <xsl:otherwise>
      <xsl:sequence select="$base-locale"/>
    </xsl:otherwise>
  </xsl:choose>
</xsl:function>

<!-- ============================================================ -->

<xsl:function name="fp:localization-template" as="item()*">
  <xsl:param name="node" as="element()"/>
  <xsl:param name="group" as="xs:string"/>

  <xsl:variable name="lang" select="f:l10n-language($node)"/>

  <xsl:choose>
    <xsl:when test="exists(fp:lookup-localization-template($node, $lang, $group))">
      <xsl:sequence select="fp:lookup-localization-template($node, $lang, $group)"/>
    </xsl:when>
    <xsl:when test="exists(fp:lookup-localization-template($node, $default-language, $group))">
      <xsl:if test="f:is-true($warn-about-missing-localizations)">
        <xsl:message expand-text="yes"
        >No localization for {$group}/{local-name($node)} in {$lang}, using {$default-language}</xsl:message>
      </xsl:if>
      <xsl:sequence select="fp:lookup-localization-template($node, $default-language, $group)"/>
    </xsl:when>
    <xsl:when test="exists(fp:lookup-localization-template($node, 'en', $group))">
      <xsl:if test="f:is-true($warn-about-missing-localizations)">
        <xsl:message expand-text="yes"
        >No localization for {$group}/{local-name($node)} in {$lang}, using en</xsl:message>
      </xsl:if>
      <xsl:sequence select="fp:lookup-localization-template($node, 'en', $group)"/>
    </xsl:when>
    <xsl:otherwise>
      <xsl:if test="f:is-true($warn-about-missing-localizations)">
        <xsl:message expand-text="yes"
        >No localization for {$group}/{local-name($node)} in {$lang}, using "MISSING"</xsl:message>
      </xsl:if>
      <lt:text>MISSING</lt:text>
    </xsl:otherwise>
  </xsl:choose>
</xsl:function>

<xsl:function name="fp:lookup-localization-template" as="element(l:template)?" cache="yes">
  <xsl:param name="node" as="element()"/>
  <xsl:param name="lang" as="xs:string"/>
  <xsl:param name="group" as="xs:string"/>

  <xsl:variable name="l10n" select="fp:localization($lang)"/>

  <xsl:variable name="templates"
                select="$l10n/l:group[@name=$group]"/>

  <!--
  <xsl:message select="'lookup:', local-name($node), $lang, $group"/>
  -->

  <xsl:iterate select="$templates/l:template">
    <xsl:variable name="result" as="item()*">
      <xsl:evaluate xpath="@match" context-item="$node"/>
    </xsl:variable>
    <xsl:choose>
      <xsl:when test="boolean($result)">
        <!--<xsl:message select="'Y:', @match/string()"/>-->
        <xsl:break select="."/>
      </xsl:when>
      <xsl:otherwise>
        <!--<xsl:message select="'N:', @match/string()"/>-->
        <xsl:next-iteration/>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:iterate>
</xsl:function>

<!-- ============================================================ -->

<xsl:function name="fp:localization-list" as="item()*">
  <xsl:param name="node" as="element()"/>
  <xsl:param name="name" as="xs:string"/>

  <xsl:variable name="lang" select="f:l10n-language($node)"/>

  <xsl:choose>
    <xsl:when test="exists(fp:lookup-localization-list($node, $lang, $name))">
      <xsl:sequence select="fp:lookup-localization-list($node, $lang, $name)"/>
    </xsl:when>
    <xsl:when test="exists(fp:lookup-localization-list($node, $default-language, $name))">
      <xsl:if test="f:is-true($warn-about-missing-localizations)">
        <xsl:message expand-text="yes"
        >No localization list for {$name} in {$lang}, using {$default-language}</xsl:message>
      </xsl:if>
      <xsl:sequence select="fp:lookup-localization-list($node, $default-language, $name)"/>
    </xsl:when>
    <xsl:when test="exists(fp:lookup-localization-list($node, 'en', $name))">
      <xsl:if test="f:is-true($warn-about-missing-localizations)">
        <xsl:message expand-text="yes"
        >No localization list for {$name}in {$lang}, using en</xsl:message>
      </xsl:if>
      <xsl:sequence select="fp:lookup-localization-list($node, 'en', $name)"/>
    </xsl:when>
    <xsl:otherwise>
      <xsl:if test="f:is-true($warn-about-missing-localizations)">
        <xsl:message expand-text="yes"
        >No localization list for {$name} in {$lang}, using "MISSING"</xsl:message>
      </xsl:if>
      <lt:text>MISSING</lt:text>
    </xsl:otherwise>
  </xsl:choose>
</xsl:function>

<xsl:function name="fp:lookup-localization-list" as="element(l:list)?" cache="yes">
  <xsl:param name="node" as="element()"/>
  <xsl:param name="lang" as="xs:string"/>
  <xsl:param name="name" as="xs:string"/>

  <xsl:variable name="l10n" select="fp:localization($lang)"/>

  <xsl:choose>
    <xsl:when test="$l10n/l:list[@name=$name]">
      <xsl:sequence select="$l10n/l:list[@name=$name]"/>
    </xsl:when>
    <xsl:when test="$l10n/l:list[@name='_default']">
      <xsl:sequence select="$l10n/l:list[@name='_default']"/>
    </xsl:when>
    <xsl:otherwise>
      <xsl:sequence select="()"/>
    </xsl:otherwise>
  </xsl:choose>
</xsl:function>

<!-- ============================================================ -->

<xsl:mode name="mp:merge-custom" on-no-match="shallow-copy"/>

<xsl:template match="l:l10n" mode="mp:merge-custom">
  <xsl:param name="custom" as="element(l:l10n)" tunnel="yes"/>

  <xsl:variable name="this" select="."/>
  <xsl:copy>
    <xsl:copy-of select="@*"/>
    <xsl:apply-templates mode="mp:merge-custom"/>

    <xsl:for-each select="$custom/l:group">
      <xsl:variable name="name" select="string(@name)"/>
      <xsl:if test="empty($this/l:group[@name = $name])">
        <xsl:message use-when="'localization' = $v:debug"
                     select="'Add localization group: ' || $name"/>
        <xsl:sequence select="."/>
      </xsl:if>
    </xsl:for-each>

    <xsl:for-each select="$custom/l:properties">
      <xsl:variable name="name" select="string(@name)"/>
      <xsl:if test="empty($this/l:properties[@name = $name])">
        <xsl:message use-when="'localization' = $v:debug"
                     select="'Add localization properties: ' || $name"/>
        <xsl:sequence select="."/>
      </xsl:if>
    </xsl:for-each>

    <xsl:for-each select="$custom/l:list">
      <xsl:variable name="name" select="string(@name)"/>
      <xsl:if test="empty($this/l:list[@name = $name])">
        <xsl:message use-when="'localization' = $v:debug"
                     select="'Add localization list: ' || $name"/>
        <xsl:sequence select="."/>
      </xsl:if>
    </xsl:for-each>
  </xsl:copy>
</xsl:template>

<xsl:template match="l:gentext" mode="mp:merge-custom">
  <xsl:param name="custom" as="element(l:l10n)" tunnel="yes"/>

  <xsl:variable name="this" select="."/>
  <xsl:copy>
    <xsl:copy-of select="@*"/>
    <xsl:for-each select="$custom/l:gentext/l:token">
      <xsl:variable name="key" select="string(@key)"/>
      <xsl:if test="empty($this/l:token[@key = $key])">
        <xsl:message use-when="'localization' = $v:debug"
                     select="'Add localization token: ' || $key"/>
        <xsl:sequence select="."/>
      </xsl:if>
    </xsl:for-each>
    <xsl:apply-templates mode="mp:merge-custom"/>
  </xsl:copy>
</xsl:template>

<xsl:template match="l:gentext/l:token" mode="mp:merge-custom">
  <xsl:param name="custom" as="element(l:l10n)" tunnel="yes"/>

  <xsl:variable name="key" select="string(@key)"/>
  <xsl:variable name="override"
                select="$custom/l:gentext/l:token[@key=$key]"/>

  <xsl:choose>
    <xsl:when test="exists($override)">
      <xsl:message use-when="'localization' = $v:debug"
                   select="'Override localization token: ' || $key"/>
      <xsl:sequence select="$override"/>
    </xsl:when>
    <xsl:otherwise>
      <xsl:copy>
        <xsl:copy-of select="@*"/>
        <xsl:apply-templates mode="mp:merge-custom"/>
      </xsl:copy>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

<xsl:template match="l:properties" mode="mp:merge-custom">
  <xsl:param name="custom" as="element(l:l10n)" tunnel="yes"/>

  <xsl:variable name="this" select="."/>
  <xsl:copy>
    <xsl:copy-of select="@*"/>
    <xsl:for-each select="$custom/l:properties[@name = $this/@name]/l:property">
      <xsl:variable name="name" select="string(@name)"/>
      <xsl:if test="empty($this/l:property[@name = $name])">
        <xsl:message use-when="'localization' = $v:debug"
                     select="'Add localization property: ' || $this/@name || '/' || $name"/>
        <xsl:sequence select="."/>
      </xsl:if>
    </xsl:for-each>
    <xsl:apply-templates mode="mp:merge-custom"/>
  </xsl:copy>
</xsl:template>

<xsl:template match="l:properties/l:property" mode="mp:merge-custom">
  <xsl:param name="custom" as="element(l:l10n)" tunnel="yes"/>

  <xsl:variable name="pname" select="string(../@name)"/>
  <xsl:variable name="name" select="string(@name)"/>
  <xsl:variable name="override"
                select="$custom/l:properties[@name=$pname]/l:property[@name=$name]"/>

  <xsl:choose>
    <xsl:when test="exists($override)">
      <xsl:message use-when="'localization' = $v:debug"
                   select="'Override localization property: ' || $pname || '/' || $name"/>
      <xsl:sequence select="$override"/>
    </xsl:when>
    <xsl:otherwise>
      <xsl:copy>
        <xsl:copy-of select="@*"/>
        <xsl:apply-templates mode="mp:merge-custom"/>
      </xsl:copy>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

<xsl:template match="l:group" mode="mp:merge-custom">
  <xsl:param name="custom" as="element(l:l10n)" tunnel="yes"/>

  <xsl:variable name="this" select="."/>
  <xsl:copy>
    <xsl:copy-of select="@*"/>
    <xsl:for-each select="$custom/l:group[@name = $this/@name]/l:template">
      <xsl:variable name="key" select="string(@key)"/>
      <xsl:if test="empty($this/l:template[@key = $key])">
        <xsl:message use-when="'localization' = $v:debug"
                     select="'Add localization template: ' || $this/@name || '/' || $key"/>
        <xsl:sequence select="."/>
      </xsl:if>
    </xsl:for-each>
    <xsl:apply-templates mode="mp:merge-custom"/>
  </xsl:copy>
</xsl:template>

<xsl:template match="l:group/l:template" mode="mp:merge-custom">
  <xsl:param name="custom" as="element(l:l10n)" tunnel="yes"/>

  <xsl:variable name="pname" select="string(../@name)"/>
  <xsl:variable name="key" select="string(@key)"/>
  <xsl:variable name="override"
                select="$custom/l:group[@name=$pname]/l:template[@key=$key]"/>

  <xsl:choose>
    <xsl:when test="exists($override)">
      <xsl:message use-when="'localization' = $v:debug"
                   select="'Override localization template: ' || $pname || '/' || $key"/>
      <xsl:sequence select="$override"/>
    </xsl:when>
    <xsl:otherwise>
      <xsl:copy>
        <xsl:copy-of select="@*"/>
        <xsl:apply-templates mode="mp:merge-custom"/>
      </xsl:copy>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

<xsl:template match="l:l10n/l:list" mode="mp:merge-custom">
  <xsl:param name="custom" as="element(l:l10n)" tunnel="yes"/>

  <xsl:variable name="name" select="string(@name)"/>
  <xsl:variable name="override"
                select="$custom/l:list[@name=$name]"/>

  <xsl:choose>
    <xsl:when test="exists($override)">
      <xsl:message use-when="'localization' = $v:debug"
                   select="'Override localization list: ' || $name"/>
      <xsl:sequence select="$override"/>
    </xsl:when>
    <xsl:otherwise>
      <xsl:copy>
        <xsl:copy-of select="@*"/>
        <xsl:apply-templates mode="mp:merge-custom"/>
      </xsl:copy>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

<xsl:template match="l:letters/l:l[exists(node())]" mode="mp:merge-custom">
  <xsl:param name="custom" as="element(l:l10n)" tunnel="yes"/>

  <xsl:variable name="symbol" select="string(.)"/>
  <xsl:variable name="override"
                select="$custom/l:letters/l:l[string(.) = $symbol]"/>

  <xsl:choose>
    <xsl:when test="exists($override)">
      <xsl:message use-when="'localization' = $v:debug"
                   select="'Override localization symbol: ' || $symbol"/>
      <xsl:sequence select="$override"/>
    </xsl:when>
    <xsl:otherwise>
      <xsl:copy>
        <xsl:copy-of select="@*"/>
        <xsl:apply-templates mode="mp:merge-custom"/>
      </xsl:copy>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

<xsl:template match="*" mode="mp:merge-custom">
  <xsl:copy>
    <xsl:copy-of select="@*"/>
    <xsl:apply-templates mode="mp:merge-custom"/>
  </xsl:copy>
</xsl:template>

<!-- ============================================================ -->

<xsl:template match="*" mode="m:gentext">
  <xsl:param name="group" as="xs:string"/>
  <xsl:param name="content" as="item()*" select="()"/>

  <xsl:variable name="template"
                select="fp:localization-template(., $group)"/>

  <!--
  <xsl:message select="'GENTEXT:', local-name(.), $group, exists($content), $template"/>>
  -->

  <xsl:apply-templates select="$template" mode="mp:localization">
    <xsl:with-param name="context" select="."/>
    <xsl:with-param name="content" select="$content"/>
    <xsl:with-param name="group" select="$group"/>
  </xsl:apply-templates>
</xsl:template>

<xsl:template match="db:question|db:answer" mode="m:gentext">
  <xsl:param name="group" as="xs:string"/>
  <xsl:param name="content" as="item()*" select="()"/>

  <!-- This is a weird special case because the default label
       ends in a colon. If we're looking for a label separator,
       and we're using the 'qanda' label style, and the label
       text ends with punctuation, just output a space.
       Note: there are some extra conditionals in here to
       avoid doing extra work if the conditions don't apply. -->

  <xsl:variable name="label" as="xs:string?"
                select="if ($group = 'label-separator')
                        then ancestor::db:qandaset[@defaultlabel][1]/@defaultlabel/string()
                        else ()"/>
  <xsl:variable name="label" as="xs:string"
                select="if ($label)
                        then $label
                        else $qandaset-default-label"/>
  <xsl:variable name="text"
                select="if ($group = 'label-separator' and $label = 'qanda')
                        then f:l10n-token(., local-name(.))
                        else string(db:label)"/>

  <xsl:choose>
    <xsl:when test="$group = 'label-separator' and exists($text)
                    and matches($text, '\p{Po}$')">
      <xsl:sequence select="' '"/>
    </xsl:when>
    <xsl:otherwise>
      <xsl:next-match>
        <xsl:with-param name="group" select="$group"/>
        <xsl:with-param name="content" select="$content"/>
      </xsl:next-match>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

</xsl:stylesheet>

l10n.xsl

12 templates, 3 functions

Instructions
Template match ≅ l:template
Mode: mp:localization
Matches: l:template
Template match ≅ lt:text
Mode: mp:localization
Matches: lt:text
Template match ≅ lt:separator
Mode: mp:localization
Matches: lt:separator
Template match ≅ lt:percent
Mode: mp:localization
Matches: lt:percent
Template match ≅ lt:label
Mode: mp:localization
Matches: lt:label
Template match ≅ lt:content
Mode: mp:localization
Matches: lt:content
Template match ≅ lt:ref
Mode: mp:localization
Matches: lt:ref
Template match ≅ lt:token
Mode: mp:localization
Matches: lt:token
Function f:l10n-token#2($context as element(), $key as xs:string) as item()*
Function f:l10n-token#3($context as element(), $lang as xs:string, $key as xs:string) as item()*
Function fp:l10n-token($lang as xs:string, $key as xs:string) as item()*
Template match ≅ h:*
Mode: mp:localization
Matches: h:*
Template match ≅ lt:*
Mode: mp:localization
Matches: lt:*
Template match ≅ *
Mode: m:gentext-list
Matches: *
Template tp:process-list match ≅
Used by: template
Mode: m:docbook
Source code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:db="http://docbook.org/ns/docbook"
                xmlns:f="http://docbook.org/ns/docbook/functions"
                xmlns:fp="http://docbook.org/ns/docbook/functions/private"
                xmlns:h="http://www.w3.org/1999/xhtml"
                xmlns:l="http://docbook.org/ns/docbook/l10n"
                xmlns:lt="http://docbook.org/ns/docbook/l10n/templates"
                xmlns:m="http://docbook.org/ns/docbook/modes"
                xmlns:map="http://www.w3.org/2005/xpath-functions/map"
                xmlns:mp="http://docbook.org/ns/docbook/modes/private"
                xmlns:tp="http://docbook.org/ns/docbook/templates/private"
                xmlns:v="http://docbook.org/ns/docbook/variables"
                xmlns:vp="http://docbook.org/ns/docbook/variables/private"
                xmlns:xs="http://www.w3.org/2001/XMLSchema"
                xmlns="http://www.w3.org/1999/xhtml"
                default-mode="m:docbook"
                exclude-result-prefixes="#all"
                version="3.0">

<xsl:template match="l:template" mode="mp:localization">
  <xsl:param name="context" as="element()"/>
  <xsl:param name="label" as="item()*"/>
  <xsl:param name="content" as="item()*"/>

  <xsl:apply-templates select="*" mode="mp:localization">
    <xsl:with-param name="lang" select="f:l10n-language($context)" tunnel="yes"/>
    <xsl:with-param name="context" select="$context" tunnel="yes"/>
    <xsl:with-param name="label" select="$label" tunnel="yes"/>
    <xsl:with-param name="content" select="$content" tunnel="yes"/>
  </xsl:apply-templates>
</xsl:template>

<xsl:template match="lt:text" mode="mp:localization">
  <xsl:sequence select="node()"/>
</xsl:template>

<xsl:template match="lt:separator" mode="mp:localization">
  <xsl:param name="context" as="element()" tunnel="yes"/>

  <span class="sep">
    <xsl:apply-templates select="$context" mode="m:gentext">
      <xsl:with-param name="group" select="'label-separator'"/>
    </xsl:apply-templates>
  </span>
</xsl:template>

<xsl:template match="lt:percent" mode="mp:localization">
  <xsl:text>%</xsl:text>
</xsl:template>

<xsl:template match="lt:label" mode="mp:localization">
  <xsl:param name="label" as="item()*" tunnel="yes"/>
  <span class="label">
    <xsl:sequence select="$label"/>
  </span>
</xsl:template>

<xsl:template match="lt:content" mode="mp:localization">
  <xsl:param name="content" as="item()*" tunnel="yes"/>

  <xsl:sequence select="$content"/>
</xsl:template>

<xsl:template match="lt:ref" mode="mp:localization">
  <xsl:param name="context" as="element()" tunnel="yes"/>
  <xsl:variable name="ref" as="element()?">
    <xsl:evaluate xpath="@select" context-item="$context"/>
  </xsl:variable>

  <xsl:apply-templates select="$ref"
                       mode="m:crossref">
    <xsl:with-param name="context" select="@context"/>
  </xsl:apply-templates>
</xsl:template>

<xsl:template match="lt:token" mode="mp:localization">
  <xsl:param name="context" as="element()" tunnel="yes"/>
  <xsl:param name="lang" tunnel="yes"/>
  <xsl:sequence select="f:l10n-token($context, $lang, @key)"/>
</xsl:template>

<xsl:function name="f:l10n-token" as="item()*" cache="yes">
  <xsl:param name="context" as="element()"/>
  <xsl:param name="key" as="xs:string"/>

  <xsl:variable name="lang" select="f:l10n-language($context)"/>
  <xsl:sequence select="fp:l10n-token($lang, $key)"/>
</xsl:function>

<xsl:function name="f:l10n-token" as="item()*" cache="yes">
  <xsl:param name="context" as="element()"/>
  <xsl:param name="lang" as="xs:string"/>
  <xsl:param name="key" as="xs:string"/>
  <xsl:sequence select="fp:l10n-token($lang, $key)"/>
</xsl:function>

<xsl:function name="fp:l10n-token" as="item()*" cache="yes">
  <xsl:param name="lang" as="xs:string"/>
  <xsl:param name="key" as="xs:string"/>

  <xsl:variable name="l10n" select="fp:localization($lang)"/>
  <xsl:choose>
    <xsl:when test="exists($l10n/l:gentext/l:token[@key=$key])">
      <xsl:sequence select="($l10n/l:gentext/l:token[@key=$key])[1]/node()"/>
    </xsl:when>
    <xsl:when test="$lang != 'en'">
      <xsl:variable name="l10n" select="fp:localization('en')"/>
      <xsl:choose>
        <xsl:when test="exists($l10n/l:gentext/l:token[@key=$key])">
          <xsl:sequence select="($l10n/l:gentext/l:token[@key=$key])[1]/node()"/>
        </xsl:when>
        <xsl:otherwise>
          <xsl:message select="'No gentext for ' || $key || ' in ' || $lang || ' or en'"/>
          <xsl:text>MISSING</xsl:text>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:when>
    <xsl:otherwise>
      <xsl:message select="'No gentext for ' || $key || ' in ' || $lang"/>
      <xsl:text>MISSING</xsl:text>
    </xsl:otherwise>
  </xsl:choose>
</xsl:function>

<xsl:template match="h:*" mode="mp:localization">
  <xsl:element name="{local-name(.)}" namespace="http://www.w3.org/1999/xhtml">
    <xsl:copy-of select="@*"/>
    <xsl:apply-templates mode="mp:localization"/>
  </xsl:element>
</xsl:template>

<xsl:template match="lt:*" mode="mp:localization">
  <xsl:message terminate="yes"
               select="'Unexpected localization element: ' || node-name(.)"/>
</xsl:template>

<!-- ============================================================ -->

<xsl:template match="*" mode="m:gentext-list">
  <xsl:param name="list" as="element()+"/>
  <xsl:param name="name" select="local-name(.)"/>

  <xsl:variable name="template"
                select="fp:localization-list(., $name)"/>

  <xsl:variable name="items" as="element(l:items)?">
    <xsl:iterate select="$template/l:items">
      <xsl:choose>
        <xsl:when test="count(.//lt:content) = count($list)">
          <xsl:break select="."/>
        </xsl:when>
        <xsl:when test="count(.//lt:content) le count($list) and .//l:repeat">
          <xsl:break select="."/>
        </xsl:when>
        <xsl:otherwise>
          <xsl:next-iteration/>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:iterate>
  </xsl:variable>

  <xsl:if test="empty($items)">
    <xsl:message expand-text="yes">
      <xsl:text>Failed to select items for {count($list)} element list </xsl:text>
      <xsl:text>in {local-name(.)}.</xsl:text>
    </xsl:message>
  </xsl:if>

  <xsl:choose>
    <xsl:when test="empty($items/l:repeat)">
      <xsl:call-template name="tp:process-list">
        <xsl:with-param name="context" select="."/>
        <xsl:with-param name="lang" select="f:l10n-language(.)"/>
        <xsl:with-param name="list" select="$list"/>
        <xsl:with-param name="template" select="$items/*"/>
      </xsl:call-template>
    </xsl:when>
    <xsl:otherwise>
      <!-- Assume the items contains (lt:content|lt:text)*, lt:repeat, (lt:content|lt:text)*
           where lt:repeat contains (lt:content|lt:text)* -->
      <xsl:variable name="before" select="$items/l:repeat/preceding-sibling::*"/>
      <xsl:variable name="after" select="$items/l:repeat/following-sibling::*"/>

      <xsl:variable name="bc" select="count($before/ancestor-or-self::lt:content)"/>
      <xsl:variable name="ac" select="count($after/ancestor-or-self::lt:content)"/>

      <xsl:variable name="rt" select="count($items/l:repeat//lt:content)"/>

      <xsl:variable name="ric" select="count($list) - ($ac + $bc)"/>
      <xsl:variable name="rc"
                    select="($ric + $rt - 1) idiv $rt"/>

      <xsl:variable name="expanded-list" as="element()+">
        <xsl:sequence select="$before"/>
        <xsl:for-each select="1 to $rc">
          <xsl:sequence select="$items/l:repeat/*"/>
        </xsl:for-each>
        <xsl:sequence select="$after"/>
      </xsl:variable>

      <xsl:call-template name="tp:process-list">
        <xsl:with-param name="context" select="."/>
        <xsl:with-param name="lang" select="f:l10n-language(.)"/>
        <xsl:with-param name="list" select="$list"/>
        <xsl:with-param name="template" select="$expanded-list"/>
      </xsl:call-template>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

<xsl:template name="tp:process-list">
  <xsl:param name="context" as="element()"/>
  <xsl:param name="lang" as="xs:string"/>
  <xsl:param name="list" as="element()*"/>
  <xsl:param name="template" as="element()*"/>

  <xsl:iterate select="$template">
    <xsl:param name="list" select="$list"/>

    <xsl:choose>
      <xsl:when test="self::lt:text">
        <xsl:sequence select="node()"/>
        <xsl:next-iteration>
          <xsl:with-param name="list" select="$list"/>
        </xsl:next-iteration>
      </xsl:when>
      <xsl:when test="self::lt:content">
        <xsl:sequence select="$list[1]"/>
        <xsl:next-iteration>
          <xsl:with-param name="list" select="$list[position() gt 1]"/>
        </xsl:next-iteration>
      </xsl:when>
      <xsl:when test="self::lt:token">
        <xsl:sequence select="f:l10n-token($context, $lang, @key)"/>
        <xsl:next-iteration>
          <xsl:with-param name="list" select="$list"/>
        </xsl:next-iteration>
      </xsl:when>
      <xsl:otherwise>
        <xsl:message select="'Unexpected element in list template:', node-name(.)"/>
        <xsl:next-iteration>
          <xsl:with-param name="list" select="$list"/>
        </xsl:next-iteration>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:iterate>
</xsl:template>

</xsl:stylesheet>

functions.xsl

41 functions (6 unused, 7 used only in one other module), 3 variables

Instructions
Variable $vp:translate-suppress-elements
Function f:translate-attribute($node as element()) as xs:boolean?
Function f:attributes#2($node as element(), $attributes as attribute()*) as attribute()*
Function f:attributes#4($node as element(), $attributes as attribute()*, $extra-classes as xs:string*, $exclude-classes as xs:string*) as attribute()*
Function f:orderedlist-startingnumber($list as element(db:orderedlist)) as xs:integer
Function f:gentext-letters($node as element()) as element(l:letters)
Unused
Function f:gentext-letters-for-language($node as element()) as element(l:letters)
Function fp:properties($context as element(), $properties as array(map(*))) as map(*)
Function f:date-format($context as element()) as xs:string
Function fp:replace-element#3($lines as array(*), $elemno as xs:integer, $new-elem as item()*) as array(*)
Used by: fp:inject()
Function fp:replace-element#5($array as array(*), $elemno as xs:integer, $count as xs:integer, $new-elem as item()*, $newarray as array(*)) as array(*)
Function f:target($id as xs:string, $context as node()) as element()*
Variable $vp:gidmap
Function f:generate-id#2($node as element(), $use-xml-id as xs:boolean) as xs:string
Function f:unique-id($node as element()) as xs:string
Unused
Function fp:pi-from-list($pis as processing-instruction()*, $property as xs:string, $default as xs:string*) as xs:string*
Function fp:css-properties($context as element()?) as attribute()?
Function fp:pi-attributes($pis as processing-instruction()*, $pimap as map(*)) as map(*)?
Variable $vp:pi-match
Function fp:pi-pi-attributes($pimap as map(*), $text as xs:string) as map(*)
Function f:spaces($length as item()*) as xs:string?
Function fp:lookup-string($context as element(), $lookup as element(), $table-name as xs:string) as node()*
Unused
Function fp:separator($node as element(), $key as xs:string) as node()*
Function f:label-separator($node as element()) as node()*
Unused
Function fp:parse-key-value-pairs#1($strings as xs:string*) as map(xs:string,xs:string)
Function fp:parse-key-value-pairs#2($strings as xs:string*, $map as map(xs:string,xs:string)) as map(xs:string,xs:string)
Function f:refsection($node as element()) as xs:boolean
Function f:section($node as element()) as xs:boolean
Unused
Function f:section-depth($node as element()?) as xs:integer
Function f:step-number($node as element(db:step)) as xs:integer+
Function f:step-numeration($node as element(db:step)) as xs:string
Function f:orderedlist-item-number($node as element(db:listitem)) as xs:integer+
Function f:orderedlist-item-numeration($node as element(db:listitem)) as xs:string
Function f:tokenize-on-char($string as xs:string, $char as xs:string) as xs:string*
Used by: template
Function f:relative-path($base as xs:string, $path as xs:string) as xs:string
Used by: template
Source code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:array="http://www.w3.org/2005/xpath-functions/array"
                xmlns:db="http://docbook.org/ns/docbook"
                xmlns:f="http://docbook.org/ns/docbook/functions"
                xmlns:fp="http://docbook.org/ns/docbook/functions/private"
                xmlns:l="http://docbook.org/ns/docbook/l10n"
                xmlns:m="http://docbook.org/ns/docbook/modes"
                xmlns:map="http://www.w3.org/2005/xpath-functions/map"
                xmlns:mp="http://docbook.org/ns/docbook/modes/private"
                xmlns:v="http://docbook.org/ns/docbook/variables"
                xmlns:vp="http://docbook.org/ns/docbook/variables/private"
                xmlns:xs="http://www.w3.org/2001/XMLSchema"
                xmlns="http://www.w3.org/1999/xhtml"
                default-mode="m:docbook"
                exclude-result-prefixes="array db f fp l m map mp v vp xs"
                version="3.0">

<xsl:key name="id" match="*" use="@xml:id"/>
<xsl:key name="genid" match="*" use="generate-id(.)"/>

<xsl:variable name="vp:translate-suppress-elements"
              select="tokenize($translate-suppress-elements, '\s+')"/>

<xsl:function name="f:translate-attribute" as="xs:boolean?">
  <xsl:param name="node" as="element()"/>
  <xsl:if test="local-name($node) = $vp:translate-suppress-elements">
    <xsl:sequence select="false()"/>
  </xsl:if>
</xsl:function>

<xsl:function name="f:attributes" as="attribute()*">
  <xsl:param name="node" as="element()"/>
  <xsl:param name="attributes" as="attribute()*"/>
  <xsl:sequence select="f:attributes($node, $attributes, local-name($node), ())"/>
</xsl:function>

<xsl:function name="f:attributes" as="attribute()*">
  <xsl:param name="node" as="element()"/>
  <xsl:param name="attributes" as="attribute()*"/>
  <xsl:param name="extra-classes" as="xs:string*"/>
  <xsl:param name="exclude-classes" as="xs:string*"/>

  <!--
  <xsl:message>
    <xsl:text>f:attributes(</xsl:text>
    <xsl:value-of select="node-name($node)"/>
    <xsl:text>,</xsl:text>
    <xsl:sequence select="$attributes"/>
    <xsl:text>,</xsl:text>
    <xsl:sequence select="$extra-classes"/>
    <xsl:text>,</xsl:text>
    <xsl:sequence select="$exclude-classes"/>
    <xsl:text>)</xsl:text>
  </xsl:message>
  -->

  <!-- combine duplicates -->
  <xsl:variable name="names"
                select="distinct-values($attributes/node-name())"/>
  <xsl:for-each select="$names">
    <xsl:variable name="name" select="."/>
    <xsl:variable name="values" as="xs:string*"
                  select="$attributes[node-name()=$name]/string()"/>
    <xsl:if test="exists($values)">
      <xsl:attribute name="{$name}"
                     select="string-join($values, ' ')"/>
    </xsl:if>
  </xsl:for-each>

  <!-- if there isn't a class attribute, manufacture one -->
  <xsl:if test="not(QName('', 'class') = $attributes/node-name())">
    <xsl:variable name="roles"
                  select="(tokenize(normalize-space(string-join($extra-classes, ' '))),
                           tokenize(normalize-space($node/@role)),
                           if ($node/@revisionflag)
                           then 'rev'||$node/@revisionflag
                           else ())"/>
    <xsl:variable name="exclude" 
                  select="tokenize(normalize-space(string-join($exclude-classes, ' ')))"/>
    <!-- sort them and make them unique -->
    <xsl:variable name="classes" as="xs:string*">
      <xsl:for-each select="distinct-values($roles)">
        <xsl:sort select="."/>
        <xsl:if test="not(. = $exclude)">
          <xsl:sequence select="."/>
        </xsl:if>
      </xsl:for-each>
    </xsl:variable>

    <xsl:if test="exists($classes)">
      <xsl:attribute name="class" select="string-join($classes, ' ')"/>
    </xsl:if>
  </xsl:if>

  <xsl:variable name="translate" select="f:translate-attribute($node)"/>
  <xsl:if test="exists($translate)">
    <xsl:attribute name="translate" select="if ($translate) then 'yes' else 'no'"/>
  </xsl:if>
</xsl:function>

<xsl:function name="f:is-true" as="xs:boolean" visibility="public">
  <xsl:param name="value"/>

  <xsl:choose>
    <xsl:when test="empty($value)">
      <xsl:value-of select="false()"/>
    </xsl:when>
    <xsl:when test="$value castable as xs:boolean">
      <xsl:value-of select="xs:boolean($value)"/>
    </xsl:when>
    <xsl:when test="$value castable as xs:integer">
      <xsl:value-of select="xs:integer($value) != 0"/>
    </xsl:when>
    <xsl:when test="string($value) = ('true', 'yes')">
      <xsl:value-of select="true()"/>
    </xsl:when>
    <xsl:when test="string($value) = ('false', 'no')">
      <xsl:value-of select="false()"/>
    </xsl:when>
    <xsl:otherwise>
      <xsl:message expand-text="yes"
                   >Warning: interpreting ‘{$value}’ as true.</xsl:message>
      <xsl:value-of select="true()"/>
    </xsl:otherwise>
  </xsl:choose>
</xsl:function>

<xsl:function name="f:orderedlist-startingnumber" as="xs:integer">
  <xsl:param name="list" as="element(db:orderedlist)"/>

  <xsl:choose>
    <xsl:when test="not($list/@continuation = 'continues')">
      <xsl:sequence select="1"/>
    </xsl:when>
    <xsl:when test="empty($list/preceding::db:orderedlist)">
      <xsl:message>
        <xsl:text>Warning: orderedlist continuation=continues, </xsl:text>
        <xsl:text>but no preceding list</xsl:text>
      </xsl:message>
      <xsl:sequence select="1"/>
    </xsl:when>
    <xsl:otherwise>
      <!-- Hat tip to Gerrit for the fix here -->
      <xsl:variable name="plist"
                    select="$list/outermost(preceding::db:orderedlist)[last()]"/>

      <xsl:sequence select="f:orderedlist-startingnumber($plist)
                            + count($plist/db:listitem)"/>
    </xsl:otherwise>
  </xsl:choose>
</xsl:function>

<xsl:function name="f:l10n-language" as="xs:string" cache="yes">
  <xsl:param name="target" as="element()"/>

  <xsl:variable name="nearest-lang"
                select="$target/ancestor-or-self::*[@xml:lang][1]/@xml:lang"/>

  <xsl:variable name="mc-language" as="xs:string"
                select="if (exists($gentext-language))
                        then $gentext-language
                        else if (exists($nearest-lang) and $nearest-lang = '')
                             then $default-language
                             else ($nearest-lang, $default-language)[1]"/>

  <xsl:variable name="language" select="lower-case($mc-language)"/>

  <xsl:variable name="adjusted-language"
                select="if (contains($language, '-'))
                        then substring-before($language, '-')
                             || '_' || substring-after($language, '-')
                        else $language"/>

  <xsl:choose>
    <xsl:when test="doc-available(
                      resolve-uri($adjusted-language||'.xml', $v:localization-base-uri))">
      <xsl:sequence select="$adjusted-language"/>
    </xsl:when>
    <!-- try just the lang code without country -->
    <xsl:when test="doc-available(
                      resolve-uri(
                        substring-before($adjusted-language, '_')||'.xml', $v:localization-base-uri))">
      <xsl:sequence select="substring-before($adjusted-language,'_')"/>
    </xsl:when>
    <!-- or use the default -->
    <xsl:otherwise>
      <xsl:message>
        <xsl:text>No localization exists for "</xsl:text>
        <xsl:sequence select="$adjusted-language"/>
        <xsl:text>" or "</xsl:text>
        <xsl:sequence select="substring-before($adjusted-language,'_')"/>
        <xsl:text>". Using default "</xsl:text>
        <xsl:sequence select="$default-language"/>
        <xsl:text>".</xsl:text>
      </xsl:message>
      <xsl:sequence select="$default-language"/>
    </xsl:otherwise>
  </xsl:choose>
</xsl:function>

<xsl:function name="f:gentext-letters" as="element(l:letters)">
  <xsl:param name="node" as="element()"/>
  <xsl:sequence select="f:gentext-letters-for-language($node)"/>
</xsl:function>

<xsl:function name="f:gentext-letters-for-language" as="element(l:letters)">
  <xsl:param name="node" as="element()"/>

  <xsl:variable name="lang" select="f:l10n-language($node)"/>
  <xsl:variable name="l10n" select="fp:localization($lang)"/>

  <xsl:variable name="letters"
                select="$l10n/l:letters"/>

  <xsl:if test="empty($letters)">
    <xsl:message select="'No letters for', $lang"/>
  </xsl:if>

  <xsl:if test="count($letters) gt 1">
    <xsl:message
        select="'Multiple letters for localization:', $lang"/>
  </xsl:if>

  <xsl:sequence select="$letters[1]"/>
</xsl:function>

<xsl:function name="fp:properties" as="map(*)">
  <xsl:param name="context" as="element()"/>
  <xsl:param name="properties" as="array(map(*))"/>

  <xsl:variable name="props" as="map(*)*">
    <xsl:for-each select="1 to array:size($properties)">
      <xsl:variable name="map" select="array:get($properties, .)"/>
      <xsl:variable name="nodes" as="node()*">
        <xsl:evaluate context-item="$context" xpath="$map?xpath"/>
      </xsl:variable>
      <xsl:if test="exists($nodes)">
        <xsl:sequence select="$map"/>
      </xsl:if>
    </xsl:for-each>
  </xsl:variable>

  <xsl:choose>
    <xsl:when test="empty($props)">
      <xsl:message use-when="'properties' = $v:debug"
          select="'No properties for ' || local-name($context)"/>
      <xsl:sequence select="map { }"/>
    </xsl:when>
    <xsl:otherwise>
      <xsl:sequence select="$props[1]"/>
    </xsl:otherwise>
  </xsl:choose>
</xsl:function>

<xsl:function name="f:date-format" as="xs:string">
  <xsl:param name="context" as="element()"/>

  <xsl:variable name="format"
                select="f:pi($context, 'date-format')"/>

  <xsl:choose>
    <xsl:when test="$context/*">
      <xsl:sequence select="'apply-templates'"/>
    </xsl:when>
    <xsl:when test="string($context) castable as xs:dateTime">
      <xsl:choose>
        <xsl:when test="$format">
          <xsl:sequence select="$format"/>
        </xsl:when>
        <xsl:otherwise>
          <xsl:sequence select="$date-dateTime-format"/>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:when>
    <xsl:when test="string($context) castable as xs:date">
      <xsl:choose>
        <xsl:when test="$format">
          <xsl:sequence select="$format"/>
        </xsl:when>
        <xsl:otherwise>
          <xsl:sequence select="$date-date-format"/>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:when>
    <xsl:otherwise>
      <xsl:sequence select="'apply-templates'"/>
    </xsl:otherwise>
  </xsl:choose>
</xsl:function>

<!-- ============================================================ -->

<xsl:function name="fp:replace-element" as="array(*)">
  <xsl:param name="lines" as="array(*)"/>
  <xsl:param name="elemno" as="xs:integer"/>
  <xsl:param name="new-elem" as="item()*"/>
  <xsl:sequence
      select="fp:replace-element($lines, $elemno, 1, $new-elem, [])"/>
</xsl:function>

<xsl:function name="fp:replace-element" as="array(*)">
  <!-- See https://saxonica.plan.io/issues/4500 -->
  <!-- reimplement this with array:join when that but is fixed -->
  <xsl:param name="array" as="array(*)"/>
  <xsl:param name="elemno" as="xs:integer"/>
  <xsl:param name="count" as="xs:integer"/>
  <xsl:param name="new-elem" as="item()*"/>
  <xsl:param name="newarray" as="array(*)"/>

  <xsl:choose>
    <xsl:when test="$count gt array:size($array)">
      <xsl:sequence select="$newarray"/>
    </xsl:when>
    <xsl:when test="$count = $elemno">
      <xsl:sequence
          select="fp:replace-element($array, $elemno, $count+1, $new-elem,
                                     array:append($newarray, $new-elem))"/>
    </xsl:when>
    <xsl:otherwise>
      <xsl:sequence
          select="fp:replace-element($array, $elemno, $count+1, $new-elem,
                                     array:append($newarray, $array($count)))"/>
    </xsl:otherwise>
  </xsl:choose>
</xsl:function>

<xsl:function name="f:target" as="element()*" cache="yes">
  <xsl:param name="id" as="xs:string"/>
  <xsl:param name="context" as="node()"/>
  <xsl:sequence select="key('id', $id, root($context))"/>
</xsl:function>

<xsl:function name="f:href" as="xs:string" cache="yes">
  <xsl:param name="context" as="node()"/>
  <xsl:param name="node" as="element()"/>
  <xsl:sequence select="'#' || f:generate-id($node)"/>
</xsl:function>

<xsl:variable name="vp:gidmap" select="map {
  'acknowledgements': 'ack',
  'appendix': 'ap',
  'book': 'bo',
  'chapter': 'ch',
  'colophon': 'co',
  'dedication': 'ded',
  'equation': 'eq',
  'example': 'ex',
  'figure': 'fig',
  'part': 'part',
  'preface': 'p',
  'procedure': 'proc',
  'refentry': 're',
  'reference': 'ref',
  'refsect1': 'rs1',
  'refsect2': 'rs2',
  'refsect3': 'rs3',
  'sect1': 's1_',
  'sect2': 's2_',
  'sect3': 's3_',
  'sect4': 's4_',
  'sect5': 's5_',
  'section': 's',
  'table': 'tab',
  'glossary': 'g',
  'glossdiv': 'gd',
  'glossentry': 'ge',
  'glossterm': 'gt',
  'bibliography': 'bi',
  'bibliodiv': 'bd'
  }"/>

<xsl:function name="f:generate-id" as="xs:string" cache="yes">
  <xsl:param name="node" as="element()"/>
  <xsl:sequence select="f:generate-id($node, true())"/>
</xsl:function>

<xsl:function name="f:generate-id" as="xs:string" cache="yes">
  <xsl:param name="node" as="element()"/>
  <xsl:param name="use-xml-id" as="xs:boolean"/>
  <xsl:choose>
    <xsl:when test="$use-xml-id and $node/@xml:id">
      <xsl:sequence select="$node/@xml:id/string()"/>
    </xsl:when>
    <xsl:when test="empty($node/parent::*)">
      <xsl:sequence select="$generated-id-root"/>
    </xsl:when>
    <xsl:otherwise>
      <xsl:variable name="aid" select="f:generate-id($node/parent::*, $use-xml-id)"/>
      <xsl:variable name="type" select="(map:get($vp:gidmap, local-name($node)),
                                         local-name($node))[1]"/>
      <xsl:variable name="prec"
                    select="$node/preceding-sibling::*[node-name(.)=node-name($node)]"/>
      <xsl:sequence
          select="$aid || $generated-id-sep || $type || string(count($prec)+1)"/>
    </xsl:otherwise>
  </xsl:choose>
</xsl:function>

<xsl:function name="f:id" as="xs:string" cache="yes">
  <xsl:param name="node" as="element()"/>
  <xsl:sequence select="if ($node/@xml:id)
                        then $node/@xml:id/string()
                        else f:generate-id($node)"/>
</xsl:function>

<xsl:function name="f:unique-id" as="xs:string" cache="yes">
  <xsl:param name="node" as="element()"/>
  <xsl:sequence select="f:generate-id($node, false())"/>
</xsl:function>

<xsl:function name="f:pi" as="xs:string?" visibility="public">
  <xsl:param name="context" as="node()?"/>
  <xsl:param name="property" as="xs:string"/>
  <xsl:sequence select="f:pi($context, $property, ())"/>
</xsl:function>

<xsl:function name="f:pi" as="xs:string*" visibility="public">
  <xsl:param name="context" as="node()?"/>
  <xsl:param name="property" as="xs:string"/>
  <xsl:param name="default" as="xs:string*"/>

  <xsl:choose>
    <xsl:when test="empty($context)">
      <xsl:sequence select="$default"/>
    </xsl:when>
    <xsl:otherwise>
      <xsl:sequence select="fp:pi-from-list(($context/processing-instruction('db'),
                                             root($context)/processing-instruction('db')),
                                            $property, $default)"/>
    </xsl:otherwise>
  </xsl:choose>
</xsl:function>

<xsl:function name="fp:pi-from-list" as="xs:string*">
  <xsl:param name="pis" as="processing-instruction()*"/>
  <xsl:param name="property" as="xs:string"/>
  <xsl:param name="default" as="xs:string*"/>

  <xsl:variable name="value"
                select="f:pi-attributes($pis)/@*[local-name(.) = $property]/string()"/>

  <xsl:sequence select="if (empty($value))
                        then $default
                        else $value"/>
</xsl:function>

<xsl:function name="fp:css-properties" as="attribute()?">
  <xsl:param name="context" as="element()?"/>

  <xsl:variable name="generic-attributes" as="map(*)">
    <xsl:map>
      <xsl:for-each select="$context/@css:*" xmlns:css="https://xsltng.docbook.org/ns/css">
        <xsl:map-entry key="local-name(.)" select="string(.)"/>
      </xsl:for-each>
    </xsl:map>
  </xsl:variable>

  <xsl:variable name="media-attributes" as="map(*)">
    <xsl:map>
      <xsl:for-each select="$context/@*">
        <xsl:if test="namespace-uri(.) = 'https://xsltng.docbook.org/ns/css#' || $output-media">
          <xsl:map-entry key="local-name(.)" select="string(.)"/>
        </xsl:if>
      </xsl:for-each>
    </xsl:map>
  </xsl:variable>

  <xsl:variable name="attributes" as="map(*)"
                select="map:merge(($generic-attributes, $media-attributes),
                                  map { 'duplicates': 'use-last' })"/>

  <xsl:if test="map:size($attributes) != 0">
    <xsl:iterate select="map:keys($attributes)">
      <xsl:param name="css" select="''"/>
      <xsl:on-completion>
        <xsl:attribute name="style" select="$css"/>
      </xsl:on-completion>
      <xsl:variable name="name" select="."/>
      <xsl:variable name="value" select="map:get($attributes, .)"/>
      <xsl:next-iteration>
        <xsl:with-param name="css" select="$css || $name || ':' || $value || ';'"/>
      </xsl:next-iteration>
    </xsl:iterate>
  </xsl:if>
</xsl:function>

<xsl:function name="f:pi-attributes" as="element()?">
  <xsl:param name="pis" as="processing-instruction()*"/>
  <xsl:variable name="attributes"
                select="fp:pi-attributes($pis, map { })"/>

  <xsl:element name="pis" namespace="">
    <xsl:for-each select="map:keys($attributes)">
      <xsl:attribute name="{.}" select="map:get($attributes, .)"/>
    </xsl:for-each>
  </xsl:element>
</xsl:function>

<xsl:function name="fp:pi-attributes" as="map(*)?">
  <xsl:param name="pis" as="processing-instruction()*"/>
  <xsl:param name="pimap" as="map(*)"/>

  <xsl:choose>
    <xsl:when test="empty($pis)">
      <xsl:sequence select="$pimap"/>
    </xsl:when>
    <xsl:otherwise>
      <xsl:variable name="map" select="fp:pi-pi-attributes($pimap,
                                          normalize-space($pis[1]))"/>
      <xsl:sequence select="fp:pi-attributes(subsequence($pis, 2), $map)"/>
    </xsl:otherwise>
  </xsl:choose>
</xsl:function>

<xsl:variable name="vp:pi-match"
              select="'^.*?(\c+)=[''&quot;](.*?)[''&quot;](.*)$'"/>
<xsl:function name="fp:pi-pi-attributes" as="map(*)">
  <xsl:param name="pimap" as="map(*)"/>
  <xsl:param name="text" as="xs:string"/>

  <xsl:choose>
    <xsl:when test="matches($text, $vp:pi-match)">
      <xsl:variable name="aname" select="replace($text, $vp:pi-match, '$1')"/>
      <xsl:variable name="avalue" select="replace($text, $vp:pi-match, '$2')"/>
      <xsl:variable name="rest" select="replace($text, $vp:pi-match, '$3')"/>
      <xsl:sequence select="fp:pi-pi-attributes(map:put($pimap, $aname, $avalue),
                                                $rest)"/>
    </xsl:when>
    <xsl:otherwise>
      <xsl:sequence select="$pimap"/>
    </xsl:otherwise>
  </xsl:choose>
</xsl:function>

<xsl:function name="f:spaces" as="xs:string?">
  <xsl:param name="length" as="item()*"/>

  <xsl:choose>
    <xsl:when test="empty($length)"/>
    <xsl:when test="count($length) gt 1">
      <xsl:sequence
          select="f:spaces(string-join($length ! string(.), ''))"/>
    </xsl:when>
    <xsl:when test="$length castable as xs:integer">
      <xsl:variable name="length" select="xs:integer($length)"/>
      <xsl:choose>
        <xsl:when test="$length lt 0"/>
        <xsl:when test="$length lt 10">
          <xsl:sequence select="substring('          ', 1, $length)"/>
        </xsl:when>
        <xsl:otherwise>
          <xsl:sequence select="'          ' || f:spaces($length - 10)"/>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:when>
    <xsl:otherwise>
      <xsl:sequence select="f:spaces(string-length(string($length)))"/>
    </xsl:otherwise>
  </xsl:choose>
</xsl:function>

<!-- ============================================================ -->

<xsl:function name="fp:lookup-string" as="node()*">
  <xsl:param name="context" as="element()"/>
  <xsl:param name="lookup" as="element()"/>
  <xsl:param name="table-name" as="xs:string"/>

  <xsl:variable name="value"
                select="$lookup/*[node-name(.)=node-name($context)]"/>

  <xsl:if test="count($value) gt 1">
    <xsl:message expand-text="yes"
                 >Duplicate {$table-name} for {node-name($context)}</xsl:message>
  </xsl:if>

  <xsl:sequence select="if (empty($value))
                        then $lookup/db:_default/node()
                        else $value[1]/node()"/>
</xsl:function>

<xsl:function name="fp:separator" as="node()*">
  <xsl:param name="node" as="element()"/>
  <xsl:param name="key" as="xs:string"/>
  <xsl:sequence select="fp:localization-template($node, 'separator')"/>
</xsl:function>

<xsl:function name="f:label-separator" as="node()*">
  <xsl:param name="node" as="element()"/>
  <xsl:sequence select="fp:separator($node, 'label-separator')"/>
</xsl:function>

<xsl:function name="fp:parse-key-value-pairs" as="map(xs:string,xs:string)">
  <xsl:param name="strings" as="xs:string*"/>
  <xsl:sequence select="fp:parse-key-value-pairs($strings, map { })"/>
</xsl:function>

<xsl:function name="fp:parse-key-value-pairs" as="map(xs:string,xs:string)">
  <xsl:param name="strings" as="xs:string*"/>
  <xsl:param name="map" as="map(xs:string,xs:string)"/>

  <xsl:variable name="car" select="$strings[1]"/>
  <xsl:variable name="cdr" select="subsequence($strings, 2)"/>

  <xsl:variable name="key" select="if (contains($car, ':'))
                                   then substring-before($car, ':')
                                   else '_default'"/>
  <xsl:variable name="value" select="if (contains($car, ':'))
                                     then substring-after($car, ':')
                                     else $car"/>

  <xsl:choose>
    <xsl:when test="empty($car)">
      <xsl:sequence select="$map"/>
    </xsl:when>
    <xsl:when test="map:contains($map, $key)">
      <xsl:message select="'Warning: ignoring duplicate key:', $key"/>
      <xsl:sequence select="fp:parse-key-value-pairs($cdr, $map)"/>
    </xsl:when>
    <xsl:otherwise>
      <xsl:sequence select="fp:parse-key-value-pairs($cdr,
                               map:put($map, $key, $value))"/>
    </xsl:otherwise>
  </xsl:choose>
</xsl:function>

<xsl:function name="f:refsection" as="xs:boolean">
  <xsl:param name="node" as="element()"/>
  <xsl:sequence select="$node/self::db:refsection
                        or $node/self::db:refsect1
                        or $node/self::db:refsect2
                        or $node/self::db:refsect3"/>
</xsl:function> 

<xsl:function name="f:section" as="xs:boolean" visibility="public">
  <xsl:param name="node" as="element()"/>
  <xsl:sequence select="$node/self::db:section
                        or $node/self::db:sect1
                        or $node/self::db:sect2
                        or $node/self::db:sect3
                        or $node/self::db:sect4
                        or $node/self::db:sect5
                        or f:refsection($node)"/>
</xsl:function>

<xsl:function name="f:section-depth" as="xs:integer" visibility="public">
  <xsl:param name="node" as="element()?"/>
  <xsl:choose>
    <xsl:when test="empty($node)">
      <xsl:value-of select="0"/>
    </xsl:when>
    <xsl:when test="$node/self::db:section">
      <xsl:value-of select="count($node/ancestor::db:section) + 1"/>
    </xsl:when>
    <xsl:when test="$node/self::db:sect1 or $node/self::db:sect2
                    or $node/self::db:sect3 or $node/self::db:sect4
                    or $node/self::db:sect5">
      <xsl:value-of select="xs:integer(substring(local-name($node), 5))"/>
    </xsl:when>
    <xsl:when test="$node/self::db:refsection">
      <xsl:value-of select="count($node/ancestor::db:refsection)+1"/>
    </xsl:when>
    <xsl:when test="$node/self::db:refsect1 or $node/self::db:refsect2
                    or $node/self::db:refsect3">
      <xsl:value-of select="xs:integer(substring(local-name($node), 8))"/>
    </xsl:when>
    <xsl:otherwise>
      <xsl:sequence select="f:section-depth($node/parent::*)"/>
    </xsl:otherwise>
  </xsl:choose>
</xsl:function>

<xsl:function name="f:step-number" as="xs:integer+">
  <xsl:param name="node" as="element(db:step)"/>
  <xsl:iterate select="reverse($node/ancestor-or-self::*)">
    <xsl:param name="number" select="()"/>
    <xsl:choose>
      <xsl:when test="self::db:procedure">
        <xsl:sequence select="$number"/>
        <xsl:break/>
      </xsl:when>
      <xsl:when test="self::db:step">
        <xsl:next-iteration>
          <xsl:with-param name="number"
                          select="(count(preceding-sibling::db:step)+1, $number)"/>
        </xsl:next-iteration>
      </xsl:when>
      <xsl:otherwise>
        <xsl:next-iteration>
          <xsl:with-param name="number" select="$number"/>
        </xsl:next-iteration>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:iterate>
</xsl:function>

<xsl:function name="f:step-numeration" as="xs:string">
  <xsl:param name="node" as="element(db:step)"/>
  <xsl:variable name="depth"
                select="count(f:step-number($node))"/>
  <xsl:variable name="depth"
                select="$depth
                        mod string-length($procedure-step-numeration)"/>
  <xsl:variable name="depth"
                select="if ($depth eq 0)
                        then string-length($procedure-step-numeration)
                        else $depth"/>
  <xsl:sequence select="substring($procedure-step-numeration, $depth, 1)"/>
</xsl:function>

<xsl:function name="f:orderedlist-item-number" as="xs:integer+">
  <xsl:param name="node" as="element(db:listitem)"/>
  <xsl:iterate select="reverse($node/ancestor-or-self::*)">
    <xsl:param name="number" select="()"/>
    <xsl:on-completion select="$number"/>
    <xsl:choose>
      <xsl:when test="self::db:listitem[parent::db:orderedlist]">
        <xsl:next-iteration>
          <xsl:with-param name="number"
                          select="(count(preceding-sibling::db:listitem)
                                   + f:orderedlist-startingnumber(parent::db:orderedlist),
                                   $number)"/>
        </xsl:next-iteration>
      </xsl:when>
      <xsl:otherwise>
        <xsl:next-iteration>
          <xsl:with-param name="number" select="$number"/>
        </xsl:next-iteration>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:iterate>
</xsl:function>

<xsl:function name="f:orderedlist-item-numeration" as="xs:string">
  <xsl:param name="node" as="element(db:listitem)"/>

  <xsl:variable name="numeration" select="$node/parent::db:orderedlist/@numeration"/>

  <xsl:choose>
    <xsl:when test="exists($numeration)">
      <xsl:choose>
        <xsl:when test="$numeration = 'upperalpha'">
          <xsl:sequence select="'A'"/>
        </xsl:when>
        <xsl:when test="$numeration = 'loweralpha'">
          <xsl:sequence select="'a'"/>
        </xsl:when>
        <xsl:when test="$numeration = 'upperroman'">
          <xsl:sequence select="'I'"/>
        </xsl:when>
        <xsl:when test="$numeration = 'lowerroman'">
          <xsl:sequence select="'i'"/>
        </xsl:when>
        <xsl:otherwise> <!-- arabic -->
          <xsl:sequence select="'1'"/>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:when>
    <xsl:otherwise>
      <xsl:variable name="depth"
                    select="count(f:orderedlist-item-number($node))"/>
      <xsl:variable name="depth"
                    select="$depth
                            mod string-length($orderedlist-item-numeration)"/>
      <xsl:variable name="depth"
                    select="if ($depth eq 0)
                            then string-length($orderedlist-item-numeration)
                            else $depth"/>
      <xsl:sequence select="substring($orderedlist-item-numeration, $depth, 1)"/>
    </xsl:otherwise>
  </xsl:choose>
</xsl:function>

<xsl:function name="f:tokenize-on-char" as="xs:string*">
  <xsl:param name="string" as="xs:string"/>
  <xsl:param name="char" as="xs:string"/>

  <xsl:variable name="ch" select="substring($char||' ', 1, 1)"/>

  <xsl:variable name="tchar"
                select="if ($ch = ('.', '?', '*', '{', '}', '\', '\[', '\]'))
                        then '\' || $ch
                        else $ch"/>

  <xsl:sequence select="tokenize($string, $tchar)"/>
</xsl:function>

<xsl:function name="f:uri-scheme" as="xs:string?">
  <xsl:param name="uri" as="xs:string"/>

  <xsl:if test="matches($uri, '^[-a-zA-Z0-9]+:')">
    <xsl:sequence select="replace($uri, '^([-a-zA-Z0-9]+):.*$', '$1')"/>
  </xsl:if>
</xsl:function>

<xsl:function name="f:relative-path" as="xs:string">
  <xsl:param name="base" as="xs:string"/>
  <xsl:param name="path" as="xs:string"/>

  <xsl:choose>
    <xsl:when test="exists(f:uri-scheme($path)) and f:uri-scheme($path) ne 'file'">
      <!-- It starts with a non-file: scheme, just assume it's absolute. -->
      <xsl:sequence select="$path"/>
    </xsl:when>
    <xsl:otherwise>
      <!-- Strip away variant forms of file: (file:/, file://, file:///, ...) -->
      <!-- In particular, file:/C:/path vs. file:///C:/path on Windows -->
      <xsl:variable name="bpath" select="replace($base, '^file:/+', '')"/>
      <xsl:variable name="ppath" select="replace($path, '^file:/+', '')"/>

      <xsl:variable name="base-parts" select="tokenize($bpath, '/')[position() lt last()]"/>
      <xsl:variable name="path-parts" select="tokenize($ppath, '/')"/>

      <!--
          <xsl:message select="'BP:', $base-parts"/>
          <xsl:message select="'PP:', $path-parts"/>
      -->

      <xsl:variable name="common-prefix" as="xs:string*">
        <xsl:iterate select="$base-parts">
          <xsl:param name="pos" select="1"/>
          <xsl:param name="common" select="()"/>
          <xsl:on-completion select="$common"/>
          <xsl:if test="$base-parts[$pos] = $path-parts[$pos]">
            <xsl:next-iteration>
              <xsl:with-param name="pos" select="$pos + 1"/>
              <xsl:with-param name="common" select="($common, $base-parts[$pos])"/>
            </xsl:next-iteration>
          </xsl:if>
        </xsl:iterate>
      </xsl:variable>

      <!--
          <xsl:message select="'CP:', $common-prefix"/>
      -->

      <xsl:variable name="base-tail"
                    select="$base-parts[position() gt count($common-prefix)]"/>
      <xsl:variable name="path-tail"
                    select="$path-parts[position() gt count($common-prefix)]"/>

      <!--
          <xsl:message select="'BT:', $base-tail"/>
          <xsl:message select="'PT:', $path-tail"/>
      -->

      <xsl:variable name="final-parts" as="xs:string*">
        <xsl:for-each select="1 to count($base-tail)">
          <xsl:sequence select="'..'"/>
        </xsl:for-each>
        <xsl:sequence select="$path-tail"/>
      </xsl:variable>

      <xsl:sequence select="string-join($final-parts, '/')"/>
    </xsl:otherwise>
  </xsl:choose>
</xsl:function>

</xsl:stylesheet>

toc.xsl

33 templates

Instructions
Template match ≅ *
Calls: tp:toc
Mode: m:toc
Matches: *
Template match ≅ /db:article|db:book|db:part|db…
Uses: $auto-toc
Calls: tp:toc
Mode: m:toc
Matches: /db:article, db:book, db:part, db:reference, db:set
Template match ≅ *
Mode: m:persistent-toc
Matches: *
Template match ≅ comment()|processing-instructi…
Mode: m:persistent-toc
Matches: comment(), processing-instruction(), text()
Template match ≅ /db:article|db:book|db:part|db…
Calls: tp:toc
Mode: m:persistent-toc
Matches: /db:article, db:book, db:part, db:reference, db:set
Template tp:toc match ≅
Mode: m:docbook
Template match ≅ *
Mode: m:toc-entry
Matches: *
Template match ≅ comment()|processing-instructi…
Mode: m:toc-entry
Matches: comment(), processing-instruction(), text()
Template match ≅ db:acknowledgements|db:appendi…
Calls: f:id()
Mode: m:toc-entry
Matches: db:acknowledgements, db:appendix, db:article, db:bibliography, db:book, db:chapter, db:dedication, db:glossary, db:index, db:part, db:preface, db:reference, db:sect1, db:sect2, db:sect3, db:sect4, db:sect5, db:section, db:set, db:topic
Template match ≅ db:refentry
Mode: m:toc-entry
Priority: 100
Matches: db:refentry
Template match ≅ *
Mode: m:toc-entry
Priority: 10
Matches: *
Template match ≅ db:bibliodiv|db:colophon|db:gl…
Mode: m:toc-entry
Matches: db:bibliodiv, db:colophon, db:glossdiv, db:indexdiv
Template match ≅ *
Mode: m:toc-nested
Matches: *
Template match ≅ comment()|processing-instructi…
Mode: m:toc-nested
Matches: comment(), processing-instruction(), text()
Template match ≅ db:equation|db:example|db:figu…
Mode: m:toc-nested
Matches: db:equation, db:example, db:figure, db:formalgroup, db:procedure, db:table
Template match ≅ db:refsect1|db:refsect2|db:ref…
Mode: m:toc-nested
Matches: db:refsect1, db:refsect2, db:refsect3, db:refsection, db:sect1, db:sect2, db:sect3, db:sect4, db:sect5, db:section
Template match ≅ *
Mode: m:list-of-figures
Matches: *
Template match ≅ db:book|db:set
Mode: m:list-of-figures
Matches: db:book, db:set
Template match ≅ *
Mode: m:list-of-tables
Matches: *
Template match ≅ db:book|db:set
Mode: m:list-of-tables
Matches: db:book, db:set
Template match ≅ *
Mode: m:list-of-examples
Matches: *
Template match ≅ db:book|db:set
Mode: m:list-of-examples
Matches: db:book, db:set
Template match ≅ *
Mode: m:list-of-equations
Matches: *
Template match ≅ db:book|db:set
Mode: m:list-of-equations
Matches: db:book, db:set
Template match ≅ *
Mode: m:list-of-procedures
Matches: *
Template match ≅ db:book|db:set
Mode: m:list-of-procedures
Matches: db:book, db:set
Template tp:list-of-titles match ≅
Mode: m:docbook
Template match ≅ *
Calls: f:id()
Mode: m:list-of-titles
Matches: *
Template match ≅ db:toc|processing-instruction(…
Mode: m:docbook
Matches: db:toc, processing-instruction('db-toc')
Template match ≅ db:toc
Mode: m:docbook
Matches: db:toc
Template match ≅ db:tocdiv
Mode: m:docbook
Matches: db:tocdiv
Template match ≅ db:tocentry
Mode: m:docbook
Matches: db:tocentry
Source code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:db="http://docbook.org/ns/docbook"
                xmlns:dbe="http://docbook.org/ns/docbook/errors"
                xmlns:f="http://docbook.org/ns/docbook/functions"
                xmlns:fp="http://docbook.org/ns/docbook/functions/private"
                xmlns:h="http://www.w3.org/1999/xhtml"
                xmlns:m="http://docbook.org/ns/docbook/modes"
                xmlns:t="http://docbook.org/ns/docbook/templates"
                xmlns:tp="http://docbook.org/ns/docbook/templates/private"
                xmlns:v="http://docbook.org/ns/docbook/variables"
                xmlns:vp="http://docbook.org/ns/docbook/variables/private"
                xmlns:xs="http://www.w3.org/2001/XMLSchema"
                xmlns="http://www.w3.org/1999/xhtml"
                default-mode="m:docbook"
                exclude-result-prefixes="#all"
                version="3.0">

<xsl:mode name="m:toc" on-no-match="shallow-skip"/>

<xsl:template match="*" mode="m:toc">
  <xsl:param name="placed-by-author" select="false()"/>
  <xsl:if test="$placed-by-author">
    <xsl:call-template name="tp:toc"/>
  </xsl:if>
</xsl:template>

<xsl:template match="/db:article|db:set|db:book|db:part|db:reference"
              mode="m:toc">
  <xsl:param name="placed-by-author" select="false()"/>
  <xsl:if test="$placed-by-author
                or (f:is-true($auto-toc)
                    and not(db:toc|processing-instruction('db-toc')))">
    <xsl:call-template name="tp:toc"/>
  </xsl:if>
</xsl:template>

<!-- By default, the persistent ToC is the same as the regular ToC.
     Customize the m:persistent-toc templates to change this. -->
<xsl:template match="*" mode="m:persistent-toc"/>
<xsl:template match="text()|processing-instruction()|comment()" mode="m:persistent-toc"/>
<xsl:template match="/db:article|db:set|db:book|db:part|db:reference"
              mode="m:persistent-toc">
  <xsl:call-template name="tp:toc"/>
</xsl:template>

<xsl:template name="tp:toc">
  <xsl:variable name="entries" as="element()*">
    <xsl:apply-templates mode="m:toc-entry"/>
  </xsl:variable>

  <xsl:variable name="lists-of-titles" as="element()*">
    <xsl:apply-templates select="." mode="m:list-of-figures"/>
    <xsl:apply-templates select="." mode="m:list-of-tables"/>
    <xsl:apply-templates select="." mode="m:list-of-examples"/>
    <xsl:apply-templates select="." mode="m:list-of-equations"/>
    <xsl:apply-templates select="." mode="m:list-of-procedures"/>
  </xsl:variable>

  <xsl:variable name="size" select="count($entries/descendant-or-self::h:li)
                                    + count($lists-of-titles//h:li)"/>
  
  <xsl:where-populated>
    <div class="list-of-titles">
      <xsl:if test="$size gt 1 or (f:is-true($generate-trivial-toc) and $size eq 1)">
        <div class="lot toc">
          <div class="title">
            <xsl:apply-templates select="." mode="m:gentext">
              <xsl:with-param name="group" select="'table-of-contents'"/>
            </xsl:apply-templates>
          </div>
          <ul class="toc">
            <xsl:sequence select="$entries"/>
          </ul>
        </div>
        <xsl:sequence select="$lists-of-titles"/>
      </xsl:if>
    </div>
  </xsl:where-populated>
</xsl:template>  

<xsl:template match="*" mode="m:toc-entry"/>
<xsl:template match="text()|processing-instruction()|comment()" mode="m:toc-entry"/>
<xsl:template mode="m:toc-entry"
              match="db:set|db:book|db:part|db:reference

                     |db:preface|db:chapter|db:appendix|db:article
                     |db:topic|db:part|db:reference|db:dedication
                     |db:bibliography|db:index|db:glossary
                     |db:acknowledgements

                     |db:article
                     |db:section|db:sect1|db:sect2|db:sect3|db:sect4|db:sect5
                     |db:topic
                     ">
  <li>
    <a href="#{f:id(.)}">
      <xsl:apply-templates select="." mode="m:headline">
        <xsl:with-param name="purpose" select="'lot'"/>
      </xsl:apply-templates>
    </a>
    <xsl:where-populated>
      <ul class="toc">
        <xsl:apply-templates mode="m:toc-nested"/>
      </ul>
    </xsl:where-populated>
  </li>
</xsl:template>

<xsl:template match="db:refentry" mode="m:toc-entry" priority="100">
  <xsl:variable name="refmeta" select=".//db:refmeta"/>
  <xsl:variable name="refentrytitle" select="$refmeta//db:refentrytitle"/>
  <xsl:variable name="refnamediv" select=".//db:refnamediv"/>
  <xsl:variable name="refname" select="$refnamediv//db:refname"/>

  <xsl:variable name="title">
    <xsl:choose>
      <xsl:when test="$refentrytitle">
        <xsl:apply-templates select="$refentrytitle[1]">
          <xsl:with-param name="purpose" select="'lot'"/>
        </xsl:apply-templates>
      </xsl:when>
      <xsl:when test="$refnamediv/db:refdescriptor">
        <xsl:apply-templates select="($refnamediv/db:refdescriptor)[1]">
          <xsl:with-param name="purpose" select="'lot'"/>
        </xsl:apply-templates>
      </xsl:when>
      <xsl:when test="$refname">
        <xsl:apply-templates select="$refname[1]">
          <xsl:with-param name="purpose" select="'lot'"/>
        </xsl:apply-templates>
      </xsl:when>
      <xsl:otherwise></xsl:otherwise>
    </xsl:choose>
  </xsl:variable>

  <li>
    <span class='refentrytitle'>
      <a href="#{f:id(.)}">
        <xsl:sequence select="$title"/>
      </a>
    </span>
    <xsl:if test="f:is-true($annotate-toc)">
      <xsl:apply-templates select="(db:refnamediv/db:refpurpose)[1]">
        <xsl:with-param name="purpose" select="'lot'"/>
      </xsl:apply-templates>
    </xsl:if>
  </li>
</xsl:template>

<xsl:template match="*[not(db:info/db:title)]" mode="m:toc-entry"
              priority="10">
  <!-- things without titles don't appear in the, uh, lists of titles -->
  <!-- preface, dedication, acknowledgements, colophon, equation,
       and procedure spring to mind... -->
</xsl:template>

<xsl:template match="db:colophon|db:bibliodiv|db:glossdiv|db:indexdiv"
              mode="m:toc-entry">
  <!-- by default, these don't appear in the ToC -->
</xsl:template>

<!-- ============================================================ -->

<xsl:template match="*" mode="m:toc-nested">
  <xsl:apply-templates select="." mode="m:toc-entry"/>
</xsl:template>
<xsl:template match="text()|processing-instruction()|comment()" mode="m:toc-nested"/>

<xsl:template match="db:formalgroup
                     |db:figure|db:table|db:example|db:equation|db:procedure"
              mode="m:toc-nested">
  <!-- these don't nest -->
</xsl:template>

<xsl:template match="db:section|db:sect1|db:sect2|db:sect3|db:sect4|db:sect5
                     |db:refsection|db:refsect1|db:refsect2|db:refsect3"
              mode="m:toc-nested">
  <xsl:variable name="depth" as="xs:integer">
    <xsl:choose>
      <xsl:when test="self::db:section">
        <xsl:sequence select="count(ancestor::db:section)+1"/>
      </xsl:when>
      <xsl:when test="self::db:refsection">
        <xsl:sequence select="count(ancestor::db:refsection)+1"/>
      </xsl:when>
      <xsl:when test="self::db:sect5">
        <xsl:sequence select="5"/>
      </xsl:when>
      <xsl:when test="self::db:sect4">
        <xsl:sequence select="4"/>
      </xsl:when>
      <xsl:when test="self::db:sect3 or self::db:refsect3">
        <xsl:sequence select="3"/>
      </xsl:when>
      <xsl:when test="self::db:sect2 or self::db:refsect2">
        <xsl:sequence select="2"/>
      </xsl:when>
      <xsl:when test="self::db:sect1 or self::db:refsect1">
        <xsl:sequence select="1"/>
      </xsl:when>
      <xsl:otherwise>
        <xsl:message select="'ERROR: no section matched in m:toc-nested: ' || node-name(.)"/>
        <xsl:sequence select="0"/>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:variable>

  <xsl:if test="$vp:section-toc-depth ge $depth">
    <xsl:apply-templates select="." mode="m:toc-entry"/>
  </xsl:if>
</xsl:template>

<!-- ============================================================ -->

<xsl:template match="*" mode="m:list-of-figures"/>
<xsl:template match="db:set|db:book" mode="m:list-of-figures">
  <xsl:if test="f:is-true($lists-of-figures)">
    <xsl:call-template name="tp:list-of-titles">
      <xsl:with-param name="elements"
                      select=".//db:figure[not(ancestor::db:formalgroup)]
                              |.//db:formalgroup[db:figure]"/>
      <xsl:with-param name="class" select="'list-of-figures'"/>
      <xsl:with-param name="group" select="'list-of-figures'"/>
    </xsl:call-template>
  </xsl:if>
</xsl:template>

<xsl:template match="*" mode="m:list-of-tables"/>
<xsl:template match="db:set|db:book" mode="m:list-of-tables">
  <xsl:if test="f:is-true($lists-of-tables)">
    <xsl:call-template name="tp:list-of-titles">
      <xsl:with-param name="elements"
                      select=".//db:table[not(ancestor::db:formalgroup)]
                              |.//db:formalgroup[db:table]"/>
      <xsl:with-param name="class" select="'list-of-tables'"/>
      <xsl:with-param name="group" select="'list-of-tables'"/>
    </xsl:call-template>
  </xsl:if>
</xsl:template>

<xsl:template match="*" mode="m:list-of-examples"/>
<xsl:template match="db:set|db:book" mode="m:list-of-examples">
  <xsl:if test="f:is-true($lists-of-examples)">
    <xsl:call-template name="tp:list-of-titles">
      <xsl:with-param name="elements"
                      select=".//db:example[not(ancestor::db:formalgroup)]
                              |.//db:formalgroup[db:example]"/>
      <xsl:with-param name="class" select="'list-of-examples'"/>
      <xsl:with-param name="group" select="'list-of-examples'"/>
    </xsl:call-template>
  </xsl:if>
</xsl:template>

<xsl:template match="*" mode="m:list-of-equations"/>
<xsl:template match="db:set|db:book" mode="m:list-of-equations">
  <xsl:if test="f:is-true($lists-of-equations)">
    <xsl:call-template name="tp:list-of-titles">
      <xsl:with-param
          name="elements"
          select=".//db:equation[db:info/db:title and not(ancestor::db:formalgroup)]
                  |.//db:formalgroup[db:equation]"/>
      <xsl:with-param name="class" select="'list-of-equations'"/>
      <xsl:with-param name="group" select="'list-of-equations'"/>
    </xsl:call-template>
  </xsl:if>
</xsl:template>

<xsl:template match="*" mode="m:list-of-procedures"/>
<xsl:template match="db:set|db:book" mode="m:list-of-procedures">
  <xsl:if test="f:is-true($lists-of-procedures)">
    <xsl:call-template name="tp:list-of-titles">
      <xsl:with-param name="elements" select=".//db:procedure[db:info/db:title]"/>
      <xsl:with-param name="class" select="'list-of-procedures'"/>
      <xsl:with-param name="group" select="'list-of-procedures'"/>
    </xsl:call-template>
  </xsl:if>
</xsl:template>

<xsl:template name="tp:list-of-titles">
  <xsl:param name="elements" as="element()*" required="yes"/>
  <xsl:param name="class" as="xs:string" required="yes"/>
  <xsl:param name="group" as="xs:string" required="yes"/>

  <xsl:if test="$elements">
    <div class="{$class} lot">
      <div class="title">
        <xsl:apply-templates select="." mode="m:gentext">
          <xsl:with-param name="group" select="$group"/>
        </xsl:apply-templates>
      </div>
      <ul class="toc">
        <xsl:apply-templates select="$elements" mode="m:list-of-titles"/>
      </ul>
    </div>
  </xsl:if>
</xsl:template>

<xsl:template match="*" mode="m:list-of-titles">
  <li>
    <a href="#{f:id(.)}">
      <xsl:apply-templates select="." mode="m:headline">
        <xsl:with-param name="purpose" select="'lot'"/>
      </xsl:apply-templates>
    </a>
  </li>
</xsl:template>

<!-- ============================================================ -->

<xsl:template match="db:toc[not(*)] | processing-instruction('db-toc')">
  <xsl:apply-templates select=".." mode="m:toc">
    <xsl:with-param name="placed-by-author" select="true()"/>
  </xsl:apply-templates>
</xsl:template>

<xsl:template match="db:toc[*]">
  <div>
    <xsl:apply-templates select="." mode="m:attributes"/>
    <div class="lot toc">
      <xsl:apply-templates select="." mode="m:generate-titlepage"/>
      <xsl:where-populated>
        <ul>
          <xsl:apply-templates select="db:tocdiv|db:tocentry"/>
        </ul>
      </xsl:where-populated>
    </div>
  </div>
</xsl:template>

<xsl:template match="db:tocdiv">
  <li>
    <xsl:call-template name="tp:tocentry-link">
      <xsl:with-param name="content" as="node()">
        <xsl:apply-templates select="db:info/db:title/node()"/>
      </xsl:with-param>
    </xsl:call-template>
    <xsl:where-populated>
      <ul>
        <xsl:apply-templates select="db:tocdiv|db:tocentry"/>
      </ul>
    </xsl:where-populated>
  </li>
</xsl:template>

<xsl:template match="db:tocentry">
  <li>
    <xsl:call-template name="tp:tocentry-link">
      <xsl:with-param name="content" as="node()">
        <xsl:apply-templates/>
      </xsl:with-param>
    </xsl:call-template>
  </li>
</xsl:template>

<xsl:template name="tp:tocentry-link">
  <xsl:param name="content" as="node()*"/>

  <xsl:variable name="target" select="if (@linkend)
                                      then key('id', @linkend)
                                      else ()"/>
  <xsl:choose>
    <xsl:when test="not(@linkend)">
      <xsl:sequence select="$content"/>
    </xsl:when>
    <xsl:when test="empty($target)">
      <xsl:message select="'Link to non-existent ID: ' || @linkend"/>
      <xsl:sequence select="$content"/>
    </xsl:when>
    <xsl:otherwise>
      <xsl:call-template name="tp:link">
        <xsl:with-param name="href" select="f:href(., $target)"/>
        <xsl:with-param name="content" select="$content"/>
      </xsl:call-template>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

</xsl:stylesheet>

divisions.xsl

2 templates

Instructions
Template match ≅ db:book|db:part|db:partintro|d…
Mode: m:docbook
Matches: db:book, db:part, db:partintro, db:reference, db:set
Template match ≅ *
Mode: m:back-cover
Matches: *
Source code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:db="http://docbook.org/ns/docbook"
                xmlns:f="http://docbook.org/ns/docbook/functions"
                xmlns:m="http://docbook.org/ns/docbook/modes"
                xmlns:t="http://docbook.org/ns/docbook/templates"
                xmlns:xs="http://www.w3.org/2001/XMLSchema"
                xmlns="http://www.w3.org/1999/xhtml"
                default-mode="m:docbook"
                exclude-result-prefixes="db f m t xs"
                version="3.0">

<xsl:template match="db:set|db:book|db:part|db:reference|db:partintro">
  <article>
    <xsl:apply-templates select="." mode="m:attributes"/>
    <xsl:apply-templates select="." mode="m:generate-titlepage"/>
    <xsl:apply-templates select="." mode="m:toc"/>
    <xsl:apply-templates/>
    <xsl:if test="self::db:set|self::db:book">
      <xsl:apply-templates select="." mode="m:back-cover"/>
    </xsl:if>
  </article>
</xsl:template>

<xsl:template match="*" mode="m:back-cover">
  <!--
  <section class="back-cover">
    <xsl:if test="not($output-media = 'print')">
      <xsl:attribute name="db-chunk" select="'back-cover' || $html-extension"/>
      <xsl:attribute name="db-navigable" select="'true'"/>
    </xsl:if>
    <p>Contents of back cover goes here</p>
  </section>
  -->
</xsl:template>

</xsl:stylesheet>

components.xsl

1 template

Instructions
Template match ≅ db:acknowledgements|db:appendi…
Mode: m:docbook
Matches: db:acknowledgements, db:appendix, db:article, db:chapter, db:colophon, db:dedication, db:preface, db:topic
Source code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:db="http://docbook.org/ns/docbook"
                xmlns:f="http://docbook.org/ns/docbook/functions"
                xmlns:m="http://docbook.org/ns/docbook/modes"
                xmlns:t="http://docbook.org/ns/docbook/templates"
                xmlns:xs="http://www.w3.org/2001/XMLSchema"
                xmlns="http://www.w3.org/1999/xhtml"
                default-mode="m:docbook"
                exclude-result-prefixes="db f m t xs"
                version="3.0">

<xsl:template match="db:preface|db:chapter|db:appendix|db:article
                     |db:topic|db:acknowledgements|db:dedication|db:colophon">
  <xsl:variable name="gi" select="if (parent::*)
                                  then 'section'
                                  else 'article'"/>
  <xsl:element name="{$gi}" namespace="http://www.w3.org/1999/xhtml">
    <xsl:apply-templates select="." mode="m:attributes"/>
    <xsl:apply-templates select="." mode="m:generate-titlepage"/>
    <xsl:apply-templates select="." mode="m:toc"/>
    <xsl:apply-templates/>
  </xsl:element>
</xsl:template>

</xsl:stylesheet>

refentry.xsl

11 templates

Instructions
Template match ≅ db:refentry
Mode: m:docbook
Matches: db:refentry
Template match ≅ db:refnamediv
Mode: m:docbook
Matches: db:refnamediv
Template match ≅ db:refnamediv
Mode: m:docbook
Matches: db:refnamediv
Template match ≅ db:refclass|db:refmeta
Mode: m:docbook
Matches: db:refclass, db:refmeta
Template match ≅ db:refdescriptor
Mode: m:docbook
Matches: db:refdescriptor
Template match ≅ db:manvolnum
Mode: m:docbook
Matches: db:manvolnum
Template match ≅ db:refentrytitle
Mode: m:docbook
Matches: db:refentrytitle
Template match ≅ db:refname
Mode: m:docbook
Matches: db:refname
Template match ≅ db:refpurpose
Mode: m:docbook
Matches: db:refpurpose
Template match ≅ db:refsynopsisdiv
Mode: m:docbook
Matches: db:refsynopsisdiv
Template match ≅ db:refsect1|db:refsect2|db:ref…
Mode: m:docbook
Matches: db:refsect1, db:refsect2, db:refsect3, db:refsection
Source code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:db="http://docbook.org/ns/docbook"
                xmlns:f="http://docbook.org/ns/docbook/functions"
                xmlns:fp="http://docbook.org/ns/docbook/functions/private"
                xmlns:m="http://docbook.org/ns/docbook/modes"
                xmlns:t="http://docbook.org/ns/docbook/templates"
                xmlns:vp="http://docbook.org/ns/docbook/variables/private"
                xmlns:xs="http://www.w3.org/2001/XMLSchema"
                xmlns="http://www.w3.org/1999/xhtml"
                default-mode="m:docbook"
                exclude-result-prefixes="db f fp m t vp xs"
                version="3.0">

<xsl:template match="db:refentry">
  <xsl:variable name="gi" select="if (parent::*)
                                  then 'section'
                                  else 'article'"/>

  <xsl:element name="{$gi}" namespace="http://www.w3.org/1999/xhtml">
    <xsl:apply-templates select="." mode="m:attributes"/>
    <xsl:apply-templates select="." mode="m:generate-titlepage"/>
    <xsl:apply-templates select="." mode="m:toc"/>
    <xsl:apply-templates/>
  </xsl:element>
</xsl:template>

<xsl:template match="db:refnamediv[preceding-sibling::db:refnamediv]"/>
<xsl:template match="db:refnamediv[not(preceding-sibling::db:refnamediv)]">
  <div>
    <xsl:apply-templates select="." mode="m:attributes"/>

    <xsl:choose>
      <xsl:when test="$refentry-generate-name">
        <header>
          <h2>
            <xsl:apply-templates select="." mode="m:gentext">
              <xsl:with-param name="group" select="'label'"/>
              <xsl:with-param name="content" select="()"/>
            </xsl:apply-templates>
          </h2>
        </header>
      </xsl:when>

      <xsl:when test="$refentry-generate-title">
        <header>
          <h2>
            <xsl:choose>
              <xsl:when test="../db:refmeta/db:refentrytitle">
                <xsl:apply-templates select="../db:refmeta/db:refentrytitle"/>
              </xsl:when>
              <xsl:when test="db:refdescriptor">
                <xsl:apply-templates select="db:refdescriptor"/>
              </xsl:when>
              <xsl:otherwise>
                <xsl:apply-templates select="db:refname[1]"/>
              </xsl:otherwise>
            </xsl:choose>
          </h2>
        </header>
      </xsl:when>
    </xsl:choose>

    <p>
      <xsl:choose>
        <xsl:when test="db:refdescriptor">
          <xsl:apply-templates select="db:refdescriptor"/>
        </xsl:when>
        <xsl:otherwise>
          <xsl:apply-templates select="db:refname"/>
        </xsl:otherwise>
      </xsl:choose>
      <xsl:apply-templates select="* except (db:refdescriptor|db:refname)"/>
    </p>
    <xsl:for-each select="following-sibling::db:refnamediv">
      <p>
        <xsl:choose>
          <xsl:when test="db:refdescriptor">
            <xsl:apply-templates select="db:refdescriptor"/>
          </xsl:when>
          <xsl:otherwise>
            <xsl:apply-templates select="db:refname"/>
          </xsl:otherwise>
        </xsl:choose>
        <xsl:apply-templates select="* except (db:refdescriptor|db:refname)"/>
      </p>
    </xsl:for-each>
  </div>
</xsl:template>

<xsl:template match="db:refmeta|db:refclass"/>

<xsl:template match="db:refdescriptor">
  <xsl:param name="purpose" select="''"/>
  <span>
    <xsl:apply-templates select="." mode="m:attributes"/>
    <xsl:apply-templates/>
  </span>
</xsl:template>

<xsl:template match="db:manvolnum">
  <span class="manvolnum">
    <span class="sep">(</span>
    <xsl:apply-templates/>
    <span class="sep">)</span>
  </span>
</xsl:template>

<xsl:template match="db:refentrytitle">
  <xsl:param name="purpose" select="''"/>
  <span>
    <xsl:apply-templates select="." mode="m:attributes"/>
    <xsl:apply-templates/>
  </span>
</xsl:template>

<xsl:template match="db:refname">
  <xsl:param name="purpose" select="''"/>
  <span>
    <xsl:apply-templates select="." mode="m:attributes"/>
    <xsl:apply-templates/>
  </span>
  <xsl:if test="not($purpose = 'lot') and following-sibling::db:refname">
    <span class="refname-sep">, </span>
  </xsl:if>
</xsl:template>

<xsl:template match="db:refpurpose">
  <xsl:param name="purpose" select="''"/>
  <span>
    <xsl:choose>
      <xsl:when test="$purpose = 'lot'">
        <xsl:attribute name="class" select="local-name(.)"/>
      </xsl:when>
      <xsl:otherwise>
        <xsl:apply-templates select="." mode="m:attributes"/>
      </xsl:otherwise>
    </xsl:choose>
    <span class="refpurpose-sep"> — </span>
    <span class="refpurpose-text">
      <xsl:apply-templates/>
    </span>
    <xsl:if test="not($purpose = 'lot')
                  and not(matches(normalize-space(.), '\p{P}$'))">
      <span class="refpurpose-punc">
        <xsl:text>.</xsl:text>
      </span>
    </xsl:if>
  </span>
</xsl:template>

<xsl:template match="db:refsynopsisdiv">
  <section>
    <xsl:apply-templates select="." mode="m:attributes"/>
    <header>
      <h2>
        <xsl:choose>
          <xsl:when test="db:info/db:title">
            <xsl:apply-templates select="db:info/db:title"
                                 mode="m:titlepage-mode"/>
          </xsl:when>
          <xsl:otherwise>
            <xsl:text>Synopsis</xsl:text>
          </xsl:otherwise>
        </xsl:choose>
      </h2>
    </header>
    <xsl:apply-templates/>
  </section>
</xsl:template>

<xsl:template match="db:refsection|db:refsect1|db:refsect2|db:refsect3">
  <section>
    <xsl:apply-templates select="." mode="m:attributes"/>
    <xsl:apply-templates select="." mode="m:generate-titlepage"/>
    <xsl:apply-templates/>
  </section>
</xsl:template>

</xsl:stylesheet>

bibliography.xsl

23 templates

Instructions
Template match ≅ db:bibliodiv|db:bibliography|d…
Mode: m:docbook
Matches: db:bibliodiv, db:bibliography, db:bibliolist
Template match ≅ db:biblioentry
Calls: f:pi()
Mode: m:docbook
Matches: db:biblioentry
Template match ≅ db:bibliomixed
Mode: m:docbook
Matches: db:bibliomixed
Template match ≅ db:bibliomset
Mode: m:bibliomixed
Matches: db:bibliomset
Template match ≅ db:abbrev
Mode: m:bibliomixed
Matches: db:abbrev
Template match ≅ db:title
Mode: m:bibliomixed
Matches: db:title
Template match ≅ db:address|db:publisher
Mode: m:bibliomixed
Matches: db:address, db:publisher
Template match ≅ *
Mode: m:bibliomixed
Matches: *
Template match ≅ text()
Mode: m:bibliomixed
Matches: text()
Template match ≅ db:releaseinfo
Mode: m:bibliomixed
Matches: db:releaseinfo
Template match ≅ db:biblioset
Mode: m:biblioentry
Matches: db:biblioset
Template match ≅ db:title
Mode: m:biblioentry
Matches: db:title
Template match ≅ db:subtitle
Calls: t:inline
Mode: m:biblioentry
Matches: db:subtitle
Template match ≅ db:address|db:publisher
Mode: m:biblioentry
Matches: db:address, db:publisher
Template match ≅ db:collab|db:othercredit
Mode: m:biblioentry
Matches: db:collab, db:othercredit
Template match ≅ db:confgroup
Mode: m:biblioentry
Matches: db:confgroup
Template match ≅ db:confdates|db:confnum|db:con…
Mode: m:biblioentry
Matches: db:confdates, db:confnum, db:confsponsor, db:conftitle
Template match ≅ db:contractnum|db:contractspon…
Mode: m:biblioentry
Matches: db:contractnum, db:contractsponsor, db:edition, db:volumenum
Template match ≅ db:releaseinfo
Mode: m:biblioentry
Matches: db:releaseinfo
Template match ≅ *
Mode: m:biblioentry
Matches: *
Template match ≅ text()
Mode: m:biblioentry
Matches: text()
Template match ≅ db:authorgroup
Mode: m:docbook
Matches: db:authorgroup
Template match ≅ db:biblioid|db:bibliomisc|db:b…
Calls: t:inline
Mode: m:docbook
Matches: db:biblioid, db:bibliomisc, db:bibliosource, db:orgdiv, db:orgname, db:subtitle
Source code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:db="http://docbook.org/ns/docbook"
                xmlns:f="http://docbook.org/ns/docbook/functions"
                xmlns:fp="http://docbook.org/ns/docbook/functions/private"
                xmlns:m="http://docbook.org/ns/docbook/modes"
                xmlns:t="http://docbook.org/ns/docbook/templates"
                xmlns:vp="http://docbook.org/ns/docbook/variables/private"
                xmlns:xs="http://www.w3.org/2001/XMLSchema"
                xmlns="http://www.w3.org/1999/xhtml"
                default-mode="m:docbook"
                exclude-result-prefixes="db f fp m t vp xs"
                version="3.0">

<xsl:template match="db:bibliography|db:bibliodiv|db:bibliolist">
  <xsl:variable name="gi" select="if (parent::*)
                                  then 'div'
                                  else 'article'"/>
  <xsl:element name="{$gi}" namespace="http://www.w3.org/1999/xhtml">
    <xsl:apply-templates select="." mode="m:attributes"/>
    <xsl:apply-templates select="." mode="m:generate-titlepage"/>
    <xsl:apply-templates/>
  </xsl:element>
</xsl:template>

<xsl:template match="db:biblioentry">
  <xsl:variable name="style"
                select="f:pi(.., 'bibliography-style', $bibliography-style)"/>
  <xsl:choose>
    <xsl:when test="$style = 'iso690'">
      <xsl:apply-templates select="." mode="m:biblio690"/>
    </xsl:when>
    <xsl:otherwise>
      <p>
        <xsl:apply-templates select="." mode="m:attributes"/>
        <xsl:call-template name="t:biblioentry"/>
      </p>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

<xsl:template match="db:bibliomixed">
  <p>
    <xsl:apply-templates select="." mode="m:attributes"/>
    <xsl:choose>
      <xsl:when test="@xml:id and not(child::*[1]/self::db:abbrev)">
        <xsl:sequence select="'[' || @xml:id || '] '"/>
        <xsl:apply-templates mode="m:bibliomixed"/>
      </xsl:when>
      <xsl:otherwise>
        <xsl:apply-templates mode="m:bibliomixed"/>
      </xsl:otherwise>
    </xsl:choose>
  </p>
</xsl:template>

<!-- ============================================================ -->

<xsl:template match="db:bibliomset" mode="m:bibliomixed">
  <span>
    <xsl:apply-templates select="." mode="m:attributes"/>
    <xsl:apply-templates mode="m:bibliomixed"/>
  </span>
</xsl:template>

<xsl:template match="db:abbrev" mode="m:bibliomixed">
  <xsl:choose>
    <xsl:when test="empty(preceding-sibling::*)
                    and (normalize-space(preceding-sibling::text()) = '')">
      <!-- this is the citation -->
      <xsl:text>[</xsl:text>
      <span>
        <xsl:apply-templates select="." mode="m:attributes"/>
        <xsl:apply-templates mode="m:bibliomixed"/>
      </span>
      <xsl:text>] </xsl:text>
    </xsl:when>
    <xsl:otherwise>
      <span>
        <xsl:apply-templates select="." mode="m:attributes"/>
        <xsl:apply-templates mode="m:bibliomixed"/>
      </span>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

<xsl:template match="db:title" mode="m:bibliomixed">
  <xsl:choose>
    <xsl:when test="parent::db:bibliomset[@relation='article']">
      <q>
        <xsl:apply-templates select="." mode="m:attributes"/>
        <xsl:apply-templates/>
      </q>
    </xsl:when>
    <xsl:otherwise>
      <cite>
        <xsl:apply-templates select="." mode="m:attributes"/>
        <xsl:apply-templates/>
      </cite>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

<xsl:template match="db:address|db:publisher" mode="m:bibliomixed">
  <span>
    <xsl:apply-templates select="." mode="m:attributes"/>
    <xsl:apply-templates mode="m:bibliomixed"/>
  </span>
</xsl:template>

<xsl:template match="*" mode="m:bibliomixed">
  <xsl:apply-templates select="."/>
</xsl:template>

<xsl:template match="text()" mode="m:bibliomixed">
  <xsl:choose>
    <xsl:when test="parent::db:address">
      <!-- explicitly xsl:value-of because we need a text node -->
      <xsl:value-of select="replace(string(.), '&#10;', ' / ')"/>
    </xsl:when>
    <xsl:otherwise>
      <xsl:copy/>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

<xsl:template match="db:releaseinfo" mode="m:bibliomixed">
  <span>
    <xsl:apply-templates select="." mode="m:attributes"/>
    <xsl:apply-templates mode="m:biblioentry"/>
  </span>
</xsl:template>

<!-- ============================================================ -->

<xsl:template match="db:biblioset" mode="m:biblioentry">
  <span>
    <xsl:apply-templates select="." mode="m:attributes"/>
    <xsl:apply-templates/>
  </span>
</xsl:template>

<xsl:template match="db:title" mode="m:biblioentry">
  <xsl:choose>
    <xsl:when test="parent::db:biblioset[@relation='article']">
      <q>
        <xsl:apply-templates select="." mode="m:attributes"/>
        <xsl:apply-templates/>
      </q>
    </xsl:when>
    <xsl:otherwise>
      <cite>
        <xsl:apply-templates select="." mode="m:attributes"/>
        <xsl:apply-templates/>
      </cite>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

<xsl:template match="db:subtitle" mode="m:biblioentry">
  <xsl:call-template name="t:inline"/>
</xsl:template>

<xsl:template match="db:address|db:publisher" mode="m:biblioentry">
  <span>
    <xsl:apply-templates select="." mode="m:attributes"/>
    <xsl:apply-templates mode="m:biblioentry"/>
  </span>
</xsl:template>

<xsl:template match="db:collab|db:othercredit" mode="m:biblioentry">
  <span>
    <xsl:apply-templates select="." mode="m:attributes"/>
    <xsl:apply-templates select="db:personname|db:orgname"
                         mode="m:biblioentry"/>
  </span>
</xsl:template>

<xsl:template match="db:confgroup" mode="m:biblioentry">
  <span>
    <xsl:apply-templates select="." mode="m:attributes"/>
    <xsl:apply-templates mode="m:biblioentry"/>
  </span>
</xsl:template>

<xsl:template match="db:confdates|db:conftitle|db:confsponsor|db:confnum"
              mode="m:biblioentry">
  <span>
    <xsl:apply-templates select="." mode="m:attributes"/>
    <xsl:apply-templates mode="m:biblioentry"/>
  </span>
  <xsl:text>. </xsl:text>
</xsl:template>

<xsl:template match="db:contractnum|db:contractsponsor
                     |db:edition|db:volumenum" mode="m:biblioentry">
  <span>
    <xsl:apply-templates select="." mode="m:attributes"/>
    <xsl:apply-templates mode="m:biblioentry"/>
  </span>
</xsl:template>

<xsl:template match="db:releaseinfo" mode="m:biblioentry">
  <span>
    <xsl:apply-templates select="." mode="m:attributes"/>
    <xsl:apply-templates mode="m:biblioentry"/>
  </span>
</xsl:template>

<xsl:template match="*" mode="m:biblioentry">
  <xsl:apply-templates select="."/>
</xsl:template>

<xsl:template match="text()" mode="m:biblioentry">
  <xsl:choose>
    <xsl:when test="parent::db:address">
      <!-- explicitly xsl:value-of because we need a text node -->
      <xsl:value-of select="replace(string(.), '&#10;', ' / ')"/>
    </xsl:when>
    <xsl:otherwise>
      <xsl:copy/>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

<!-- ============================================================ -->

<xsl:template match="db:authorgroup[not(parent::db:info)]">
  <span>
    <xsl:apply-templates select="." mode="m:attributes"/>
    <xsl:call-template name="t:person-name-list"/>
  </span>
</xsl:template>

<xsl:template match="db:biblioid|db:orgname|db:orgdiv|db:bibliosource
                     |db:bibliomisc|db:subtitle">
  <xsl:call-template name="t:inline"/>
</xsl:template>

<!-- ============================================================ -->

</xsl:stylesheet>

biblio690.xsl

34 templates, 2 functions

Instructions
Template match ≅ db:biblioentry
Mode: m:biblio690
Matches: db:biblioentry
Template match ≅ db:biblioentry
Mode: m:biblio690
Matches: db:biblioentry
Template match ≅ db:biblioentry
Mode: m:biblio690
Matches: db:biblioentry
Template match ≅ db:biblioentry
Mode: m:biblio690
Matches: db:biblioentry
Template match ≅ db:biblioentry
Mode: m:biblio690
Matches: db:biblioentry
Template match ≅ db:biblioentry
Mode: m:biblio690
Matches: db:biblioentry
Template match ≅ db:biblioentry
Mode: m:biblio690
Matches: db:biblioentry
Template match ≅ db:biblioentry
Mode: m:biblio690
Matches: db:biblioentry
Template match ≅ db:biblioentry
Mode: m:biblio690
Matches: db:biblioentry
Template match ≅ db:biblioset
Mode: m:biblio690
Matches: db:biblioset
Template match ≅ db:authorgroup
Mode: m:biblio690
Matches: db:authorgroup
Template match ≅ db:author
Mode: m:biblio690
Matches: db:author
Template match ≅ db:personname
Mode: m:biblio690
Matches: db:personname
Template match ≅ db:title
Mode: m:biblio690
Matches: db:title
Template match ≅ db:biblioset
Mode: m:biblio690
Matches: db:biblioset
Template match ≅ db:title
Mode: mp:biblio690-punct
Matches: db:title
Template match ≅ db:subtitle
Mode: m:biblio690
Matches: db:subtitle
Template match ≅ db:bibliomisc
Mode: m:biblio690
Matches: db:bibliomisc
Template match ≅ db:bibliomisc
Mode: m:biblio690
Matches: db:bibliomisc
Template match ≅ db:bibliomisc
Mode: m:biblio690
Matches: db:bibliomisc
Template match ≅ db:bibliomisc
Mode: m:biblio690
Matches: db:bibliomisc
Template match ≅ db:bibliomisc
Mode: m:biblio690
Matches: db:bibliomisc
Template match ≅ db:edition
Mode: m:biblio690
Matches: db:edition
Template match ≅ db:volumenum
Mode: m:biblio690
Matches: db:volumenum
Template match ≅ db:issuenum
Mode: m:biblio690
Matches: db:issuenum
Template match ≅ db:publisher
Mode: m:biblio690
Matches: db:publisher
Template match ≅ db:pubdate
Mode: m:biblio690
Matches: db:pubdate
Template match ≅ db:date
Mode: m:biblio690
Matches: db:date
Template match ≅ db:pagenums
Mode: m:biblio690
Matches: db:pagenums
Template match ≅ db:biblioid
Mode: m:biblio690
Matches: db:biblioid
Template match ≅ db:biblioid
Mode: m:biblio690
Matches: db:biblioid
Template match ≅ db:city|db:firstname|db:givenn…
Mode: m:biblio690
Matches: db:city, db:firstname, db:givenname, db:publishername, db:surname
Template match ≅ db:biblioentry
Mode: m:biblio690
Matches: db:biblioentry
Template match ≅ db:*
Mode: m:biblio690
Matches: db:*
Function fp:iso690($context as element(), $key as xs:string) as item()*
Function fp:optional-sep($context as element(), $key as xs:string) as item()*
Source code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:db="http://docbook.org/ns/docbook"
                xmlns:f="http://docbook.org/ns/docbook/functions"
                xmlns:fp="http://docbook.org/ns/docbook/functions/private"
                xmlns:m="http://docbook.org/ns/docbook/modes"
                xmlns:mp="http://docbook.org/ns/docbook/modes/private"
                xmlns:t="http://docbook.org/ns/docbook/templates"
                xmlns:xlink='http://www.w3.org/1999/xlink'
                xmlns:xs="http://www.w3.org/2001/XMLSchema"
                xmlns="http://www.w3.org/1999/xhtml"
                default-mode="m:biblio690"
                exclude-result-prefixes="#all"
                version="3.0">

<xsl:template match="db:biblioentry[contains-token(@role, 'monograph')]">
  <xsl:variable name="entry">
    <db:biblioentry role="{@role}">
      <xsl:sequence select="db:authorgroup|db:author"/>
      <xsl:sequence select="db:title"/>
      <xsl:sequence select="db:subtitle"/>
      <xsl:sequence select="db:bibliomisc[contains-token(@role, 'medium')]"/>
      <xsl:sequence select="db:bibliomisc[contains-token(@role, 'secondary')]"/>
      <xsl:sequence select="db:edition"/>
      <xsl:sequence select="db:publisher"/>
      <xsl:sequence select="db:pubdate"/>
      <xsl:sequence select="db:pagenums"/>
      <xsl:sequence select="db:date[contains-token(@role, 'cit')]"/>
      <xsl:sequence select="db:bibliomisc[contains-token(@role, 'serie')]"/>
      <xsl:sequence select="db:bibliomisc[not(@role)]"/>
      <xsl:sequence select="db:biblioid"/>
    </db:biblioentry>
  </xsl:variable>

  <p>
    <xsl:apply-templates select="$entry/db:biblioentry" mode="m:attributes">
      <xsl:with-param name="style" select="'iso690'"/>
    </xsl:apply-templates>
    <xsl:apply-templates select="$entry/db:biblioentry/*"/>
  </p>
</xsl:template>

<xsl:template match="db:biblioentry[contains-token(@role, 'serial')]">
  <xsl:variable name="entry">
    <db:biblioentry role="{@role}">
      <xsl:sequence select="db:title"/>
      <xsl:sequence select="db:subtitle"/>
      <xsl:sequence select="db:bibliomisc[contains-token(@role, 'medium')]"/>
      <xsl:sequence select="db:bibliomisc[contains-token(@role, 'secondary')]"/>
      <xsl:sequence select="db:edition"/>
      <xsl:sequence select="db:pubdate[contains-token(@role, 'issuing')]"/>
      <xsl:sequence select="db:issuenum"/>
      <xsl:sequence select="db:publisher"/>
      <xsl:sequence select="db:pubdate[not(@role)]"/>
      <xsl:sequence select="db:date[contains-token(@role, 'cit')]"/>
      <xsl:sequence select="db:bibliomisc[contains-token(@role, 'serie')]"/>
      <xsl:sequence select="db:bibliomisc[not(@role)]"/>
      <xsl:sequence select="db:biblioid"/>
    </db:biblioentry>
  </xsl:variable>

  <p>
    <xsl:apply-templates select="$entry/db:biblioentry" mode="m:attributes">
      <xsl:with-param name="style" select="'iso690'"/>
    </xsl:apply-templates>
    <xsl:apply-templates select="$entry/db:biblioentry/*"/>
  </p>
</xsl:template>

<xsl:template match="db:biblioentry[contains-token(@role, 'part')]">
  <xsl:variable name="entry">
    <db:biblioentry role="{@role}">
      <xsl:sequence select="db:authorgroup|db:author"/>
      <xsl:sequence select="db:title"/>
      <xsl:sequence select="db:subtitle"/>
      <xsl:sequence select="db:bibliomisc[contains-token(@role, 'medium')]"/>
      <xsl:sequence select="db:edition"/>
      <xsl:sequence select="db:volumenum"/>
      <xsl:sequence select="db:bibliomisc[contains-token(@role, 'secondary')]"/>
      <xsl:sequence select="db:publisher"/>
      <xsl:sequence select="db:pubdate"/>
      <xsl:sequence select="db:date[contains-token(@role, 'cit')]"/>
      <xsl:sequence select="db:bibliomisc[contains-token(@role, 'secnum')]"/>
      <xsl:sequence select="db:bibliomisc[contains-token(@role, 'sectitle')]"/>
      <xsl:sequence select="db:pagenums"/>
      <xsl:sequence select="db:biblioid"/>
    </db:biblioentry>
  </xsl:variable>

  <p>
    <xsl:apply-templates select="$entry/db:biblioentry" mode="m:attributes">
      <xsl:with-param name="style" select="'iso690'"/>
    </xsl:apply-templates>
    <xsl:apply-templates select="$entry/db:biblioentry/*"/>
  </p>
</xsl:template>

<xsl:template match="db:biblioentry[contains-token(@role, 'contribution')]">
  <xsl:variable name="part" select="db:biblioset[@relation='part']"/>
  <xsl:variable name="book" select="db:biblioset[@relation='book']"/>

  <xsl:variable name="entry">
    <db:biblioentry role="{@role}">
      <db:biblioset relation="part">
        <xsl:sequence select="$part/db:authorgroup|$part/db:author"/>
        <xsl:sequence select="$part/db:title"/>
        <xsl:sequence select="$part/db:subtitle"/>
      </db:biblioset>
      <db:biblioset relation="book">
        <xsl:sequence select="$book/db:authorgroup|$book/db:author"/>
        <xsl:sequence select="$book/db:title"/>
        <xsl:sequence select="$book/db:subtitle"/>
        <xsl:sequence select="$book/db:bibliomisc[contains-token(@role, 'medium')]"/>
        <xsl:sequence select="$book/db:edition"/>
        <xsl:sequence select="$book/db:publisher"/>
        <xsl:sequence select="$book/db:pubdate"/>
        <xsl:sequence select="$book/db:volumenum"/>
        <xsl:sequence select="$book/db:pagenums"/>
        <xsl:sequence select="$book/db:biblioid"/>
      </db:biblioset>
    </db:biblioentry>
  </xsl:variable>

  <p>
    <xsl:apply-templates select="$entry/db:biblioentry" mode="m:attributes">
      <xsl:with-param name="style" select="'iso690'"/>
    </xsl:apply-templates>
    <xsl:apply-templates select="$entry/db:biblioentry/*"/>
  </p>
</xsl:template>

<xsl:template match="db:biblioentry[contains-token(@role, 'article')]">
  <xsl:variable name="art" select="db:biblioset[@relation='article']"/>
  <xsl:variable name="jour" select="db:biblioset[@relation='journal']"/>

  <xsl:variable name="entry">
    <db:biblioentry role="{@role}">
      <db:biblioset relation="part">
        <xsl:sequence select="$art/db:authorgroup|$art/db:author"/>
        <xsl:sequence select="$art/db:title"/>
        <xsl:sequence select="$art/db:subtitle"/>
        <xsl:sequence select="$art/db:bibliomisc[contains-token(@role, 'secondary')]"/>
      </db:biblioset>
      <db:biblioset relation="journal">
        <xsl:sequence select="$jour/db:title"/>
        <xsl:sequence select="$jour/db:subtitle"/>
        <xsl:sequence select="$jour/db:bibliomisc[contains-token(@role, 'medium')]"/>
        <xsl:sequence select="$jour/db:pubdate"/>
        <xsl:sequence select="$jour/db:volumenum"/>
        <xsl:sequence select="$jour/db:issuenum"/>
        <xsl:sequence select="$jour/db:date[contains-token(@role, 'cit')]"/>
        <xsl:sequence select="$jour/db:pagenums"/>
        <xsl:sequence select="$jour/db:biblioid"/>
      </db:biblioset>
    </db:biblioentry>
  </xsl:variable>

  <p>
    <xsl:apply-templates select="$entry/db:biblioentry" mode="m:attributes">
      <xsl:with-param name="style" select="'iso690'"/>
    </xsl:apply-templates>
    <xsl:apply-templates select="$entry/db:biblioentry/*"/>
  </p>
</xsl:template>

<xsl:template match="db:biblioentry[contains-token(@role, 'patent')]">
  <xsl:variable name="entry">
    <db:biblioentry role="{@role}">
      <xsl:sequence select="db:authorgroup|db:author"/>
      <xsl:sequence select="db:title"/>
      <xsl:sequence select="db:subtitle"/>
      <xsl:sequence select="db:bibliomisc[contains-token(@role, 'secondary')]"/>
      <xsl:sequence select="db:bibliomisc[not(@role)]"/>
      <xsl:sequence select="db:address"/>
      <xsl:sequence select="db:bibliomisc[contains-token(@role, 'patenttype')]"/>
      <xsl:sequence select="db:biblioid[@otherclass='patentnum']"/>
      <xsl:sequence select="db:pubdate"/>
    </db:biblioentry>
  </xsl:variable>

  <p>
    <xsl:apply-templates select="$entry/db:biblioentry" mode="m:attributes">
      <xsl:with-param name="style" select="'iso690'"/>
    </xsl:apply-templates>
    <xsl:apply-templates select="$entry/db:biblioentry/*"/>
  </p>
</xsl:template>

<xsl:template match="db:biblioentry[contains-token(@role, 'messagesystem')]">
  <xsl:variable name="entry">
    <db:biblioentry role="{@role}">
      <xsl:sequence select="db:title"/>
      <xsl:sequence select="db:subtitle"/>
      <xsl:sequence select="db:bibliomisc[contains-token(@role, 'medium')]"/>
      <xsl:sequence select="db:publisher"/>
      <xsl:sequence select="db:pubdate"/>
      <xsl:sequence select="db:date[contains-token(@role, 'cit')]"/>
      <xsl:sequence select="db:biblioid"/>
    </db:biblioentry>
  </xsl:variable>

  <p>
    <xsl:apply-templates select="$entry/db:biblioentry" mode="m:attributes">
      <xsl:with-param name="style" select="'iso690'"/>
    </xsl:apply-templates>
    <xsl:apply-templates select="$entry/db:biblioentry/*"/>
  </p>
</xsl:template>

<xsl:template match="db:biblioentry[contains-token(@role, 'message')]">
  <xsl:variable name="part" select="db:biblioset[@relation='part']"/>
  <xsl:variable name="book" select="db:biblioset[@relation='book']"/>

  <xsl:variable name="entry">
    <db:biblioentry role="{@role}">
      <db:biblioset relation="part">
        <xsl:sequence select="$part/db:authorgroup|$part/db:author"/>
        <xsl:sequence select="$part/db:title"/>
        <xsl:sequence select="$part/db:subtitle"/>
      </db:biblioset>
      <db:biblioset relation="book">
        <xsl:sequence select="$book/db:title"/>
        <xsl:sequence select="$book/db:subtitle"/>
        <xsl:sequence select="$book/db:bibliomisc[contains-token(@role, 'medium')]"/>
        <xsl:sequence select="$book/db:publisher"/>
        <xsl:sequence select="$book/db:pubdate"/>
        <xsl:sequence select="$book/db:date[contains-token(@role, 'cit')]"/>
        <xsl:sequence select="$book/db:biblioid"/>
      </db:biblioset>
    </db:biblioentry>
  </xsl:variable>

  <p>
    <xsl:apply-templates select="$entry/db:biblioentry" mode="m:attributes">
      <xsl:with-param name="style" select="'iso690'"/>
    </xsl:apply-templates>
    <xsl:apply-templates select="$entry/db:biblioentry/*"/>
  </p>
</xsl:template>

<xsl:template match="db:biblioentry">
  <p>
    <xsl:apply-templates select="." mode="m:attributes"/>
    <xsl:apply-templates/>
  </p>
</xsl:template>

<xsl:template match="db:biblioset">
  <xsl:if test="preceding-sibling::db:biblioset and @relation = 'book'">
    <xsl:sequence select="f:l10n-token(., 'In')"/>
    <xsl:text> </xsl:text>
  </xsl:if>
  <span>
    <xsl:apply-templates select="." mode="m:attributes"/>
    <xsl:apply-templates/>
  </span>
</xsl:template>

<xsl:template match="db:authorgroup">
  <span>
    <xsl:apply-templates select="." mode="m:attributes"/>
    <xsl:apply-templates select="." mode="m:gentext-list">
      <xsl:with-param name="list" as="element()*">
        <xsl:apply-templates select="*"/>
      </xsl:with-param>
    </xsl:apply-templates>
  </span>
  <xsl:sequence select="fp:optional-sep(*[last()], 'primary.sep')"/>
</xsl:template>

<xsl:template match="db:author">
  <span>
    <xsl:apply-templates select="." mode="m:attributes"/>
    <xsl:apply-templates select="*"/>
  </span>
  <xsl:if test="not(parent::db:authorgroup)">
    <xsl:sequence select="fp:optional-sep(., 'primary.sep')"/>
  </xsl:if>
</xsl:template>

<xsl:template match="db:personname">
  <span>
    <xsl:apply-templates select="." mode="m:attributes"/>
    <xsl:apply-templates select="db:surname"/>
    <xsl:sequence select="fp:iso690(., 'lastfirst.sep')"/>
    <xsl:apply-templates select="db:firstname|db:givenname"/>
  </span>
</xsl:template>

<xsl:template match="db:title">
  <em>
    <xsl:apply-templates select="." mode="m:attributes"/>
    <xsl:apply-templates/>
  </em>
  <xsl:apply-templates select="." mode="mp:biblio690-punct"/>
</xsl:template>

<xsl:template match="db:biblioset[@relation='article']/db:title
                     |db:biblioset[@relation='part']/db:title">
  <span>
    <xsl:apply-templates select="." mode="m:attributes"/>
    <xsl:apply-templates/>
  </span>
  <xsl:apply-templates select="." mode="mp:biblio690-punct"/>
</xsl:template>

<xsl:template match="db:title" mode="mp:biblio690-punct">
  <xsl:choose>
    <xsl:when test="following-sibling::db:bibliomisc[contains-token(@role, 'medium')]">
      <!-- nop -->
    </xsl:when>
    <xsl:when test="following-sibling::db:subtitle">
      <xsl:sequence select="fp:optional-sep(., 'submaintitle.sep')"/>
    </xsl:when>
    <xsl:otherwise>
      <xsl:sequence select="fp:optional-sep(., 'title.sep')"/>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

<xsl:template match="db:subtitle">
  <span>
    <xsl:apply-templates select="." mode="m:attributes"/>
    <xsl:apply-templates/>
  </span>
  <xsl:sequence select="fp:optional-sep(., 'title.sep')"/>
</xsl:template>

<xsl:template match="db:bibliomisc[contains-token(@role, 'secondary')]">
  <span>
    <xsl:apply-templates select="." mode="m:attributes"/>
    <xsl:apply-templates/>
  </span>
  <xsl:variable name="fs" select="following-sibling::*[1]"/>
  <xsl:choose>
    <xsl:when test="$fs/self::db:bibliomisc and contains-token($fs/@role, 'secondary')">
      <xsl:sequence select="fp:iso690(., 'secondary.person.sep')"/>
    </xsl:when>
    <xsl:otherwise>
      <xsl:sequence select="fp:optional-sep(., 'secondary.sep')"/>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

<xsl:template match="db:bibliomisc[contains-token(@role, 'serie')]">
  <span>
    <xsl:apply-templates select="." mode="m:attributes"/>
    <xsl:apply-templates/>
  </span>
  <xsl:sequence select="fp:optional-sep(., 'serie.sep')"/>
</xsl:template>

<xsl:template match="db:bibliomisc[contains-token(@role, 'patenttype')]">
  <span>
    <xsl:apply-templates select="." mode="m:attributes"/>
    <xsl:apply-templates/>
  </span>
  <xsl:sequence select="fp:optional-sep(., 'pattype.sep')"/>
</xsl:template>

<xsl:template match="db:bibliomisc[contains-token(@role, 'medium')]">
  <xsl:sequence select="fp:iso690(., 'medium1')"/>
  <span>
    <xsl:apply-templates select="." mode="m:attributes"/>
    <xsl:apply-templates/>
  </span>
  <xsl:sequence select="fp:iso690(., 'medium2')"/>
  <xsl:sequence select="fp:iso690(., 'title.sep')"/>
</xsl:template>

<xsl:template match="db:bibliomisc">
  <span>
    <xsl:apply-templates select="." mode="m:attributes"/>
    <xsl:apply-templates/>
  </span>
  <xsl:sequence select="fp:optional-sep(., 'primary.sep')"/> <!-- ??? -->
</xsl:template>

<xsl:template match="db:edition">
  <span>
    <xsl:apply-templates select="." mode="m:attributes"/>
    <xsl:apply-templates/>
  </span>
  <xsl:sequence select="fp:optional-sep(., 'edition.sep')"/>
</xsl:template>

<xsl:template match="db:volumenum">
  <span>
    <xsl:apply-templates select="." mode="m:attributes"/>
    <xsl:apply-templates/>
  </span>
  <xsl:sequence select="if ((following-sibling::db:issuenum)
                            or (following-sibling::db:pagenums))
                        then fp:iso690(., 'edition.serial.sep')
                        else fp:optional-sep(., 'edition.sep')"/>
</xsl:template>

<xsl:template match="db:issuenum">
  <span>
    <xsl:apply-templates select="." mode="m:attributes"/>
    <xsl:apply-templates/>
  </span>
  <xsl:choose>
    <xsl:when test="following-sibling::*[1]/self::db:date[contains-token(@role, 'cit')]">
      <!-- nop -->
    </xsl:when>
    <xsl:when test="following-sibling::db:pagenums">
      <xsl:sequence select="fp:iso690(., 'edition.serial.sep')"/>
    </xsl:when>
    <xsl:otherwise>
      <xsl:sequence select="fp:optional-sep(., 'edition.sep')"/>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

<xsl:template match="db:publisher">
  <span>
    <xsl:apply-templates select="." mode="m:attributes"/>
    <xsl:if test="db:address/db:city">
      <xsl:apply-templates select="db:address/db:city"/>
      <xsl:sequence select="fp:iso690(., 'placepubl.sep')"/>
    </xsl:if>
    <xsl:apply-templates select="db:publishername"/>
  </span>
  <xsl:choose>
    <xsl:when test="following-sibling::*[1]/self::db:pubdate">
      <xsl:sequence select="fp:iso690(., 'publyear.sep')"/>
    </xsl:when>
    <xsl:otherwise>
      <xsl:sequence select="fp:optional-sep(., 'pubinfo.sep')"/>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

<xsl:template match="db:pubdate">
  <span>
    <xsl:apply-templates select="." mode="m:attributes"/>
    <xsl:apply-templates/>
    <xsl:if test="ends-with(normalize-space(.), '-')
                  or ends-with(normalize-space(.), '—')">
      <xsl:text> </xsl:text>
    </xsl:if>
  </span>
  <xsl:choose>
    <xsl:when test="following-sibling::*[1]/self::db:date[contains-token(@role, 'cit')]">
      <!-- nop -->
    </xsl:when>
    <xsl:otherwise>
      <xsl:sequence select="if (following-sibling::db:volumenum)
                            then fp:iso690(., 'edition.serial.sep')
                            else fp:optional-sep(., 'pubinfo.sep')"/>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

<xsl:template match="db:date[contains-token(@role, 'cit')]">
  <xsl:sequence select="fp:iso690(., 'datecit1')"/>
  <span>
    <xsl:apply-templates select="." mode="m:attributes"/>
    <xsl:apply-templates/>
  </span>
  <xsl:sequence select="fp:iso690(., 'datecit2')"/>
  <xsl:sequence select="if (following-sibling::db:pagenums)
                        then fp:iso690(., 'edition.serial.sep')
                        else fp:optional-sep(., 'pubinfo.sep')"/>
</xsl:template>

<xsl:template match="db:pagenums">
  <span>
    <xsl:apply-templates select="." mode="m:attributes"/>
    <xsl:apply-templates/>
  </span>
  <xsl:sequence select="fp:optional-sep(., 'primary.sep')"/> <!-- ??? -->
</xsl:template>

<xsl:template match="db:biblioid[contains-token(@class, 'uri')]">
  <span>
    <xsl:apply-templates select="." mode="m:attributes"/>
    <xsl:choose>
      <xsl:when test="preceding-sibling::db:biblioid[contains-token(@class, 'uri')]">
        <xsl:sequence select="fp:iso690(., 'acctoo')"/>
        <xsl:apply-templates/>
        <xsl:if test="empty(node())">
          <xsl:sequence select="if (starts-with(@xlink:href, 'http'))
                                then fp:iso690(., 'onwww')
                                else fp:iso690(., 'oninet')"/>
        </xsl:if>
        <xsl:text>: </xsl:text>
        <xsl:sequence select="fp:iso690(., 'link1')"/>
        <xsl:sequence select="string(@xlink:href)"/>
        <xsl:sequence select="fp:iso690(., 'link2')"/>
      </xsl:when>
      <xsl:otherwise>
        <xsl:sequence select="fp:iso690(., 'access')"/>
        <xsl:apply-templates/>
        <xsl:if test="empty(node())">
          <xsl:sequence select="if (starts-with(@xlink:href, 'http'))
                                then fp:iso690(., 'onwww')
                                else fp:iso690(., 'oninet')"/>
        </xsl:if>
        <xsl:text>: </xsl:text>
        <xsl:sequence select="fp:iso690(., 'link1')"/>
        <xsl:sequence select="string(@xlink:href)"/>
        <xsl:sequence select="fp:iso690(., 'link2')"/>
      </xsl:otherwise>
    </xsl:choose>
    <xsl:sequence select="fp:optional-sep(., 'primary.sep')"/> <!-- ??? -->
  </span>
</xsl:template>

<xsl:template match="db:biblioid">
  <span>
    <xsl:apply-templates select="." mode="m:attributes"/>
    <xsl:choose>
      <xsl:when test="@class = 'isbn'">
        <xsl:sequence select="fp:iso690(., 'isbn')"/>
      </xsl:when>
      <xsl:when test="@class = 'issn'">
        <xsl:sequence select="fp:iso690(., 'issn')"/>
      </xsl:when>
      <xsl:otherwise/>
    </xsl:choose>
    <xsl:apply-templates/>
  </span>
  <xsl:sequence select="if (contains-token(@otherclass, 'patentnum'))
                        then fp:optional-sep(., 'patnum.sep')
                        else fp:optional-sep(., 'primary.sep')"/> <!-- ??? -->
</xsl:template>

<xsl:template match="db:surname|db:firstname|db:givenname
                     |db:city|db:publishername">
  <span>
    <xsl:apply-templates select="." mode="m:attributes"/>
    <xsl:apply-templates/>
  </span>
</xsl:template>

<xsl:template match="db:biblioentry[contains-token(@role, 'patent')]/db:address">
  <xsl:if test="db:country">
    <span>
      <xsl:apply-templates select="db:country" mode="m:attributes"/>
      <xsl:apply-templates select="db:country/node()"/>
    </span>
    <xsl:text> </xsl:text>
  </xsl:if>
</xsl:template>

<!-- ============================================================ -->

<xsl:template match="db:*">
  <xsl:apply-templates select="." mode="m:docbook"/>
</xsl:template>

<!-- ============================================================ -->

<xsl:function name="fp:iso690" as="item()*">
  <xsl:param name="context" as="element()"/>
  <xsl:param name="key" as="xs:string"/>

  <xsl:sequence select="f:l10n-token($context, 'iso690.'||$key)"/>
</xsl:function>

<xsl:function name="fp:optional-sep" as="item()*">
  <xsl:param name="context" as="element()"/>
  <xsl:param name="key" as="xs:string"/>

  <xsl:choose>
    <xsl:when test="ends-with(normalize-space($context), '.')">
      <xsl:text> </xsl:text>
    </xsl:when>
    <xsl:otherwise>
      <xsl:sequence select="f:l10n-token($context, 'iso690.'||$key)"/>
    </xsl:otherwise>
  </xsl:choose>
</xsl:function>

</xsl:stylesheet>

glossary.xsl

10 templates

Instructions
Template match ≅ db:glossary|db:glossdiv|db:glo…
Mode: m:docbook
Matches: db:glossary, db:glossdiv, db:glosslist
Template match ≅ db:glossentry
Mode: m:docbook
Matches: db:glossentry
Template match ≅ db:glossterm
Calls: t:inline
Mode: m:docbook
Matches: db:glossterm
Template match ≅ db:glossentry/db:glossterm
Mode: m:docbook
Matches: db:glossentry/db:glossterm
Template match ≅ db:glossentry/db:acronym
Mode: m:docbook
Matches: db:glossentry/db:acronym
Template match ≅ db:glossentry/db:abbrev
Mode: m:docbook
Matches: db:glossentry/db:abbrev
Template match ≅ db:glosssee
Calls: f:href()
Mode: m:docbook
Matches: db:glosssee
Template match ≅ db:glossentry/db:glossdef
Mode: m:docbook
Matches: db:glossentry/db:glossdef
Template match ≅ db:glossseealso
Mode: m:docbook
Matches: db:glossseealso
Template match ≅ db:glossseealso
Calls: f:href()
Mode: m:docbook
Matches: db:glossseealso
Source code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:db="http://docbook.org/ns/docbook"
                xmlns:f="http://docbook.org/ns/docbook/functions"
                xmlns:fp="http://docbook.org/ns/docbook/functions/private"
                xmlns:m="http://docbook.org/ns/docbook/modes"
                xmlns:t="http://docbook.org/ns/docbook/templates"
                xmlns:vp="http://docbook.org/ns/docbook/variables/private"
                xmlns:xs="http://www.w3.org/2001/XMLSchema"
                xmlns="http://www.w3.org/1999/xhtml"
                default-mode="m:docbook"
                exclude-result-prefixes="db f fp m t vp xs"
                version="3.0">

<xsl:key name="glossterm" match="db:glossentry"
         use="(db:glossterm/@baseform, db:glossterm/normalize-space(.))[1]"/>

<xsl:template match="db:glossary|db:glossdiv|db:glosslist">
  <xsl:variable name="gi" select="if (parent::*)
                                  then 'div'
                                  else 'article'"/>
  <xsl:element name="{$gi}" namespace="http://www.w3.org/1999/xhtml">
    <xsl:apply-templates select="." mode="m:attributes"/>
    <xsl:apply-templates select="." mode="m:generate-titlepage"/>
    <xsl:apply-templates select="* except (db:glossentry|db:bibliography)"/>
    <dl class="{local-name(.)}">
      <xsl:choose>
        <xsl:when test="$glossary-sort-entries">
          <xsl:apply-templates select="db:glossentry">
            <xsl:sort select="(@sortas, normalize-space(db:glossterm[1]))[1]"
                      collation="{$sort-collation}"/>
          </xsl:apply-templates>
        </xsl:when>
        <xsl:otherwise>
          <xsl:apply-templates select="db:glossentry"/>
        </xsl:otherwise>
      </xsl:choose>
    </dl>
    <xsl:apply-templates select="db:bibliography"/>
  </xsl:element>
</xsl:template>

<xsl:template match="db:glossentry">
  <dt>
    <xsl:apply-templates select="." mode="m:attributes"/>
    <xsl:apply-templates select="db:glossterm|db:indexterm"/>
  </dt>
  <xsl:apply-templates select="db:glosssee|db:glossdef"/>
</xsl:template>

<xsl:template match="db:glossterm">
  <xsl:call-template name="t:inline"/>
</xsl:template>

<xsl:template match="db:glossentry/db:glossterm">
  <span>
    <xsl:apply-templates select="." mode="m:attributes"/>
    <xsl:apply-templates/>
  </span>
  <xsl:if test="following-sibling::db:glossterm">
    <xsl:apply-templates select="." mode="m:gentext">
      <xsl:with-param name="group" select="'separator'"/>
    </xsl:apply-templates>
  </xsl:if>
</xsl:template>

<xsl:template match="db:glossentry/db:acronym">
  <span>
    <xsl:apply-templates select="." mode="m:attributes"/>
    <xsl:apply-templates/>
  </span>
  <xsl:if test="following-sibling::db:acronym
                |following-sibling::db:abbrev">
    <xsl:apply-templates select="." mode="m:gentext">
      <xsl:with-param name="group" select="'separator'"/>
    </xsl:apply-templates>
  </xsl:if>
</xsl:template>

<xsl:template match="db:glossentry/db:abbrev">
  <span>
    <xsl:apply-templates select="." mode="m:attributes"/>
    <xsl:apply-templates/>
  </span>
  <xsl:if test="following-sibling::db:acronym
                |following-sibling::db:abbrev">
    <xsl:apply-templates select="." mode="m:gentext">
      <xsl:with-param name="group" select="'separator'"/>
    </xsl:apply-templates>
  </xsl:if>
</xsl:template>

<xsl:template match="db:glosssee">
  <xsl:variable name="target"
                select="(key('id', @otherterm),
                         key('glossterm', normalize-space(.)))[1]"/>

  <dd>
    <xsl:apply-templates select="." mode="m:attributes"/>
    <p>
      <xsl:apply-templates select="." mode="m:gentext">
        <xsl:with-param name="group" select="'see'"/>
        <xsl:with-param name="content">
          <xsl:choose>
            <xsl:when test="$target">
              <a href="{f:href(., $target)}">
                <xsl:apply-templates/>
              </a>
            </xsl:when>
            <xsl:when test="@otherterm and not($target)">
              <xsl:message>
                <xsl:text>Warning: </xsl:text>
                <xsl:text>glosssee @otherterm reference not found: </xsl:text>
                <xsl:value-of select="@otherterm"/>
              </xsl:message>
              <xsl:apply-templates/>
            </xsl:when>
            <xsl:otherwise>
              <xsl:apply-templates/>
            </xsl:otherwise>
          </xsl:choose>
        </xsl:with-param>
      </xsl:apply-templates>
      <xsl:text>.</xsl:text>
    </p>
  </dd>
</xsl:template>

<xsl:template match="db:glossentry/db:glossdef">
  <dd>
    <xsl:apply-templates select="." mode="m:attributes"/>
    <xsl:apply-templates select="*[not(self::db:glossseealso)]"/>
  </dd>
  <xsl:apply-templates select="db:glossseealso"/>
</xsl:template>

<xsl:template match="db:glossseealso[preceding-sibling::db:glossseealso]"/>
<xsl:template match="db:glossseealso">
  <dd>
    <p>
      <xsl:variable name="targets" as="element()+">
        <xsl:for-each select="(., following-sibling::db:glossseealso)">
          <xsl:variable name="target"
                        select="if (key('id', @otherterm))
                                then key('id', @otherterm)[1]
                                else key('glossterm', string(.))"/>
          <xsl:choose>
            <xsl:when test="$target">
              <a href="{f:href(/,$target)}">
                <xsl:apply-templates select="$target" mode="m:crossref"/>
              </a>
            </xsl:when>
            <xsl:when test="@otherterm and not($target)">
              <xsl:message>
                <xsl:text>Warning: </xsl:text>
                <xsl:text>glossseealso @otherterm reference not found: </xsl:text>
                <xsl:value-of select="@otherterm"/>
              </xsl:message>
              <span>
                <xsl:apply-templates/>
              </span>
            </xsl:when>
            <xsl:otherwise>
              <span>
                <xsl:apply-templates/>
              </span>
            </xsl:otherwise>
          </xsl:choose>
        </xsl:for-each>
      </xsl:variable>

      <xsl:apply-templates select="." mode="m:gentext-list">
        <xsl:with-param name="list" select="$targets"/>
        <xsl:with-param name="name" select="'glossary-seealso'"/>
      </xsl:apply-templates>
    </p>
  </dd>
</xsl:template>

<!-- ============================================================ -->

</xsl:stylesheet>

index.xsl

21 templates, 8 functions (1 unused)

Instructions
Template match ≅ db:indexterm
Mode: m:docbook
Matches: db:indexterm
Template match ≅ db:primary|db:secondary|db:see…
Mode: m:docbook
Matches: db:primary, db:secondary, db:see, db:seealso, db:tertiary
Template match ≅ db:index|db:indexdiv|db:setind…
Mode: m:docbook
Matches: db:index, db:indexdiv, db:setindex
Function fp:primary($indexterm as element(db:indexterm)) as xs:string
Function fp:secondary($indexterm as element(db:indexterm)) as xs:string
Function fp:tertiary($indexterm as element(db:indexterm)) as xs:string
Function fp:scope($node as