comparison doc/wiki2docbook/html2db/html2db.xsl @ 1773:2ae81598b254

scripts for converting wiki documentation to docbook
author nadvornik
date Sun, 22 Nov 2009 09:12:22 +0000
parents
children
comparison
equal deleted inserted replaced
1772:9f3b7a089caf 1773:2ae81598b254
1 <?xml version="1.0" encoding="utf-8"?>
2 <!-- Copyright 2004 by Laszlo Systems, Inc.
3 Released under the Artistic License.
4 Written by Oliver Steele.
5 Version 1.0.1
6 http://osteele.com/sources/xslt/htm2db/
7 -->
8 <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
9 xmlns:exslt="http://exslt.org/common"
10 xmlns:java="http://xml.apache.org/xalan/java"
11 xmlns:math="http://exslt.org/math"
12 xmlns:db="urn:docbook"
13 xmlns:h="http://www.w3.org/1999/xhtml"
14 exclude-result-prefixes="exslt java math db h"
15 version="1.0">
16
17 <!-- Prefixed to every id generated from <a name=> and <a href="#"> -->
18 <xsl:param name="anchor-id-prefix" select="''"/>
19
20 <!-- Default document root; can be overridden by <?html2db class=> -->
21 <xsl:param name="document-root" select="'article'"/>
22
23 <xsl:include href="html2db-utils.xsl"/>
24
25 <!--
26 Default templates
27 -->
28
29 <!-- pass docbook elements through unchanged; just strip the prefix
30 -->
31 <xsl:template match="db:*">
32 <xsl:element name="{local-name()}">
33 <xsl:for-each select="@*">
34 <xsl:attribute name="{name()}">
35 <xsl:value-of select="."/>
36 </xsl:attribute>
37 </xsl:for-each>
38 <xsl:apply-templates/>
39 </xsl:element>
40 </xsl:template>
41
42 <xsl:template match="@id">
43 <xsl:copy/>
44 </xsl:template>
45
46 <!-- copy processing instructions, too -->
47 <xsl:template match="processing-instruction()">
48 <xsl:copy/>
49 </xsl:template>
50
51 <!-- except for html2db instructions -->
52 <xsl:template match="processing-instruction('html2db')"/>
53
54 <!-- Warn about any html elements that don't match a more
55 specific template. Copy them too, since it's often
56 easier to find them in the output. -->
57 <xsl:template match="h:*">
58 <xsl:message terminate="no">
59 Unknown element <xsl:value-of select="name()"/>
60 </xsl:message>
61 <xsl:copy>
62 <xsl:apply-templates/>
63 </xsl:copy>
64 </xsl:template>
65
66 <!--
67 Root element and body
68 -->
69
70 <!-- ignore everything except the body -->
71 <xsl:template match="/">
72 <xsl:apply-templates select="//h:body"/>
73 </xsl:template>
74
75 <xsl:template match="h:body">
76 <xsl:variable name="class-pi"
77 select="processing-instruction('html2db')[starts-with(string(), 'class=&quot;')][1]"/>
78 <xsl:variable name="class">
79 <xsl:choose>
80 <xsl:when test="count($class-pi)!=0">
81 <xsl:value-of select="substring-before(substring-after(string($class-pi[0]), 'class=&quot;'), '&quot;')"/>
82 </xsl:when>
83 <xsl:otherwise>
84 <xsl:value-of select="$document-root"/>
85 </xsl:otherwise>
86 </xsl:choose>
87 </xsl:variable>
88
89 <!-- Warn if there are any text nodes outside a para, etc. See
90 the note at the naked text template for why this is a
91 warning. -->
92 <xsl:if test="text()[normalize-space() != '']">
93 <xsl:message terminate="no">
94 Text must be inside a &lt;p&gt; tag.
95 </xsl:message>
96 </xsl:if>
97
98 <xsl:element name="{$class}">
99 <xsl:apply-templates select="@id"/>
100 <xsl:call-template name="section-content">
101 <xsl:with-param name="level" select="1"/>
102 <xsl:with-param name="nodes" select="//h:body/node()|//h:body/text()"/>
103 </xsl:call-template>
104 </xsl:element>
105 </xsl:template>
106
107 <!--
108 Section and section title processing
109 -->
110
111 <!--
112 Nest elements that *follow* an h1, h2, etc. into <section> elements
113 such that the <h1> content is the section's <title>.
114 -->
115 <xsl:template name="section-content">
116 <xsl:param name="level"/>
117 <xsl:param name="nodes"/>
118 <xsl:param name="h1" select="concat('h', $level)"/>
119 <xsl:param name="h2" select="concat('h', $level+1)"/>
120 <xsl:param name="h2-position" select="count(exslt:node-set($nodes)[1]/following-sibling::*[local-name()=$h2])"/>
121
122 <!-- copy up to first h2 -->
123 <xsl:apply-templates select="exslt:node-set($nodes)[
124 count(following-sibling::*[local-name()=$h2])=$h2-position
125 ]"/>
126
127 <!-- if section is empty, add an empty para so it will validate -->
128 <xsl:if test="not(exslt:node-set($nodes)/h:para[
129 count(following-sibling::*[local-name()=$h2])=$h2-position
130 ])">
131 <para/>
132 </xsl:if>
133
134 <!-- subsections -->
135 <xsl:for-each select="exslt:node-set($nodes)[local-name()=$h2]">
136 <section>
137 <xsl:variable name="mynodes" select="exslt:node-set($nodes)[
138 count(following-sibling::*[local-name()=$h2])=
139 count(current()/following-sibling::*[local-name()=$h2])]"/>
140 <xsl:for-each select="exslt:node-set($mynodes)[local-name()=$h2]">
141 <xsl:choose>
142 <xsl:when test="@id">
143 <xsl:apply-templates select="@id"/>
144 </xsl:when>
145 <xsl:when test="h:a/@name">
146 <xsl:attribute name="id">
147 <xsl:value-of select="concat($anchor-id-prefix, h:a/@name)"/>
148 </xsl:attribute>
149 </xsl:when>
150 </xsl:choose>
151 </xsl:for-each>
152 <xsl:call-template name="section-content">
153 <xsl:with-param name="level" select="$level+1"/>
154 <xsl:with-param name="nodes" select="exslt:node-set($nodes)[
155 count(following-sibling::*[local-name()=$h2])=
156 count(current()/following-sibling::*[local-name()=$h2])]"/>
157 </xsl:call-template>
158 </section>
159 </xsl:for-each>
160 </xsl:template>
161
162 <!--
163 Remove anchors from hn titles. section-content attaches these as ids
164 to the section (after mutilating them as described in the docs).
165 -->
166 <xsl:template match="h:h1|h:h2|h:h3|h:h4|h:h5|h:h6">
167 <title>
168 <xsl:apply-templates mode="skip-anchors" select="node()"/>
169 </title>
170 </xsl:template>
171
172 <xsl:template mode="skip-anchors" match="h:a[@name]">
173 <xsl:apply-templates/>
174 </xsl:template>
175
176 <xsl:template mode="skip-anchors" match="node()">
177 <xsl:apply-templates select="."/>
178 </xsl:template>
179
180 <!--
181 Inline elements
182 -->
183 <xsl:template match="h:b|h:i|h:em|h:strong">
184 <emphasis role="{local-name()}">
185 <xsl:apply-templates/>
186 </emphasis>
187 </xsl:template>
188
189 <xsl:template match="h:dfn">
190 <indexterm significance="preferred">
191 <primary><xsl:apply-templates/></primary>
192 </indexterm>
193 <glossterm><xsl:apply-templates/></glossterm>
194 </xsl:template>
195
196 <xsl:template match="h:var">
197 <replaceable><xsl:apply-templates/></replaceable>
198 </xsl:template>
199
200 <!--
201 Inline elements in code
202 -->
203 <xsl:template match="h:code/h:i|h:tt/h:i|h:pre/h:i">
204 <replaceable>
205 <xsl:apply-templates/>
206 </replaceable>
207 </xsl:template>
208
209 <xsl:template match="h:code|h:tt">
210 <literal>
211 <xsl:if test="@class">
212 <xsl:attribute name="role"><xsl:value-of select="@class"/></xsl:attribute>
213 </xsl:if>
214 <xsl:apply-templates/>
215 </literal>
216 </xsl:template>
217
218 <!-- For now, everything that doesn't have a specific match in inline
219 processing mode is matched against the default processing mode. -->
220 <xsl:template mode="inline" match="*">
221 <xsl:apply-templates select="."/>
222 </xsl:template>
223
224 <!--
225 Block elements
226 -->
227 <xsl:template match="h:p">
228 <para>
229 <xsl:apply-templates select="@id"/>
230 <xsl:apply-templates mode="inline"/>
231 </para>
232 </xsl:template>
233
234 <!-- Wrap naked text nodes in a <para> so that they'll process more
235 correctly. The h:body also warns about these, because even
236 this preprocessing step isn't guaranteed to fix them. This is
237 because "Some <i>italic</i> text" will be preprocessed into
238 "<para>Some </para> <emphasis>italic</emphasis><para>
239 text</para>" instead of "<para>Some <emphasis>italic</emphasis>
240 text</para>". Getting this right would require more work than
241 just maintaining the source documents. -->
242 <xsl:template match="h:body/text()[normalize-space()!= '']">
243 <!-- add an invalid tag to make it easy to find this in
244 the generated file -->
245 <naked-text>
246 <para>
247 <xsl:apply-templates/>
248 </para>
249 </naked-text>
250 </xsl:template>
251
252 <xsl:template match="h:body/h:code|h:pre">
253 <programlisting>
254 <xsl:apply-templates/>
255 </programlisting>
256 </xsl:template>
257
258 <xsl:template match="h:blockquote">
259 <blockquote>
260 <xsl:apply-templates mode="item" select="."/>
261 </blockquote>
262 </xsl:template>
263
264 <!--
265 Images
266 -->
267 <xsl:template name="imageobject">
268 <imageobject>
269 <imagedata fileref="{@src}">
270 <xsl:apply-templates select="@width|@height"/>
271 </imagedata>
272 </imageobject>
273 </xsl:template>
274
275 <xsl:template match="h:img/@width">
276 <xsl:copy/>
277 </xsl:template>
278
279 <xsl:template match="h:img">
280 <xsl:param name="informal">
281 <xsl:if test="not(@title) and not(db:title)">informal</xsl:if>
282 </xsl:param>
283 <xsl:element name="{$informal}figure">
284 <xsl:apply-templates select="@id"/>
285 <xsl:choose>
286 <xsl:when test="@title">
287 <title><xsl:value-of select="@title"/></title>
288 </xsl:when>
289 <xsl:otherwise>
290 <xsl:apply-templates select="db:title"/>
291 </xsl:otherwise>
292 </xsl:choose>
293 <mediaobject>
294 <xsl:call-template name="imageobject"/>
295 <xsl:if test="@alt and normalize-space(@alt)!=''">
296 <caption>
297 <para>
298 <xsl:value-of select="@alt"/>
299 </para>
300 </caption>
301 </xsl:if>
302 </mediaobject>
303 </xsl:element>
304 </xsl:template>
305
306 <xsl:template mode="inline" match="h:img">
307 <inlinemediaobject>
308 <xsl:apply-templates select="@id"/>
309 <xsl:call-template name="imageobject"/>
310 </inlinemediaobject>
311 </xsl:template>
312
313 <!--
314 links
315 -->
316
317 <!-- anchors -->
318 <xsl:template match="h:a[@name]">
319 <anchor id="{$anchor-id-prefix}{@name}"/>
320 <xsl:apply-templates/>
321 </xsl:template>
322
323 <!-- internal link -->
324 <xsl:template match="h:a[starts-with(@href, '#')]">
325 <link linkend="{$anchor-id-prefix}{substring-after(@href, '#')}">
326 <xsl:apply-templates select="@*"/>
327 <xsl:apply-templates/>
328 </link>
329 </xsl:template>
330
331 <!-- external link -->
332 <xsl:template match="h:a">
333 <ulink url="{@href}">
334 <xsl:apply-templates select="@*"/>
335 <xsl:apply-templates/>
336 </ulink>
337 </xsl:template>
338
339 <!-- email -->
340 <xsl:template match="h:a[starts-with(@href, 'mailto:')]">
341 <email>
342 <xsl:apply-templates select="@*"/>
343 <xsl:value-of select="substring-after(@href, 'mailto:')"/>
344 </email>
345 </xsl:template>
346
347 <!-- link attributes -->
348
349 <xsl:template match="h:a/@*"/>
350
351 <xsl:template match="h:a/@id">
352 <xsl:apply-templates select="@id"/>
353 </xsl:template>
354
355 <xsl:template match="h:a/@target|h:a/@link">
356 <xsl:processing-instruction name="db2html">
357 <xsl:text>attribute name="</xsl:text>
358 <xsl:value-of select="name()"/>
359 <xsl:text>" value=</xsl:text>
360 <xsl:call-template name="quote"/>
361 </xsl:processing-instruction>
362 </xsl:template>
363
364 <!--
365 lists
366 -->
367
368 <xsl:template match="h:dl">
369 <variablelist>
370 <xsl:apply-templates select="db:*"/>
371 <xsl:apply-templates select="h:dt"/>
372 </variablelist>
373 </xsl:template>
374
375 <xsl:template match="h:dt">
376 <xsl:variable name="item-number" select="count(preceding-sibling::h:dt)+1"/>
377 <varlistentry>
378 <term>
379 <xsl:apply-templates/>
380 </term>
381 <listitem>
382 <!-- Select the dd that follows this dt without an intervening dd -->
383 <xsl:apply-templates mode="item"
384 select="following-sibling::h:dd[
385 count(preceding-sibling::h:dt)=$item-number
386 ]"/>
387 <!-- If there is no such dd, then insert an empty para -->
388 <xsl:if test="count(following-sibling::h:dd[
389 count(preceding-sibling::h:dt)=$item-number
390 ])=0">
391 <para/>
392 </xsl:if>
393 </listitem>
394 </varlistentry>
395 </xsl:template>
396
397 <xsl:template mode="item" match="*[count(h:p) = 0]">
398 <para>
399 <xsl:apply-templates/>
400 </para>
401 </xsl:template>
402
403 <xsl:template mode="nonblank-nodes" match="node()">
404 <xsl:element name="{local-name()}"/>
405 </xsl:template>
406
407 <xsl:template mode="nonblank-nodes" match="text()[normalize-space()='']"/>
408
409 <xsl:template mode="nonblank-nodes" match="text()">
410 <text/>
411 </xsl:template>
412
413 <xsl:template mode="item" match="*">
414 <!-- Test whether the first non-blank node is not a p -->
415 <xsl:param name="nonblank-nodes">
416 <xsl:apply-templates mode="nonblank-nodes"/>
417 </xsl:param>
418
419 <xsl:param name="tested" select="
420 count(exslt:node-set($nonblank-nodes)/*) != 0 and
421 local-name(exslt:node-set($nonblank-nodes)/*[1]) != 'p'"/>
422
423 <xsl:param name="n1" select="count(*[1]/following::h:p)"/>
424 <xsl:param name="n2" select="count(text()[1]/following::h:p)"/>
425
426 <xsl:param name="n">
427 <xsl:if test="$tested">
428 <xsl:value-of select="java:java.lang.Math.max($n1, $n2)"/>
429 </xsl:if>
430 </xsl:param>
431
432 <xsl:if test="false()">
433 <nodeset tested="{$tested}" count="{count(exslt:node-set($nonblank-nodes)/*)}">
434 <xsl:for-each select="exslt:node-set($nonblank-nodes)/*">
435 <element name="{local-name()}"/>
436 </xsl:for-each>
437 </nodeset>
438 </xsl:if>
439
440 <!-- Wrap everything before the first p into a para -->
441 <xsl:if test="$tested">
442 <para>
443 <xsl:apply-templates select="
444 node()[count(following::h:p)=$n] |
445 text()[count(following::h:p)=$n]"/>
446 </para>
447 </xsl:if>
448 <xsl:apply-templates select="
449 node()[count(following::h:p)!=$n] |
450 text()[count(following::h:p)!=$n]"/>
451 </xsl:template>
452
453 <xsl:template match="h:ol">
454 <orderedlist spacing="compact">
455 <xsl:for-each select="h:li">
456 <listitem>
457 <xsl:apply-templates mode="item" select="."/>
458 </listitem>
459 </xsl:for-each>
460 </orderedlist>
461 </xsl:template>
462
463 <xsl:template match="h:ul">
464 <itemizedlist spacing="compact">
465 <xsl:for-each select="h:li">
466 <listitem>
467 <xsl:apply-templates mode="item" select="."/>
468 </listitem>
469 </xsl:for-each>
470 </itemizedlist>
471 </xsl:template>
472
473 <xsl:template match="h:ul[processing-instruction('html2db')]">
474 <simplelist>
475 <xsl:for-each select="h:li">
476 <member type="vert">
477 <xsl:apply-templates mode="item" select="."/>
478 </member>
479 </xsl:for-each>
480 </simplelist>
481 </xsl:template>
482
483 <!--
484 ignored markup
485 -->
486 <xsl:template match="h:br">
487 <xsl:processing-instruction name="db2html">
488 <xsl:text>element="</xsl:text>
489 <xsl:value-of select="local-name()"/>
490 <xsl:text>"</xsl:text>
491 </xsl:processing-instruction>
492 </xsl:template>
493
494 <xsl:template match="h:span|h:div">
495 <xsl:apply-templates select="*|node()|text()"/>
496 </xsl:template>
497
498 <!--
499 Utility functions and templates for tables
500 -->
501 <xsl:template mode="count-columns" match="h:tr">
502 <n>
503 <xsl:value-of select="count(h:td)"/>
504 </n>
505 </xsl:template>
506
507 <!-- tables -->
508 <xsl:template match="h:table">
509 <xsl:param name="informal">
510 <xsl:if test="not(@summary)">informal</xsl:if>
511 </xsl:param>
512 <xsl:param name="colcounts">
513 <xsl:apply-templates mode="count-columns" select=".//h:tr"/>
514 </xsl:param>
515 <xsl:param name="cols" select="math:max(exslt:node-set($colcounts)/n)"/>
516 <xsl:param name="sorted">
517 <xsl:for-each select="exslt:node-set($colcounts)/n">
518 <xsl:sort order="descending" data-type="number"/>
519 <n><xsl:value-of select="."/></n>
520 </xsl:for-each>
521 </xsl:param>
522 <xsl:element name="{$informal}table">
523 <xsl:apply-templates select="@id"/>
524 <xsl:if test="processing-instruction('html2db')[starts-with(., 'rowsep')]">
525 <xsl:attribute name="rowsep">1</xsl:attribute>
526 </xsl:if>
527 <xsl:apply-templates select="processing-instruction()"/>
528 <xsl:if test="@summary">
529 <title><xsl:value-of select="@summary"/></title>
530 </xsl:if>
531 <tgroup cols="{$cols}">
532 <xsl:if test=".//h:tr/h:th">
533 <thead>
534 <xsl:for-each select=".//h:tr[count(h:th)!=0]">
535 <row>
536 <xsl:apply-templates select="@id"/>
537 <xsl:for-each select="h:td|h:th">
538 <entry>
539 <xsl:apply-templates select="@id"/>
540 <xsl:apply-templates/>
541 </entry>
542 </xsl:for-each>
543 </row>
544 <xsl:text>&#10;</xsl:text> <!-- cr -->
545 </xsl:for-each>
546 </thead>
547 </xsl:if>
548 <tbody>
549 <xsl:for-each select=".//h:tr[count(h:th)=0]">
550 <row>
551 <xsl:apply-templates select="@id"/>
552 <xsl:for-each select="h:td|h:th">
553 <entry>
554 <xsl:apply-templates select="@id"/>
555 <xsl:apply-templates/>
556 </entry>
557 </xsl:for-each>
558 </row>
559 <xsl:text>&#10;</xsl:text> <!-- cr -->
560 </xsl:for-each>
561 </tbody>
562 </tgroup>
563 </xsl:element>
564 </xsl:template>
565 </xsl:stylesheet>