1773
|
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="')][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="'), '"')"/>
|
|
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 <p> 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> </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> </xsl:text> <!-- cr -->
|
|
560 </xsl:for-each>
|
|
561 </tbody>
|
|
562 </tgroup>
|
|
563 </xsl:element>
|
|
564 </xsl:template>
|
|
565 </xsl:stylesheet>
|