comparison software/eXist/webapp/mpdl/_stuff/futureDev/html2fop.xsl @ 7:5589d865af7a

Erstellung XQL/XSL Applikation
author Josef Willenborg <jwillenborg@mpiwg-berlin.mpg.de>
date Tue, 08 Feb 2011 15:16:46 +0100
parents
children
comparison
equal deleted inserted replaced
6:2396a569e446 7:5589d865af7a
1 <?xml version="1.0"?>
2 <xsl:stylesheet
3 version="1.0"
4 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
5 xmlns:fo="http://www.w3.org/1999/XSL/Format"
6 xmlns:fox="http://xml.apache.org/fop/extensions">
7
8 <!-- ============================================
9 This stylesheet transforms most of the common
10 HTML elements into XSL formatting objects.
11
12 This version written 1 November 2002 by
13 Doug Tidwell, dtidwell@us.ibm.com.
14
15 Brought to you by your friends at developerWorks:
16 ibm.com/developerWorks.
17 =============================================== -->
18
19 <!-- ============================================
20 This variable sets the size of the page. If
21 it's 'ltr', we an 8.5 x 11 inch page; otherwise,
22 we use an A4-sized page. 'ltr' is the default.
23 To change the value, you can make the following
24 line read select="'A4'", or you can check the
25 documentation for your XSLT processor to see
26 how to set variables externally to the style
27 sheet. (For Xalan, add "-PARAM page-size a4"
28 to the command.)
29 =============================================== -->
30
31 <xsl:variable name="page-size" select="'ltr'"/>
32
33 <xsl:template match="html">
34
35 <!-- ============================================
36 Because character entities aren't built into
37 the XSL-FO vocabulary, they're included here.
38 =============================================== -->
39
40 <xsl:text disable-output-escaping="yes">
41 &lt;!DOCTYPE fo:root [
42 &lt;!ENTITY tilde "&amp;#126;"&gt;
43 &lt;!ENTITY florin "&amp;#131;"&gt;
44 &lt;!ENTITY elip "&amp;#133;"&gt;
45 &lt;!ENTITY dag "&amp;#134;"&gt;
46 &lt;!ENTITY ddag "&amp;#135;"&gt;
47 &lt;!ENTITY cflex "&amp;#136;"&gt;
48 &lt;!ENTITY permil "&amp;#137;"&gt;
49 &lt;!ENTITY uscore "&amp;#138;"&gt;
50 &lt;!ENTITY OElig "&amp;#140;"&gt;
51 &lt;!ENTITY lsquo "&amp;#145;"&gt;
52 &lt;!ENTITY rsquo "&amp;#146;"&gt;
53 &lt;!ENTITY ldquo "&amp;#147;"&gt;
54 &lt;!ENTITY rdquo "&amp;#148;"&gt;
55 &lt;!ENTITY bullet "&amp;#149;"&gt;
56 &lt;!ENTITY endash "&amp;#150;"&gt;
57 &lt;!ENTITY emdash "&amp;#151;"&gt;
58 &lt;!ENTITY trade "&amp;#153;"&gt;
59 &lt;!ENTITY oelig "&amp;#156;"&gt;
60 &lt;!ENTITY Yuml "&amp;#159;"&gt;
61
62 &lt;!ENTITY nbsp "&amp;#160;"&gt;
63 &lt;!ENTITY iexcl "&amp;#161;"&gt;
64 &lt;!ENTITY cent "&amp;#162;"&gt;
65 &lt;!ENTITY pound "&amp;#163;"&gt;
66 &lt;!ENTITY curren "&amp;#164;"&gt;
67 &lt;!ENTITY yen "&amp;#165;"&gt;
68 &lt;!ENTITY brvbar "&amp;#166;"&gt;
69 &lt;!ENTITY sect "&amp;#167;"&gt;
70 &lt;!ENTITY uml "&amp;#168;"&gt;
71 &lt;!ENTITY copy "&amp;#169;"&gt;
72 &lt;!ENTITY ordf "&amp;#170;"&gt;
73 &lt;!ENTITY laquo "&amp;#171;"&gt;
74 &lt;!ENTITY not "&amp;#172;"&gt;
75 &lt;!ENTITY shy "&amp;#173;"&gt;
76 &lt;!ENTITY reg "&amp;#174;"&gt;
77 &lt;!ENTITY macr "&amp;#175;"&gt;
78 &lt;!ENTITY deg "&amp;#176;"&gt;
79 &lt;!ENTITY plusmn "&amp;#177;"&gt;
80 &lt;!ENTITY sup2 "&amp;#178;"&gt;
81 &lt;!ENTITY sup3 "&amp;#179;"&gt;
82 &lt;!ENTITY acute "&amp;#180;"&gt;
83 &lt;!ENTITY micro "&amp;#181;"&gt;
84 &lt;!ENTITY para "&amp;#182;"&gt;
85 &lt;!ENTITY middot "&amp;#183;"&gt;
86 &lt;!ENTITY cedil "&amp;#184;"&gt;
87 &lt;!ENTITY sup1 "&amp;#185;"&gt;
88 &lt;!ENTITY ordm "&amp;#186;"&gt;
89 &lt;!ENTITY raquo "&amp;#187;"&gt;
90 &lt;!ENTITY frac14 "&amp;#188;"&gt;
91 &lt;!ENTITY frac12 "&amp;#189;"&gt;
92 &lt;!ENTITY frac34 "&amp;#190;"&gt;
93 &lt;!ENTITY iquest "&amp;#191;"&gt;
94 &lt;!ENTITY Agrave "&amp;#192;"&gt;
95 &lt;!ENTITY Aacute "&amp;#193;"&gt;
96 &lt;!ENTITY Acirc "&amp;#194;"&gt;
97 &lt;!ENTITY Atilde "&amp;#195;"&gt;
98 &lt;!ENTITY Auml "&amp;#196;"&gt;
99 &lt;!ENTITY Aring "&amp;#197;"&gt;
100 &lt;!ENTITY AElig "&amp;#198;"&gt;
101 &lt;!ENTITY Ccedil "&amp;#199;"&gt;
102 &lt;!ENTITY Egrave "&amp;#200;"&gt;
103 &lt;!ENTITY Eacute "&amp;#201;"&gt;
104 &lt;!ENTITY Ecirc "&amp;#202;"&gt;
105 &lt;!ENTITY Euml "&amp;#203;"&gt;
106 &lt;!ENTITY Igrave "&amp;#204;"&gt;
107 &lt;!ENTITY Iacute "&amp;#205;"&gt;
108 &lt;!ENTITY Icirc "&amp;#206;"&gt;
109 &lt;!ENTITY Iuml "&amp;#207;"&gt;
110 &lt;!ENTITY ETH "&amp;#208;"&gt;
111 &lt;!ENTITY Ntilde "&amp;#209;"&gt;
112 &lt;!ENTITY Ograve "&amp;#210;"&gt;
113 &lt;!ENTITY Oacute "&amp;#211;"&gt;
114 &lt;!ENTITY Ocirc "&amp;#212;"&gt;
115 &lt;!ENTITY Otilde "&amp;#213;"&gt;
116 &lt;!ENTITY Ouml "&amp;#214;"&gt;
117 &lt;!ENTITY times "&amp;#215;"&gt;
118 &lt;!ENTITY Oslash "&amp;#216;"&gt;
119 &lt;!ENTITY Ugrave "&amp;#217;"&gt;
120 &lt;!ENTITY Uacute "&amp;#218;"&gt;
121 &lt;!ENTITY Ucirc "&amp;#219;"&gt;
122 &lt;!ENTITY Uuml "&amp;#220;"&gt;
123 &lt;!ENTITY Yacute "&amp;#221;"&gt;
124 &lt;!ENTITY THORN "&amp;#222;"&gt;
125 &lt;!ENTITY szlig "&amp;#223;"&gt;
126 &lt;!ENTITY agrave "&amp;#224;"&gt;
127 &lt;!ENTITY aacute "&amp;#225;"&gt;
128 &lt;!ENTITY acirc "&amp;#226;"&gt;
129 &lt;!ENTITY atilde "&amp;#227;"&gt;
130 &lt;!ENTITY auml "&amp;#228;"&gt;
131 &lt;!ENTITY aring "&amp;#229;"&gt;
132 &lt;!ENTITY aelig "&amp;#230;"&gt;
133 &lt;!ENTITY ccedil "&amp;#231;"&gt;
134 &lt;!ENTITY egrave "&amp;#232;"&gt;
135 &lt;!ENTITY eacute "&amp;#233;"&gt;
136 &lt;!ENTITY ecirc "&amp;#234;"&gt;
137 &lt;!ENTITY euml "&amp;#235;"&gt;
138 &lt;!ENTITY igrave "&amp;#236;"&gt;
139 &lt;!ENTITY iacute "&amp;#237;"&gt;
140 &lt;!ENTITY icirc "&amp;#238;"&gt;
141 &lt;!ENTITY iuml "&amp;#239;"&gt;
142 &lt;!ENTITY eth "&amp;#240;"&gt;
143 &lt;!ENTITY ntilde "&amp;#241;"&gt;
144 &lt;!ENTITY ograve "&amp;#242;"&gt;
145 &lt;!ENTITY oacute "&amp;#243;"&gt;
146 &lt;!ENTITY ocirc "&amp;#244;"&gt;
147 &lt;!ENTITY otilde "&amp;#245;"&gt;
148 &lt;!ENTITY ouml "&amp;#246;"&gt;
149 &lt;!ENTITY oslash "&amp;#248;"&gt;
150 &lt;!ENTITY ugrave "&amp;#249;"&gt;
151 &lt;!ENTITY uacute "&amp;#250;"&gt;
152 &lt;!ENTITY ucirc "&amp;#251;"&gt;
153 &lt;!ENTITY uuml "&amp;#252;"&gt;
154 &lt;!ENTITY yacute "&amp;#253;"&gt;
155 &lt;!ENTITY thorn "&amp;#254;"&gt;
156 &lt;!ENTITY yuml "&amp;#255;"&gt;
157 ]&gt;
158 </xsl:text>
159
160 <!-- ============================================
161 The XSL-FO section starts here....
162 =============================================== -->
163
164 <fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format"
165 xmlns:fox="http://xml.apache.org/fop/extensions">
166
167 <!-- ============================================
168 Define the page layouts. There are two sets of
169 three page mastters here; we use one set for
170 letter-sized paper, the other set for A4.
171 =============================================== -->
172
173 <fo:layout-master-set>
174 <xsl:choose>
175 <xsl:when test="$page-size='ltr'">
176 <fo:simple-page-master master-name="first"
177 page-height="11in" page-width="8.5in"
178 margin-right="72pt" margin-left="72pt"
179 margin-bottom="36pt" margin-top="72pt">
180 <fo:region-body margin-bottom="50pt"/>
181 <fo:region-after region-name="ra-right"
182 extent="25pt"/>
183 </fo:simple-page-master>
184
185 <fo:simple-page-master master-name="left"
186 page-height="11in" page-width="8.5in"
187 margin-right="72pt" margin-left="72pt"
188 margin-bottom="36pt" margin-top="36pt">
189 <fo:region-before region-name="rb-left"
190 extent="25pt"/>
191 <fo:region-body margin-top="50pt"
192 margin-bottom="50pt"/>
193 <fo:region-after region-name="ra-left"
194 extent="25pt"/>
195 </fo:simple-page-master>
196
197 <fo:simple-page-master master-name="right"
198 page-height="11in" page-width="8.5in"
199 margin-right="72pt" margin-left="72pt"
200 margin-bottom="36pt" margin-top="36pt">
201 <fo:region-before region-name="rb-right"
202 extent="25pt"/>
203 <fo:region-body margin-top="50pt"
204 margin-bottom="50pt"/>
205 <fo:region-after region-name="ra-right"
206 extent="25pt"/>
207 </fo:simple-page-master>
208 </xsl:when>
209
210 <!-- ============================================
211 Page layouts for A4-sized paper
212 =============================================== -->
213
214 <xsl:otherwise>
215 <fo:simple-page-master master-name="first"
216 page-height="29.7cm" page-width="21cm"
217 margin-right="72pt" margin-left="72pt"
218 margin-bottom="36pt" margin-top="72pt">
219 <fo:region-body margin-top="1.5cm"
220 margin-bottom="1.5cm"/>
221 <fo:region-after region-name="ra-right"
222 extent="1cm"/>
223 </fo:simple-page-master>
224
225 <fo:simple-page-master master-name="left"
226 page-height="29.7cm" page-width="21cm"
227 margin-right="72pt" margin-left="72pt"
228 margin-bottom="36pt" margin-top="36pt">
229 <fo:region-before region-name="rb-left"
230 extent="3cm"/>
231 <fo:region-body margin-top="1.5cm"
232 margin-bottom="1.5cm"/>
233 <fo:region-after region-name="ra-left"
234 extent="1cm"/>
235 </fo:simple-page-master>
236
237 <fo:simple-page-master master-name="right"
238 page-height="29.7cm" page-width="21cm"
239 margin-right="72pt" margin-left="72pt"
240 margin-bottom="36pt" margin-top="36pt">
241 <fo:region-before region-name="rb-right"
242 extent="3cm"/>
243 <fo:region-body margin-top="1.5cm"
244 margin-bottom="1.5cm"/>
245 <fo:region-after region-name="ra-right"
246 extent="1cm"/>
247 </fo:simple-page-master>
248 </xsl:otherwise>
249 </xsl:choose>
250
251 <!-- ============================================
252 Now we define how we use the page layouts. One
253 is for the first page, one is for the even-
254 numbered pages, and one is for odd-numbered pages.
255 =============================================== -->
256
257 <fo:page-sequence-master master-name="standard">
258 <fo:repeatable-page-master-alternatives>
259 <fo:conditional-page-master-reference
260 master-reference="first"
261 page-position="first"/>
262 <fo:conditional-page-master-reference
263 master-reference="left"
264 odd-or-even="even"/>
265 <fo:conditional-page-master-reference
266 master-reference="right"
267 odd-or-even="odd"/>
268 </fo:repeatable-page-master-alternatives>
269 </fo:page-sequence-master>
270
271 </fo:layout-master-set>
272
273 <!-- ============================================
274 Now that we've defined all of the page layouts,
275 we generate the bookmarks for the PDF file.
276 =============================================== -->
277
278 <xsl:call-template name="generate-bookmarks"/>
279
280 <!-- ============================================
281 This is where the actual content of the document
282 starts.
283 =============================================== -->
284
285 <fo:page-sequence master-reference="standard">
286
287 <!-- ============================================
288 We define the static content for the headers
289 and footers of the various page layouts first.
290 =============================================== -->
291
292 <fo:static-content flow-name="rb-right">
293 <fo:block font-size="10pt" text-align-last="end">
294 <fo:table table-layout="fixed">
295 <fo:table-column column-width="396pt"/>
296 <fo:table-column column-width="72pt"/>
297 <fo:table-body>
298 <fo:table-row>
299 <fo:table-cell>
300 <fo:block text-align="start">
301 developerWorks loves you!
302 </fo:block>
303 </fo:table-cell>
304 <fo:table-cell>
305 <fo:block text-align="end" font-weight="bold"
306 font-family="monospace">
307 ibm.com/developerWorks
308 </fo:block>
309 </fo:table-cell>
310 </fo:table-row>
311 </fo:table-body>
312 </fo:table>
313 </fo:block>
314 </fo:static-content>
315 <fo:static-content flow-name="ra-right">
316 <fo:block font-size="10pt" text-align-last="end">
317 <fo:table table-layout="fixed">
318 <fo:table-column column-width="396pt"/>
319 <fo:table-column column-width="72pt"/>
320 <fo:table-body>
321 <fo:table-row>
322 <fo:table-cell>
323 <fo:block text-align="start">
324 <xsl:value-of select="/html/head/title"/>
325 </fo:block>
326 </fo:table-cell>
327 <fo:table-cell>
328 <fo:block text-align="end">Page
329 <fo:page-number/> of
330 <fo:page-number-citation
331 ref-id="TheVeryLastPage"/>
332 </fo:block>
333 </fo:table-cell>
334 </fo:table-row>
335 </fo:table-body>
336 </fo:table>
337 </fo:block>
338 </fo:static-content>
339 <fo:static-content flow-name="rb-left">
340 <fo:block font-size="10pt" text-align-last="end">
341 <fo:table table-layout="fixed">
342 <fo:table-column column-width="72pt"/>
343 <fo:table-column column-width="396pt"/>
344 <fo:table-body>
345 <fo:table-row>
346 <fo:table-cell>
347 <fo:block text-align="start" font-weight="bold"
348 font-family="monospace">
349 ibm.com/developerWorks
350 </fo:block>
351 </fo:table-cell>
352 <fo:table-cell>
353 <fo:block text-align="end">
354 developerWorks loves you!
355 </fo:block>
356 </fo:table-cell>
357 </fo:table-row>
358 </fo:table-body>
359 </fo:table>
360 </fo:block>
361 </fo:static-content>
362 <fo:static-content flow-name="ra-left">
363 <fo:block font-size="10pt" text-align-last="end">
364 <fo:table table-layout="fixed">
365 <fo:table-column column-width="72pt"/>
366 <fo:table-column column-width="396pt"/>
367 <fo:table-body>
368 <fo:table-row>
369 <fo:table-cell>
370 <fo:block text-align="start">Page
371 <fo:page-number/>
372 of <fo:page-number-citation
373 ref-id="TheVeryLastPage"/>
374 </fo:block>
375 </fo:table-cell>
376 <fo:table-cell>
377 <fo:block text-align="end">
378 <xsl:value-of select="/html/head/title"/>
379 </fo:block>
380 </fo:table-cell>
381 </fo:table-row>
382 </fo:table-body>
383 </fo:table>
384 </fo:block>
385 </fo:static-content>
386
387 <xsl:apply-templates select="body"/>
388 </fo:page-sequence>
389 </fo:root>
390 </xsl:template>
391
392 <!-- ============================================
393 Templates for individual HTML elements begin
394 here.
395 =============================================== -->
396
397 <!-- ============================================
398 Processing for the anchor tag is complex. First
399 of all, if this is a named anchor, we write an empty
400 <fo:block> with the appropriate id. (In the special
401 case that the next element is an <h1>, we ignore
402 the element altogether and put the id on the <h1>.)
403 Next, if this is a regular anchor and the href
404 starts with a hash mark (#), we create a link with
405 an internal-destination. Otherwise, we create a
406 link with an external destination.
407 =============================================== -->
408
409 <xsl:template match="a">
410 <xsl:choose>
411 <xsl:when test="@name">
412 <xsl:if test="not(name(following-sibling::*[1]) = 'h1')">
413 <fo:block line-height="0pt" space-after="0pt"
414 font-size="0pt" id="{@name}"/>
415 </xsl:if>
416 </xsl:when>
417 <xsl:when test="@href">
418 <fo:basic-link color="blue">
419 <xsl:choose>
420 <xsl:when test="starts-with(@href, '#')">
421 <xsl:attribute name="internal-destination">
422 <xsl:value-of select="substring(@href, 2)"/>
423 </xsl:attribute>
424 </xsl:when>
425 <xsl:otherwise>
426 <xsl:attribute name="external-destination">
427 <xsl:value-of select="@href"/>
428 </xsl:attribute>
429 </xsl:otherwise>
430 </xsl:choose>
431 <xsl:apply-templates select="*|text()"/>
432 </fo:basic-link>
433 <xsl:if test="starts-with(@href, '#')">
434 <xsl:text> on page </xsl:text>
435 <fo:page-number-citation ref-id="{substring(@href, 2)}"/>
436 </xsl:if>
437 </xsl:when>
438 </xsl:choose>
439 </xsl:template>
440
441 <!-- ============================================
442 We render an address element in italics.
443 =============================================== -->
444
445 <xsl:template match="address">
446 <fo:block font-style="italic" space-after="12pt">
447 <xsl:apply-templates select="*|text()"/>
448 </fo:block>
449 </xsl:template>
450
451 <!-- ============================================
452 For bold elements, we just change the font-weight.
453 =============================================== -->
454
455 <xsl:template match="b">
456 <fo:inline font-weight="bold">
457 <xsl:apply-templates select="*|text()"/>
458 </fo:inline>
459 </xsl:template>
460
461 <!-- ============================================
462 The big element is handled with a relative
463 font size. That means a <big> element inside
464 another <big> element will be even bigger, just
465 as it is in HTML.
466 =============================================== -->
467
468 <xsl:template match="big">
469 <fo:inline font-size="120%">
470 <xsl:apply-templates select="*|text()"/>
471 </fo:inline>
472 </xsl:template>
473
474 <!-- ============================================
475 A blockquote is indented on both sides.
476 =============================================== -->
477
478 <xsl:template match="blockquote">
479 <fo:block start-indent="1.5cm" end-indent="1.5cm"
480 space-after="12pt">
481 <xsl:apply-templates select="*|text()"/>
482 </fo:block>
483 </xsl:template>
484
485 <!-- ============================================
486 The HTML <body> element contains everything in
487 the main part of the document. This is analogous
488 to the <fo:flow flow-name="xsl-region-body">
489 element, so we put the main document processing here.
490 =============================================== -->
491
492 <xsl:template match="body">
493
494 <!-- ============================================
495 Start generating the content for the main page
496 area (xsl-region-body).
497 =============================================== -->
498
499 <fo:flow flow-name="xsl-region-body">
500 <xsl:apply-templates select="/html/head/title"/>
501 <fo:block space-after="12pt" line-height="17pt"
502 font-size="14pt" text-align="center">
503 developerWorks loves you!
504 </fo:block>
505 <fo:block space-after="24pt" line-height="17pt"
506 font-size="14pt" text-align="center" font-weight="bold"
507 font-family="monospace">
508 ibm.com/developerWorks
509 </fo:block>
510
511 <!-- ============================================
512 Now we call the template to build the table
513 of contents.
514 =============================================== -->
515
516 <xsl:call-template name="toc"/>
517
518 <!-- ============================================
519 This one line of code processes everything in
520 the body of the document. The template that
521 processes the <body> element in turn processes
522 everything that's inside it.
523 =============================================== -->
524
525 <xsl:apply-templates select="*|text()"/>
526
527 <!-- ============================================
528 We put an ID at the end of the document so we
529 can do "Page x of y" numbering.
530 =============================================== -->
531 <fo:block id="TheVeryLastPage" font-size="0pt"
532 line-height="0pt" space-after="0pt"/>
533
534 </fo:flow>
535 </xsl:template>
536
537 <!-- ============================================
538 We handle a break element by inserting an
539 empty <fo:block>.
540 =============================================== -->
541
542 <xsl:template match="br">
543 <fo:block> </fo:block>
544 </xsl:template>
545
546 <!-- ============================================
547 We're handling <center> as a block element; if
548 you use it, it creates a new paragraph that's
549 centered on the page.
550 =============================================== -->
551
552 <xsl:template match="center">
553 <fo:block text-align="center">
554 <xsl:apply-templates select="*|text()"/>
555 </fo:block>
556 </xsl:template>
557
558 <!-- ============================================
559 The <cite> element is rendered in italics,
560 unless it's inside an italic (<i>) element.
561 We use the parent axis to check this.
562 =============================================== -->
563
564 <xsl:template match="cite">
565 <xsl:choose>
566 <xsl:when test="parent::i">
567 <fo:inline font-style="normal">
568 <xsl:apply-templates select="*|text()"/>
569 </fo:inline>
570 </xsl:when>
571 <xsl:otherwise>
572 <fo:inline font-style="italic">
573 <xsl:apply-templates select="*|text()"/>
574 </fo:inline>
575 </xsl:otherwise>
576 </xsl:choose>
577 </xsl:template>
578
579 <!-- ============================================
580 We render <code> inline in a monospaced font.
581 =============================================== -->
582
583 <xsl:template match="code">
584 <fo:inline font-family="monospace">
585 <xsl:apply-templates select="*|text()"/>
586 </fo:inline>
587 </xsl:template>
588
589 <!-- ============================================
590 We don't do anything with the <dl> element, we
591 just handle the elements it contains. Notice
592 that we're ignoring any text that appears
593 in the <dl> itself; I'm not sure if that's
594 the right call.
595 =============================================== -->
596
597 <xsl:template match="dl">
598 <xsl:apply-templates select="*"/>
599 </xsl:template>
600
601 <!-- ============================================
602 A definition term is rendered in bold. We
603 specify keep-with-next here, although it doesn't
604 always work with FOP.
605 =============================================== -->
606
607 <xsl:template match="dt">
608 <fo:block font-weight="bold" space-after="2pt"
609 keep-with-next="always">
610 <xsl:apply-templates select="*|text()"/>
611 </fo:block>
612 </xsl:template>
613
614 <!-- ============================================
615 We handle each <dd> element as an indented block
616 beneath the defined term. If the following
617 element is another <dd>, that means it's another
618 definition for the same term. In that case,
619 we don't put as much vertical space after the
620 block.
621 =============================================== -->
622
623 <xsl:template match="dd">
624 <fo:block start-indent="1cm">
625 <xsl:attribute name="space-after">
626 <xsl:choose>
627 <xsl:when test="name(following::*[1]) = 'dd'">
628 <xsl:text>3pt</xsl:text>
629 </xsl:when>
630 <xsl:otherwise>
631 <xsl:text>12pt</xsl:text>
632 </xsl:otherwise>
633 </xsl:choose>
634 </xsl:attribute>
635 <xsl:apply-templates select="*|text()"/>
636 </fo:block>
637 </xsl:template>
638
639 <!-- ============================================
640 The HTML <em> element is typically rendered in
641 italics.
642 =============================================== -->
643
644 <xsl:template match="em">
645 <fo:inline font-style="italic">
646 <xsl:apply-templates select="*|text()"/>
647 </fo:inline>
648 </xsl:template>
649
650 <!-- ============================================
651 For the <font> element, we handle the color,
652 face, and size attributes. Color will work if
653 it's one of the twelve colors supported by XSL-FO
654 or it's a hex value like x0033ff. (In other words,
655 if you tell FOP to set the color to PapayaWhip,
656 you're out of luck.) The face attribute will
657 work if FOP supports it. (There are ways to add
658 fonts to FOP, see the FOP documentation for more
659 info.) Size is supported for values like
660 size="14pt", size="3", and size="+3".
661 =============================================== -->
662
663 <xsl:template match="font">
664 <xsl:variable name="color">
665 <xsl:choose>
666 <xsl:when test="@color">
667 <xsl:value-of select="@color"/>
668 </xsl:when>
669 <xsl:otherwise>
670 <xsl:text>black</xsl:text>
671 </xsl:otherwise>
672 </xsl:choose>
673 </xsl:variable>
674 <xsl:variable name="face">
675 <xsl:choose>
676 <xsl:when test="@face">
677 <xsl:value-of select="@face"/>
678 </xsl:when>
679 <xsl:otherwise>
680 <xsl:text>sans-serif</xsl:text>
681 </xsl:otherwise>
682 </xsl:choose>
683 </xsl:variable>
684 <xsl:variable name="size">
685 <xsl:choose>
686 <xsl:when test="@size">
687 <xsl:choose>
688 <xsl:when test="contains(@size, 'pt')">
689 <xsl:text>@size</xsl:text>
690 </xsl:when>
691 <xsl:when test="@size = '+1'">
692 <xsl:text>110%</xsl:text>
693 </xsl:when>
694 <xsl:when test="@size = '+2'">
695 <xsl:text>120%</xsl:text>
696 </xsl:when>
697 <xsl:when test="@size = '+3'">
698 <xsl:text>130%</xsl:text>
699 </xsl:when>
700 <xsl:when test="@size = '+4'">
701 <xsl:text>140%</xsl:text>
702 </xsl:when>
703 <xsl:when test="@size = '+5'">
704 <xsl:text>150%</xsl:text>
705 </xsl:when>
706 <xsl:when test="@size = '+6'">
707 <xsl:text>175%</xsl:text>
708 </xsl:when>
709 <xsl:when test="@size = '+7'">
710 <xsl:text>200%</xsl:text>
711 </xsl:when>
712 <xsl:when test="@size = '-1'">
713 <xsl:text>90%</xsl:text>
714 </xsl:when>
715 <xsl:when test="@size = '-2'">
716 <xsl:text>80%</xsl:text>
717 </xsl:when>
718 <xsl:when test="@size = '-3'">
719 <xsl:text>70%</xsl:text>
720 </xsl:when>
721 <xsl:when test="@size = '-4'">
722 <xsl:text>60%</xsl:text>
723 </xsl:when>
724 <xsl:when test="@size = '-5'">
725 <xsl:text>50%</xsl:text>
726 </xsl:when>
727 <xsl:when test="@size = '-6'">
728 <xsl:text>40%</xsl:text>
729 </xsl:when>
730 <xsl:when test="@size = '-7'">
731 <xsl:text>30%</xsl:text>
732 </xsl:when>
733 <xsl:when test="@size = '1'">
734 <xsl:text>8pt</xsl:text>
735 </xsl:when>
736 <xsl:when test="@size = '2'">
737 <xsl:text>10pt</xsl:text>
738 </xsl:when>
739 <xsl:when test="@size = '3'">
740 <xsl:text>12pt</xsl:text>
741 </xsl:when>
742 <xsl:when test="@size = '4'">
743 <xsl:text>14pt</xsl:text>
744 </xsl:when>
745 <xsl:when test="@size = '5'">
746 <xsl:text>18pt</xsl:text>
747 </xsl:when>
748 <xsl:when test="@size = '6'">
749 <xsl:text>24pt</xsl:text>
750 </xsl:when>
751 <xsl:when test="@size = '7'">
752 <xsl:text>36pt</xsl:text>
753 </xsl:when>
754 <xsl:otherwise>
755 <xsl:text>12pt</xsl:text>
756 </xsl:otherwise>
757 </xsl:choose>
758 </xsl:when>
759 <xsl:otherwise>
760 <xsl:text>12pt</xsl:text>
761 </xsl:otherwise>
762 </xsl:choose>
763 </xsl:variable>
764 <fo:inline font-size="{$size}" font-family="{$face}"
765 color="{$color}">
766 <xsl:apply-templates select="*|text()"/>
767 </fo:inline>
768 </xsl:template>
769
770 <!-- ============================================
771 We render the <h1> by putting a horizontal rule
772 and a page break before it. We also process
773 the id attribute; if the <h1> tag has one, we
774 use it. If not, we see if the preceding element
775 is a named anchor (<a name="x"/>). If there is
776 a named anchor before the <h1>, we use the name
777 of the anchor point as the id.
778 =============================================== -->
779
780 <xsl:template match="h1">
781 <fo:block break-before="page">
782 <fo:leader leader-pattern="rule"/>
783 </fo:block>
784 <fo:block font-size="28pt" line-height="32pt"
785 keep-with-next="always"
786 space-after="22pt" font-family="serif">
787 <xsl:attribute name="id">
788 <xsl:choose>
789 <xsl:when test="@id">
790 <xsl:value-of select="@id"/>
791 </xsl:when>
792 <xsl:when test="name(preceding-sibling::*[1]) = 'a' and
793 preceding-sibling::*[1][@name]">
794 <xsl:value-of select="preceding-sibling::*[1]/@name"/>
795 </xsl:when>
796 <xsl:otherwise>
797 <xsl:value-of select="generate-id()"/>
798 </xsl:otherwise>
799 </xsl:choose>
800 </xsl:attribute>
801 <xsl:apply-templates select="*|text()"/>
802 </fo:block>
803 </xsl:template>
804
805 <!-- ============================================
806 <h2> is in a slightly smaller font than an <h1>,
807 and it doesn't have a page break or a line.
808 =============================================== -->
809
810 <xsl:template match="h2">
811 <fo:block font-size="24pt" line-height="28pt"
812 keep-with-next="always" space-after="18pt"
813 font-family="serif">
814 <xsl:attribute name="id">
815 <xsl:choose>
816 <xsl:when test="@id">
817 <xsl:value-of select="@id"/>
818 </xsl:when>
819 <xsl:otherwise>
820 <xsl:value-of select="generate-id()"/>
821 </xsl:otherwise>
822 </xsl:choose>
823 </xsl:attribute>
824 <xsl:apply-templates select="*|text()"/>
825 </fo:block>
826 </xsl:template>
827
828 <!-- ============================================
829 <h3> is slightly smaller than <h2>.
830 =============================================== -->
831
832 <xsl:template match="h3">
833 <fo:block font-size="21pt" line-height="24pt"
834 keep-with-next="always" space-after="14pt"
835 font-family="serif">
836 <xsl:attribute name="id">
837 <xsl:choose>
838 <xsl:when test="@id">
839 <xsl:value-of select="@id"/>
840 </xsl:when>
841 <xsl:otherwise>
842 <xsl:value-of select="generate-id()"/>
843 </xsl:otherwise>
844 </xsl:choose>
845 </xsl:attribute>
846 <xsl:apply-templates select="*|text()"/>
847 </fo:block>
848 </xsl:template>
849
850 <!-- ============================================
851 <h4> is smaller than <h3>. For the bookmarks
852 and table of contents, <h4> is the lowest level
853 we include.
854 =============================================== -->
855
856 <xsl:template match="h4">
857 <fo:block font-size="18pt" line-height="21pt"
858 keep-with-next="always" space-after="12pt"
859 font-family="serif">
860 <xsl:attribute name="id">
861 <xsl:choose>
862 <xsl:when test="@id">
863 <xsl:value-of select="@id"/>
864 </xsl:when>
865 <xsl:otherwise>
866 <xsl:value-of select="generate-id()"/>
867 </xsl:otherwise>
868 </xsl:choose>
869 </xsl:attribute>
870 <xsl:apply-templates select="*|text()"/>
871 </fo:block>
872 </xsl:template>
873
874 <!-- ============================================
875 <h5> is pretty small, and is underlined to
876 help it stand out.
877 =============================================== -->
878
879 <xsl:template match="h5">
880 <fo:block font-size="16pt" line-height="19pt"
881 keep-with-next="always" space-after="12pt"
882 font-family="serif" text-decoration="underline">
883 <xsl:attribute name="id">
884 <xsl:choose>
885 <xsl:when test="@id">
886 <xsl:value-of select="@id"/>
887 </xsl:when>
888 <xsl:otherwise>
889 <xsl:value-of select="generate-id()"/>
890 </xsl:otherwise>
891 </xsl:choose>
892 </xsl:attribute>
893 <xsl:apply-templates select="*|text()"/>
894 </fo:block>
895 </xsl:template>
896
897 <!-- ============================================
898 <h6> is the smallest heading of all, and is
899 underlined and italicized.
900 =============================================== -->
901
902 <xsl:template match="h6">
903 <fo:block font-size="14pt" line-height="17pt"
904 keep-with-next="always" space-after="12pt"
905 font-family="serif" font-style="italic"
906 text-decoration="underline">
907 <xsl:attribute name="id">
908 <xsl:choose>
909 <xsl:when test="@id">
910 <xsl:value-of select="@id"/>
911 </xsl:when>
912 <xsl:otherwise>
913 <xsl:value-of select="generate-id()"/>
914 </xsl:otherwise>
915 </xsl:choose>
916 </xsl:attribute>
917 <xsl:apply-templates select="*|text()"/>
918 </fo:block>
919 </xsl:template>
920
921 <!-- ============================================
922 We render an <hr> with a leader. Because <hr>
923 is empty, we don't have to process any child
924 elements.
925 =============================================== -->
926
927 <xsl:template match="hr">
928 <fo:block>
929 <fo:leader leader-pattern="rule"/>
930 </fo:block>
931 </xsl:template>
932
933 <!-- ============================================
934 Italics. You can't get much simpler than that.
935 =============================================== -->
936
937 <xsl:template match="i">
938 <fo:inline font-style="italic">
939 <xsl:apply-templates select="*|text()"/>
940 </fo:inline>
941 </xsl:template>
942
943 <!-- ============================================
944 For the <img> element, we use the src attribute
945 as it comes from HTML. We also check for any
946 width and height attributes. If those attributes
947 are there, we try to use them; height="300px" is
948 used as-is, while height="300" is converted to
949 the value "300px".
950 =============================================== -->
951
952 <xsl:template match="img">
953 <fo:block space-after="12pt">
954 <fo:external-graphic src="{@src}">
955 <xsl:if test="@width">
956 <xsl:attribute name="width">
957 <xsl:choose>
958 <xsl:when test="contains(@width, 'px')">
959 <xsl:value-of select="@width"/>
960 </xsl:when>
961 <xsl:otherwise>
962 <xsl:value-of select="concat(@width, 'px')"/>
963 </xsl:otherwise>
964 </xsl:choose>
965 </xsl:attribute>
966 </xsl:if>
967 <xsl:if test="@height">
968 <xsl:attribute name="height">
969 <xsl:choose>
970 <xsl:when test="contains(@height, 'px')">
971 <xsl:value-of select="@height"/>
972 </xsl:when>
973 <xsl:otherwise>
974 <xsl:value-of select="concat(@height, 'px')"/>
975 </xsl:otherwise>
976 </xsl:choose>
977 </xsl:attribute>
978 </xsl:if>
979 </fo:external-graphic>
980 </fo:block>
981 </xsl:template>
982
983 <!-- ============================================
984 The <kbd> element is in a slightly larger
985 monospaced text.
986 =============================================== -->
987
988 <xsl:template match="kbd">
989 <fo:inline font-family="monospace" font-size="110%">
990 <xsl:apply-templates select="*|text()"/>
991 </fo:inline>
992 </xsl:template>
993
994 <!-- ============================================
995 We handle the <li> elements under the <ol> and
996 <ul> elements, so there's no <li> template here.
997 =============================================== -->
998
999 <!-- ============================================
1000 For the <nobr> element, we simply turn off the
1001 wrap-option.
1002 =============================================== -->
1003
1004 <xsl:template match="nobr">
1005 <fo:inline wrap-option="no-wrap">
1006 <xsl:apply-templates select="*|text()"/>
1007 </fo:inline>
1008 </xsl:template>
1009
1010 <!-- ============================================
1011 We handle an ordered list with two complications:
1012 If the list appears inside another list (either
1013 an <ol> or <ul>), we don't put any vertical space
1014 after it. The other issue is that we indent the
1015 list according to how deeply nested the list is.
1016 =============================================== -->
1017
1018 <xsl:template match="ol">
1019 <fo:list-block provisional-distance-between-starts="1cm"
1020 provisional-label-separation="0.5cm">
1021 <xsl:attribute name="space-after">
1022 <xsl:choose>
1023 <xsl:when test="ancestor::ul or ancestor::ol">
1024 <xsl:text>0pt</xsl:text>
1025 </xsl:when>
1026 <xsl:otherwise>
1027 <xsl:text>12pt</xsl:text>
1028 </xsl:otherwise>
1029 </xsl:choose>
1030 </xsl:attribute>
1031 <xsl:attribute name="start-indent">
1032 <xsl:variable name="ancestors">
1033 <xsl:choose>
1034 <xsl:when test="count(ancestor::ol) or count(ancestor::ul)">
1035 <xsl:value-of select="1 +
1036 (count(ancestor::ol) +
1037 count(ancestor::ul)) *
1038 1.25"/>
1039 </xsl:when>
1040 <xsl:otherwise>
1041 <xsl:text>1</xsl:text>
1042 </xsl:otherwise>
1043 </xsl:choose>
1044 </xsl:variable>
1045 <xsl:value-of select="concat($ancestors, 'cm')"/>
1046 </xsl:attribute>
1047 <xsl:apply-templates select="*"/>
1048 </fo:list-block>
1049 </xsl:template>
1050
1051 <!-- ============================================
1052 When we handle items in an ordered list, we need
1053 to check if the list has a start attribute. If
1054 it does, we change the starting number accordingly.
1055 Once we've figured out where to start counting,
1056 we check the type attribute to see what format
1057 the numbers should use.
1058 =============================================== -->
1059
1060 <xsl:template match="ol/li">
1061 <fo:list-item>
1062 <fo:list-item-label end-indent="label-end()">
1063 <fo:block>
1064 <xsl:variable name="value-attr">
1065 <xsl:choose>
1066 <xsl:when test="../@start">
1067 <xsl:number value="position() + ../@start - 1"/>
1068 </xsl:when>
1069 <xsl:otherwise>
1070 <xsl:number value="position()"/>
1071 </xsl:otherwise>
1072 </xsl:choose>
1073 </xsl:variable>
1074 <xsl:choose>
1075 <xsl:when test="../@type='i'">
1076 <xsl:number value="$value-attr" format="i. "/>
1077 </xsl:when>
1078 <xsl:when test="../@type='I'">
1079 <xsl:number value="$value-attr" format="I. "/>
1080 </xsl:when>
1081 <xsl:when test="../@type='a'">
1082 <xsl:number value="$value-attr" format="a. "/>
1083 </xsl:when>
1084 <xsl:when test="../@type='A'">
1085 <xsl:number value="$value-attr" format="A. "/>
1086 </xsl:when>
1087 <xsl:otherwise>
1088 <xsl:number value="$value-attr" format="1. "/>
1089 </xsl:otherwise>
1090 </xsl:choose>
1091 </fo:block>
1092 </fo:list-item-label>
1093 <fo:list-item-body start-indent="body-start()">
1094 <fo:block>
1095 <xsl:apply-templates select="*|text()"/>
1096 </fo:block>
1097 </fo:list-item-body>
1098 </fo:list-item>
1099 </xsl:template>
1100
1101 <!-- ============================================
1102 Your basic paragraph.
1103 =============================================== -->
1104
1105 <xsl:template match="p">
1106 <fo:block font-size="12pt" line-height="15pt"
1107 space-after="12pt">
1108 <xsl:apply-templates select="*|text()"/>
1109 </fo:block>
1110 </xsl:template>
1111
1112 <!-- ============================================
1113 Preformatted text is rendered in a monospaced
1114 font. We also have to set the wrap-option
1115 and white-space-collapse properties.
1116 =============================================== -->
1117
1118 <xsl:template match="pre">
1119 <fo:block font-family="monospace"
1120 white-space-collapse="false" wrap-option="no-wrap">
1121 <xsl:apply-templates select="*|text()"/>
1122 </fo:block>
1123 </xsl:template>
1124
1125 <!-- ============================================
1126 Sample text is rendered in a slightly larger
1127 monospaced font.
1128 =============================================== -->
1129
1130 <xsl:template match="samp">
1131 <fo:inline font-family="monospace" font-size="110%">
1132 <xsl:apply-templates select="*|text()"/>
1133 </fo:inline>
1134 </xsl:template>
1135
1136 <!-- ============================================
1137 The <small> element is rendered with a relative
1138 font size. That means putting one <small>
1139 element inside another creates really small
1140 text.
1141 =============================================== -->
1142
1143 <xsl:template match="small">
1144 <fo:inline font-size="80%">
1145 <xsl:apply-templates select="*|text()"/>
1146 </fo:inline>
1147 </xsl:template>
1148
1149 <!-- ============================================
1150 For strikethrough text, we use the text-decoration
1151 property.
1152 =============================================== -->
1153
1154 <xsl:template match="strike">
1155 <fo:inline text-decoration="line-through">
1156 <xsl:apply-templates select="*|text()"/>
1157 </fo:inline>
1158 </xsl:template>
1159
1160 <!-- ============================================
1161 Strongly emphasized text is simply rendered
1162 in bold.
1163 =============================================== -->
1164
1165 <xsl:template match="strong">
1166 <fo:inline font-weight="bold">
1167 <xsl:apply-templates select="*|text()"/>
1168 </fo:inline>
1169 </xsl:template>
1170
1171 <!-- ============================================
1172 For subscript text, we use the vertical-align
1173 property and decrease the font size.
1174 =============================================== -->
1175
1176 <xsl:template match="sub">
1177 <fo:inline vertical-align="sub" font-size="75%">
1178 <xsl:apply-templates select="*|text()"/>
1179 </fo:inline>
1180 </xsl:template>
1181
1182 <!-- ============================================
1183 Superscript text changes the vertical-align
1184 property also, and uses a smaller font.
1185 =============================================== -->
1186
1187 <xsl:template match="sup">
1188 <fo:inline vertical-align="super" font-size="75%">
1189 <xsl:apply-templates select="*|text()"/>
1190 </fo:inline>
1191 </xsl:template>
1192
1193 <!-- ============================================
1194 Tables are a hassle. The main problem we have
1195 is converting the cols attribute into some
1196 number of <fo:table-column> elements. We do
1197 this with a named template called build-columns.
1198 Once we've processed the cols attribute, we
1199 invoke all of the templates for the children
1200 of this element.
1201 =============================================== -->
1202
1203 <xsl:template match="table">
1204 <fo:table table-layout="fixed">
1205 <xsl:choose>
1206 <xsl:when test="@cols">
1207 <xsl:call-template name="build-columns">
1208 <xsl:with-param name="cols"
1209 select="concat(@cols, ' ')"/>
1210 </xsl:call-template>
1211 </xsl:when>
1212 <xsl:otherwise>
1213 <fo:table-column column-width="200pt"/>
1214 </xsl:otherwise>
1215 </xsl:choose>
1216 <fo:table-body>
1217 <xsl:apply-templates select="*"/>
1218 </fo:table-body>
1219 </fo:table>
1220 </xsl:template>
1221
1222 <!-- ============================================
1223 For a table cell, we put everything inside a
1224 <fo:table-cell> element. We set the padding
1225 property correctly, then we set the border
1226 style. For the border style, we look to see if
1227 any of the ancestor elements we care about
1228 specified a solid border. Next, we check for the
1229 rowspan, colspan, and align attributes. Notice
1230 that for align, we check this element, then go
1231 up the ancestor chain until we find the <table>
1232 element or we find something that specifies the
1233 alignment.
1234 =============================================== -->
1235
1236 <xsl:template match="td">
1237 <fo:table-cell
1238 padding-start="3pt" padding-end="3pt"
1239 padding-before="3pt" padding-after="3pt">
1240 <xsl:if test="@colspan">
1241 <xsl:attribute name="number-columns-spanned">
1242 <xsl:value-of select="@colspan"/>
1243 </xsl:attribute>
1244 </xsl:if>
1245 <xsl:if test="@rowspan">
1246 <xsl:attribute name="number-rows-spanned">
1247 <xsl:value-of select="@rowspan"/>
1248 </xsl:attribute>
1249 </xsl:if>
1250 <xsl:if test="@border='1' or
1251 ancestor::tr[@border='1'] or
1252 ancestor::thead[@border='1'] or
1253 ancestor::table[@border='1']">
1254 <xsl:attribute name="border-style">
1255 <xsl:text>solid</xsl:text>
1256 </xsl:attribute>
1257 <xsl:attribute name="border-color">
1258 <xsl:text>black</xsl:text>
1259 </xsl:attribute>
1260 <xsl:attribute name="border-width">
1261 <xsl:text>1pt</xsl:text>
1262 </xsl:attribute>
1263 </xsl:if>
1264 <xsl:variable name="align">
1265 <xsl:choose>
1266 <xsl:when test="@align">
1267 <xsl:choose>
1268 <xsl:when test="@align='center'">
1269 <xsl:text>center</xsl:text>
1270 </xsl:when>
1271 <xsl:when test="@align='right'">
1272 <xsl:text>end</xsl:text>
1273 </xsl:when>
1274 <xsl:when test="@align='justify'">
1275 <xsl:text>justify</xsl:text>
1276 </xsl:when>
1277 <xsl:otherwise>
1278 <xsl:text>start</xsl:text>
1279 </xsl:otherwise>
1280 </xsl:choose>
1281 </xsl:when>
1282 <xsl:when test="ancestor::tr[@align]">
1283 <xsl:choose>
1284 <xsl:when test="ancestor::tr/@align='center'">
1285 <xsl:text>center</xsl:text>
1286 </xsl:when>
1287 <xsl:when test="ancestor::tr/@align='right'">
1288 <xsl:text>end</xsl:text>
1289 </xsl:when>
1290 <xsl:when test="ancestor::tr/@align='justify'">
1291 <xsl:text>justify</xsl:text>
1292 </xsl:when>
1293 <xsl:otherwise>
1294 <xsl:text>start</xsl:text>
1295 </xsl:otherwise>
1296 </xsl:choose>
1297 </xsl:when>
1298 <xsl:when test="ancestor::thead">
1299 <xsl:text>center</xsl:text>
1300 </xsl:when>
1301 <xsl:when test="ancestor::table[@align]">
1302 <xsl:choose>
1303 <xsl:when test="ancestor::table/@align='center'">
1304 <xsl:text>center</xsl:text>
1305 </xsl:when>
1306 <xsl:when test="ancestor::table/@align='right'">
1307 <xsl:text>end</xsl:text>
1308 </xsl:when>
1309 <xsl:when test="ancestor::table/@align='justify'">
1310 <xsl:text>justify</xsl:text>
1311 </xsl:when>
1312 <xsl:otherwise>
1313 <xsl:text>start</xsl:text>
1314 </xsl:otherwise>
1315 </xsl:choose>
1316 </xsl:when>
1317 <xsl:otherwise>
1318 <xsl:text>start</xsl:text>
1319 </xsl:otherwise>
1320 </xsl:choose>
1321 </xsl:variable>
1322 <fo:block text-align="{$align}">
1323 <xsl:apply-templates select="*|text()"/>
1324 </fo:block>
1325 </fo:table-cell>
1326 </xsl:template>
1327
1328 <!-- ============================================
1329 The rarely-used <tfoot> element contains some
1330 number of <tr> elements; we just invoke the
1331 template for <tr> here.
1332 =============================================== -->
1333
1334 <xsl:template match="tfoot">
1335 <xsl:apply-templates select="tr"/>
1336 </xsl:template>
1337
1338 <!-- ============================================
1339 If there's a <th> element, we process it just
1340 like a normal <td>, except the font-weight is
1341 always bold and the text-align is always center.
1342 =============================================== -->
1343
1344 <xsl:template match="th">
1345 <fo:table-cell
1346 padding-start="3pt" padding-end="3pt"
1347 padding-before="3pt" padding-after="3pt">
1348 <xsl:if test="@border='1' or
1349 ancestor::tr[@border='1'] or
1350 ancestor::table[@border='1']">
1351 <xsl:attribute name="border-style">
1352 <xsl:text>solid</xsl:text>
1353 </xsl:attribute>
1354 <xsl:attribute name="border-color">
1355 <xsl:text>black</xsl:text>
1356 </xsl:attribute>
1357 <xsl:attribute name="border-width">
1358 <xsl:text>1pt</xsl:text>
1359 </xsl:attribute>
1360 </xsl:if>
1361 <fo:block font-weight="bold" text-align="center">
1362 <xsl:apply-templates select="*|text()"/>
1363 </fo:block>
1364 </fo:table-cell>
1365 </xsl:template>
1366
1367 <!-- ============================================
1368 Just like <tfoot>, the rarely-used <thead> element
1369 contains some number of table rows. We just
1370 invoke the template for <tr> here.
1371 =============================================== -->
1372
1373 <xsl:template match="thead">
1374 <xsl:apply-templates select="tr"/>
1375 </xsl:template>
1376
1377 <!-- ============================================
1378 The title of the document is rendered in a large
1379 bold font, centered on the page. This is the
1380 <title> element in the <head> in <html>.
1381 =============================================== -->
1382
1383 <xsl:template match="title">
1384 <fo:block space-after="18pt" line-height="27pt"
1385 font-size="24pt" font-weight="bold" text-align="center">
1386 <xsl:apply-templates select="*|text()"/>
1387 </fo:block>
1388 </xsl:template>
1389
1390 <!-- ============================================
1391 For an HTML table row, we create an XSL-FO table
1392 row, then invoke the templates for everything
1393 inside it.
1394 =============================================== -->
1395
1396 <xsl:template match="tr">
1397 <fo:table-row>
1398 <xsl:apply-templates select="*|text()"/>
1399 </fo:table-row>
1400 </xsl:template>
1401
1402 <!-- ============================================
1403 Teletype text is rendered in a monospaced font.
1404 =============================================== -->
1405
1406 <xsl:template match="tt">
1407 <fo:inline font-family="monospace">
1408 <xsl:apply-templates select="*|text()"/>
1409 </fo:inline>
1410 </xsl:template>
1411
1412 <!-- ============================================
1413 For underlined text, we use the text-decoration
1414 property.
1415 =============================================== -->
1416
1417 <xsl:template match="u">
1418 <fo:inline text-decoration="underline">
1419 <xsl:apply-templates select="*|text()"/>
1420 </fo:inline>
1421 </xsl:template>
1422
1423 <!-- ============================================
1424 The unordered list is pretty straightforward;
1425 the only complication is calculating the space-
1426 after and start-indent properties. If this
1427 list is inside another list, we don't put any
1428 space after this one, and we calculate the
1429 indentation based on the nesting level of this
1430 list.
1431 =============================================== -->
1432
1433 <xsl:template match="ul">
1434 <fo:list-block provisional-distance-between-starts="1cm"
1435 provisional-label-separation="0.5cm">
1436 <xsl:attribute name="space-after">
1437 <xsl:choose>
1438 <xsl:when test="ancestor::ul or ancestor::ol">
1439 <xsl:text>0pt</xsl:text>
1440 </xsl:when>
1441 <xsl:otherwise>
1442 <xsl:text>12pt</xsl:text>
1443 </xsl:otherwise>
1444 </xsl:choose>
1445 </xsl:attribute>
1446 <xsl:attribute name="start-indent">
1447 <xsl:variable name="ancestors">
1448 <xsl:choose>
1449 <xsl:when test="count(ancestor::ol) or count(ancestor::ul)">
1450 <xsl:value-of select="1 +
1451 (count(ancestor::ol) +
1452 count(ancestor::ul)) *
1453 1.25"/>
1454 </xsl:when>
1455 <xsl:otherwise>
1456 <xsl:text>1</xsl:text>
1457 </xsl:otherwise>
1458 </xsl:choose>
1459 </xsl:variable>
1460 <xsl:value-of select="concat($ancestors, 'cm')"/>
1461 </xsl:attribute>
1462 <xsl:apply-templates select="*"/>
1463 </fo:list-block>
1464 </xsl:template>
1465
1466 <!-- ============================================
1467 List items inside unordered lists are easy; we
1468 just have to use the correct Unicode character
1469 for the bullet.
1470 =============================================== -->
1471
1472 <xsl:template match="ul/li">
1473 <fo:list-item>
1474 <fo:list-item-label end-indent="label-end()">
1475 <fo:block>&#x2022;</fo:block>
1476 </fo:list-item-label>
1477 <fo:list-item-body start-indent="body-start()">
1478 <fo:block>
1479 <xsl:apply-templates select="*|text()"/>
1480 </fo:block>
1481 </fo:list-item-body>
1482 </fo:list-item>
1483 </xsl:template>
1484
1485 <!-- ============================================
1486 The <var> element is rendered in italics.
1487 =============================================== -->
1488
1489 <xsl:template match="var">
1490 <fo:inline font-style="italic">
1491 <xsl:apply-templates select="*|text()"/>
1492 </fo:inline>
1493 </xsl:template>
1494
1495 <!-- ============================================
1496 Named templates
1497 =============================================== -->
1498
1499 <!-- ============================================
1500 This template creates the table of contents.
1501 It indents each entry according to the heading
1502 level (<h1> isn't indented, <h2> is indented
1503 1 cm, etc.). We insert the title of each
1504 section as a link, put a leader of dots, then
1505 the page number. Notice that we generate an
1506 id for the heading if it doesn't have one
1507 already; this is done with the XSLT generate-id()
1508 function.
1509 =============================================== -->
1510
1511 <xsl:template name="toc">
1512 <fo:block>
1513 <fo:leader leader-pattern="rule" space-after="18pt"/>
1514 </fo:block>
1515 <fo:block space-after="12pt" id="TableOfContents"
1516 line-height="21pt" font-size="18pt" text-align="start">
1517 Table of Contents
1518 </fo:block>
1519 <fo:block line-height="11pt" font-size="8pt"
1520 space-after="6pt">
1521 If you're viewing this document online, you can
1522 click any of the topics below to link directly to
1523 that section.
1524 </fo:block>
1525 <xsl:for-each select="/html/body//h1 |
1526 /html/body//h2 |
1527 /html/body//h3 |
1528 /html/body//h4">
1529 <fo:block text-align-last="justify" line-height="17pt"
1530 font-size="14pt" space-after="3pt" text-align="start"
1531 text-indent="-1cm">
1532 <xsl:attribute name="start-indent">
1533 <xsl:choose>
1534 <xsl:when test="name() = 'h1'">
1535 <xsl:text>1cm</xsl:text>
1536 </xsl:when>
1537 <xsl:when test="name() = 'h2'">
1538 <xsl:text>1.5cm</xsl:text>
1539 </xsl:when>
1540 <xsl:when test="name() = 'h3'">
1541 <xsl:text>2cm</xsl:text>
1542 </xsl:when>
1543 <xsl:when test="name() = 'h4'">
1544 <xsl:text>2.5cm</xsl:text>
1545 </xsl:when>
1546 </xsl:choose>
1547 </xsl:attribute>
1548 <fo:basic-link color="blue">
1549 <xsl:attribute name="internal-destination">
1550 <xsl:choose>
1551 <xsl:when test="@id">
1552 <xsl:value-of select="@id"/>
1553 </xsl:when>
1554 <xsl:when test="name(preceding-sibling::*[1]) = 'a' and
1555 preceding-sibling::*[1][@name]">
1556 <xsl:value-of select="preceding-sibling::*[1]/@name"/>
1557 </xsl:when>
1558 <xsl:otherwise>
1559 <xsl:value-of select="generate-id()"/>
1560 </xsl:otherwise>
1561 </xsl:choose>
1562 </xsl:attribute>
1563 <xsl:apply-templates select="*|text()"/>
1564 </fo:basic-link>
1565 <fo:leader leader-pattern="dots"
1566 leader-pattern-width="5pt"/>
1567 <fo:page-number-citation>
1568 <xsl:attribute name="ref-id">
1569 <xsl:choose>
1570 <xsl:when test="@id">
1571 <xsl:value-of select="@id"/>
1572 </xsl:when>
1573 <xsl:when test="name(preceding-sibling::*[1]) = 'a' and
1574 preceding-sibling::*[1][@name]">
1575 <xsl:value-of select="preceding-sibling::*[1]/@name"/>
1576 </xsl:when>
1577 <xsl:otherwise>
1578 <xsl:value-of select="generate-id()"/>
1579 </xsl:otherwise>
1580 </xsl:choose>
1581 </xsl:attribute>
1582 </fo:page-number-citation>
1583 </fo:block>
1584 </xsl:for-each>
1585 </xsl:template>
1586
1587 <!-- ============================================
1588 This complicated template creates the PDF bookmarks
1589 supported by FOP. For each <h1> element, it
1590 creates a bookmark for that element, then it
1591 looks for all of the <h2> elements beneath it.
1592 For each <h2>, it looks for all the <h3>
1593 elements beneath it, etc. We use generate-id()
1594 extensively so we can determine whether a given
1595 <h1> or <h2> or <h3> is one we've seen before.
1596 The end result of all this hard work is a set of
1597 hierarchical bookmarks that are nested within each
1598 other.
1599 =============================================== -->
1600
1601 <xsl:template name="generate-bookmarks">
1602 <fox:outline internal-destination="TableOfContents">
1603 <fox:label>Table of Contents</fox:label>
1604 </fox:outline>
1605 <xsl:for-each select="/html/body//h1">
1606 <xsl:variable name="current-h1" select="generate-id()"/>
1607 <fox:outline>
1608 <xsl:attribute name="internal-destination">
1609 <xsl:choose>
1610 <xsl:when test="@id">
1611 <xsl:value-of select="@id"/>
1612 </xsl:when>
1613 <xsl:when test="name(preceding-sibling::*[1]) = 'a' and
1614 preceding-sibling::*[1][@name]">
1615 <xsl:value-of select="preceding-sibling::*[1]/@name"/>
1616 </xsl:when>
1617 <xsl:otherwise>
1618 <xsl:value-of select="generate-id()"/>
1619 </xsl:otherwise>
1620 </xsl:choose>
1621 </xsl:attribute>
1622 <fox:label>
1623 <xsl:value-of select="."/>
1624 </fox:label>
1625 <xsl:for-each select="following-sibling::h2">
1626 <xsl:variable name="current-h2" select="generate-id()"/>
1627 <xsl:if
1628 test="generate-id(preceding-sibling::h1[1]) = $current-h1">
1629 <fox:outline>
1630 <xsl:attribute name="internal-destination">
1631 <xsl:choose>
1632 <xsl:when test="@id">
1633 <xsl:value-of select="@id"/>
1634 </xsl:when>
1635 <xsl:otherwise>
1636 <xsl:value-of select="$current-h2"/>
1637 </xsl:otherwise>
1638 </xsl:choose>
1639 </xsl:attribute>
1640 <fox:label>
1641 <xsl:value-of select="."/>
1642 </fox:label>
1643 <xsl:for-each select="following-sibling::h3">
1644 <xsl:variable name="current-h3" select="generate-id()"/>
1645 <xsl:if
1646 test="generate-id(preceding-sibling::h2[1]) = $current-h2">
1647 <fox:outline>
1648 <xsl:attribute name="internal-destination">
1649 <xsl:choose>
1650 <xsl:when test="@id">
1651 <xsl:value-of select="@id"/>
1652 </xsl:when>
1653 <xsl:otherwise>
1654 <xsl:value-of select="$current-h2"/>
1655 </xsl:otherwise>
1656 </xsl:choose>
1657 </xsl:attribute>
1658 <fox:label>
1659 <xsl:value-of select="."/>
1660 </fox:label>
1661 <xsl:for-each select="following-sibling::h4">
1662 <xsl:if
1663 test="generate-id(preceding-sibling::h3[1]) = $current-h3">
1664 <fox:outline>
1665 <xsl:attribute name="internal-destination">
1666 <xsl:choose>
1667 <xsl:when test="@id">
1668 <xsl:value-of select="@id"/>
1669 </xsl:when>
1670 <xsl:otherwise>
1671 <xsl:value-of select="$current-h3"/>
1672 </xsl:otherwise>
1673 </xsl:choose>
1674 </xsl:attribute>
1675 <fox:label>
1676 <xsl:value-of select="."/>
1677 </fox:label>
1678 </fox:outline>
1679 </xsl:if>
1680 </xsl:for-each>
1681 </fox:outline>
1682 </xsl:if>
1683 </xsl:for-each>
1684 </fox:outline>
1685 </xsl:if>
1686 </xsl:for-each>
1687 </fox:outline>
1688 </xsl:for-each>
1689 </xsl:template>
1690
1691 <!-- ============================================
1692 This template generates an <fo:table-column>
1693 element for each token in the cols attribute of
1694 the HTML <table> tag. The template processes
1695 the first token, then invokes itself with the
1696 rest of the string.
1697 =============================================== -->
1698
1699 <xsl:template name="build-columns">
1700 <xsl:param name="cols"/>
1701
1702 <xsl:if test="string-length(normalize-space($cols))">
1703 <xsl:variable name="next-col">
1704 <xsl:value-of select="substring-before($cols, ' ')"/>
1705 </xsl:variable>
1706 <xsl:variable name="remaining-cols">
1707 <xsl:value-of select="substring-after($cols, ' ')"/>
1708 </xsl:variable>
1709 <xsl:choose>
1710 <xsl:when test="contains($next-col, 'pt')">
1711 <fo:table-column column-width="{$next-col}"/>
1712 </xsl:when>
1713 <xsl:when test="number($next-col) &gt; 0">
1714 <fo:table-column column-width="{concat($next-col, 'pt')}"/>
1715 </xsl:when>
1716 <xsl:otherwise>
1717 <fo:table-column column-width="50pt"/>
1718 </xsl:otherwise>
1719 </xsl:choose>
1720
1721 <xsl:call-template name="build-columns">
1722 <xsl:with-param name="cols" select="concat($remaining-cols, ' ')"/>
1723 </xsl:call-template>
1724 </xsl:if>
1725 </xsl:template>
1726
1727 </xsl:stylesheet>