1<?xml version="1.0" encoding="utf-8"?>
2<!--
3  - DokuWiki xslfo plugin: Export single pages to PDF via XSL-FO.
4  -
5  - @license GPL 3 (http://www.gnu.org/licenses/gpl.html)
6  - @author Sam Wilson <sam@samwilson.id.au>
7  -->
8<xsl:stylesheet version="1.0"
9                xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
10                xmlns:fo="http://www.w3.org/1999/XSL/Format">
11    <xsl:variable name="tplincdir" select="document/dokuwiki/tplincdir/text()" />
12    <xsl:variable name="mediadir" select="document/dokuwiki/mediadir/text()" />
13
14    <xsl:template match="/">
15        <fo:root>
16
17            <fo:layout-master-set>
18                <fo:simple-page-master master-name="A4-portrait" page-height="29.7cm" page-width="21.0cm" margin="2cm">
19                    <fo:region-body margin-top="1.5cm" margin-bottom="1.5cm"/>
20                    <fo:region-before extent="2.0cm"/>
21                    <fo:region-after extent="2.0cm"/>
22                </fo:simple-page-master>
23            </fo:layout-master-set>
24
25            <fo:page-sequence master-reference="A4-portrait">
26
27                <fo:static-content flow-name="xsl-region-before">
28                    <fo:block>
29                        <xsl:call-template name="header"/>
30                    </fo:block>
31                </fo:static-content>
32
33                <fo:static-content flow-name="xsl-region-after">
34                    <fo:block>
35                        <xsl:call-template name="footer"/>
36                    </fo:block>
37                </fo:static-content>
38
39                <xsl:apply-templates select="document" />
40
41            </fo:page-sequence>
42
43        </fo:root>
44    </xsl:template>
45
46    <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
47    <!-- Begin header and footer -->
48    <xsl:template name="header">
49        <fo:block font-size="8pt" border-bottom="thin solid black">
50            <fo:block-container position="absolute">
51                <fo:block text-align="left">
52                    <xsl:value-of select="//header[@level='1']" />
53                </fo:block>
54            </fo:block-container>
55            <fo:block text-align="center">
56
57            </fo:block>
58            <fo:block-container position="absolute">
59                <fo:block text-align="right">
60                    <xsl:value-of select="//dokuwiki/lastmod/text()" />
61                </fo:block>
62            </fo:block-container>
63        </fo:block>
64    </xsl:template>
65    <xsl:template name="footer">
66        <fo:block font-size="8pt" border-top="thin solid black" text-align="center">
67            <fo:table table-layout="fixed">
68                <fo:table-body>
69                    <fo:table-row>
70                        <fo:table-cell>
71                            <fo:block text-align="left">
72                                <xsl:value-of select="//dokuwiki/url/text()" />
73                            </fo:block>
74                        </fo:table-cell>
75                        <fo:table-cell>
76                            <fo:block text-align="right">
77                                Page <fo:page-number/> of <fo:page-number-citation ref-id="document-end" />
78                            </fo:block>
79                        </fo:table-cell>
80                    </fo:table-row>
81                </fo:table-body>
82            </fo:table>
83        </fo:block>
84    </xsl:template>
85    <!-- End header and footer -->
86
87    <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
88    <!-- Document and sections -->
89    <xsl:template match="document">
90        <fo:flow flow-name="xsl-region-body">
91            <xsl:apply-templates />
92            <!-- End ID for total-page-count reference in header -->
93            <fo:block id="document-end"></fo:block>
94        </fo:flow>
95    </xsl:template>
96
97    <xsl:template match="section">
98        <fo:block>
99            <xsl:apply-templates />
100        </fo:block>
101    </xsl:template>
102
103    <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
104    <!-- Headings -->
105    <xsl:template match="header[@level='1']">
106        <fo:block font-size="20pt" line-height="15pt" space-before="15pt" space-after="12pt" text-align="center">
107            <xsl:apply-templates />
108        </fo:block>
109    </xsl:template>
110    <xsl:template match="header[@level='2']">
111        <fo:block font-size="17pt" line-height="15pt" space-before="15pt" space-after="12pt">
112            <xsl:apply-templates />
113        </fo:block>
114    </xsl:template>
115    <xsl:template match="header[@level='3']">
116        <fo:block font-size="12pt" space-before="15pt" space-after="5pt">
117            <xsl:apply-templates />
118        </fo:block>
119    </xsl:template>
120
121    <!-- Paragraphs -->
122    <xsl:template match="p">
123        <fo:block font-size="10pt" space-after="12pt">
124            <xsl:apply-templates />
125        </fo:block>
126    </xsl:template>
127
128    <!-- Inline elements: strong, emphasis, monospace, underline -->
129    <xsl:template match="strong">
130        <fo:inline font-weight="bold">
131            <xsl:apply-templates />
132        </fo:inline>
133    </xsl:template>
134
135    <xsl:template match="monospace">
136        <fo:inline font-family="monospace">
137            <xsl:apply-templates />
138        </fo:inline>
139    </xsl:template>
140
141    <xsl:template match="emphasis">
142        <fo:inline font-style="italic">
143            <xsl:apply-templates />
144        </fo:inline>
145    </xsl:template>
146
147    <xsl:template match="underline">
148        <fo:inline text-decoration="underline">
149            <xsl:apply-templates />
150        </fo:inline>
151    </xsl:template>
152
153    <xsl:template match="multiplyentity">
154        <fo:inline>
155            <xsl:value-of select="./x" />
156            <xsl:text>&#215;</xsl:text>
157            <xsl:value-of select="./y" />
158        </fo:inline>
159    </xsl:template>
160
161    <xsl:template match="preformatted|code">
162        <fo:block font-family="monospace" font-size="9pt" space-after="12pt"
163                  white-space-collapse="false" wrap-option="no-wrap" padding="3pt"
164                  linefeed-treatment="preserve" white-space-treatment="preserve">
165            <xsl:apply-templates />
166        </fo:block>
167    </xsl:template>
168    <xsl:template match="code">
169        <fo:block font-family="monospace" font-size="9pt" space-after="12pt"  padding="3pt"
170                  white-space-collapse="false" wrap-option="no-wrap" background-color="#efefef"
171                  linefeed-treatment="preserve" white-space-treatment="preserve">
172            <xsl:apply-templates />
173        </fo:block>
174    </xsl:template>
175    <xsl:template match="file">
176        <fo:block font-family="monospace" font-size="9pt" space-after="12pt"
177                  white-space-collapse="false" wrap-option="no-wrap" padding="3pt"
178                  linefeed-treatment="preserve" white-space-treatment="preserve" border="thin solid black">
179            <xsl:apply-templates />
180        </fo:block>
181    </xsl:template>
182
183    <xsl:template match="subscript">
184        <fo:inline vertical-align="sub" font-size="75%">
185            <xsl:apply-templates />
186        </fo:inline>
187    </xsl:template>
188
189    <xsl:template match="superscript">
190        <fo:inline vertical-align="super" font-size="75%">
191            <xsl:apply-templates />
192        </fo:inline>
193    </xsl:template>
194
195    <xsl:template match="delete">
196        <fo:inline text-decoration="line-through">
197            <xsl:apply-templates />
198        </fo:inline>
199    </xsl:template>
200
201    <xsl:template match="linebreak">
202        <fo:block></fo:block>
203    </xsl:template>
204
205    <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
206    <!-- Links -->
207    <xsl:template match="link">
208        <fo:basic-link color="blue">
209            <xsl:choose>
210                <xsl:when test="starts-with(@href, '#')">
211                    <xsl:attribute name="internal-destination">
212                        <xsl:value-of select="substring(@href, 2)"/>
213                    </xsl:attribute>
214                </xsl:when>
215                <xsl:otherwise>
216                    <xsl:attribute name="external-destination">
217                        <xsl:value-of select="@href"/>
218                    </xsl:attribute>
219                </xsl:otherwise>
220            </xsl:choose>
221            <xsl:apply-templates />
222        </fo:basic-link>
223    </xsl:template>
224
225    <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
226    <!-- Images and other attachments -->
227    <xsl:template match="media">
228        <xsl:variable name="src" select="@src" />
229        <xsl:variable name="ext" select="@ext" />
230        <xsl:variable name="width" select="@width" />
231        <xsl:variable name="height" select="@height" />
232        <xsl:variable name="filename">
233            <xsl:value-of select="//dokuwiki/media_filename[@src=$src and @width=$width and @height=$height]/text()" />
234        </xsl:variable>
235        <fo:inline>
236            <fo:basic-link color="blue">
237                <xsl:attribute name="external-destination">
238                    <xsl:value-of select="@href"/>
239                </xsl:attribute>
240                <xsl:choose>
241                    <xsl:when test="(@ext!='jpg' and @ext!='gif') or @linking = 'linkonly'">
242                        <fo:external-graphic content-width="1em" src="url('{$tplincdir}../../images/fileicons/{$ext}.png')" />
243                        <xsl:apply-templates />
244                    </xsl:when>
245                    <xsl:otherwise>
246                        <fo:external-graphic src="url({$filename})" />
247                    </xsl:otherwise>
248                </xsl:choose>
249                <xsl:choose>
250                    <xsl:when test="(@ext!='jpg' and @ext!='gif' and not(normalize-space(.))) or @linking = 'linkonly'">
251                        <xsl:value-of select="@basename" />
252                    </xsl:when>
253                </xsl:choose>
254            </fo:basic-link>
255        </fo:inline>
256    </xsl:template>
257
258    <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
259    <!-- Lists -->
260    <xsl:template match="listu|listo">
261        <fo:list-block provisional-distance-between-starts="0.5cm" provisional-label-separation="0.2cm" font-size="10pt">
262            <xsl:attribute name="start-indent">
263                <xsl:variable name="ancestors">
264                    <xsl:choose>
265                        <xsl:when test="count(ancestor::listo) or count(ancestor::listu)">
266                            <xsl:value-of select="count(ancestor::listo) + count(ancestor::listu)"/>
267                        </xsl:when>
268                        <xsl:otherwise>
269                            <xsl:text>0</xsl:text>
270                        </xsl:otherwise>
271                    </xsl:choose>
272                </xsl:variable>
273                <xsl:value-of select="concat((0.5+($ancestors*0.5)), 'cm')"/>
274            </xsl:attribute>
275            <xsl:apply-templates />
276        </fo:list-block>
277    </xsl:template>
278
279    <xsl:template match="listu/listitem">
280        <fo:list-item>
281            <fo:list-item-label end-indent="label-end()">
282                <fo:block>
283                    <xsl:choose>
284                        <xsl:when test="count(ancestor::listu)=1">&#x2022;</xsl:when>
285                        <xsl:when test="count(ancestor::listu)=2">&#x2013;</xsl:when>
286                        <xsl:otherwise>&#x2219;</xsl:otherwise>
287                    </xsl:choose>
288                </fo:block>
289            </fo:list-item-label>
290            <fo:list-item-body start-indent="body-start()">
291                <fo:block>
292                    <xsl:apply-templates />
293                </fo:block>
294            </fo:list-item-body>
295        </fo:list-item>
296    </xsl:template>
297    <xsl:template match="listo/listitem">
298        <fo:list-item>
299            <fo:list-item-label end-indent="label-end()">
300                <fo:block>
301                    <xsl:variable name="format">
302                        <xsl:choose>
303                            <xsl:when test="count(ancestor::listo)=1">1.</xsl:when>
304                            <xsl:when test="count(ancestor::listo)=2">a)</xsl:when>
305                            <xsl:when test="count(ancestor::listo)=3">I.</xsl:when>
306                            <xsl:when test="count(ancestor::listo)=4">A)</xsl:when>
307                            <xsl:when test="count(ancestor::listo)=5">i.</xsl:when>
308                            <xsl:otherwise>1.</xsl:otherwise>
309                        </xsl:choose>
310                    </xsl:variable>
311                    <xsl:number format="{$format}" />
312                </fo:block>
313            </fo:list-item-label>
314            <fo:list-item-body start-indent="body-start()">
315                <fo:block>
316                    <xsl:apply-templates />
317                </fo:block>
318            </fo:list-item-body>
319        </fo:list-item>
320    </xsl:template>
321    <xsl:template match="listcontent">
322        <fo:block>
323            <xsl:apply-templates />
324        </fo:block>
325    </xsl:template>
326
327    <!-- Definitionlist plugin - - - - - - - - - - - - - - - - - - - - - - - -->
328    <xsl:template match="dl">
329        <fo:table table-layout="fixed" width="100%" font-size="10pt">
330            <fo:table-body>
331                <xsl:for-each select="dt">
332                    <xsl:variable name="current-term" select="."/>
333                    <fo:table-row>
334                        <fo:table-cell font-weight="bold" width="5.5cm">
335                            <fo:block>
336                                <xsl:apply-templates />
337                            </fo:block>
338                        </fo:table-cell>
339                        <fo:table-cell>
340                            <fo:block>
341                                <xsl:apply-templates select="following-sibling::dd[preceding-sibling::dt[1] = $current-term]" />
342                            </fo:block>
343                        </fo:table-cell>
344                    </fo:table-row>
345                </xsl:for-each>
346            </fo:table-body>
347        </fo:table>
348    </xsl:template>
349    <xsl:template match="dd">
350        <fo:block>
351            <xsl:apply-templates />
352        </fo:block>
353    </xsl:template>
354
355    <!-- Tables  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
356    <xsl:template match="table">
357        <fo:table table-layout="fixed" margin="1cm auto 0.8cm auto" keep-together.within-page="0.8">
358            <xsl:attribute name="width">
359                <xsl:value-of select="substring-before(substring-after(@style,'width:'),';')" />
360            </xsl:attribute>
361            <xsl:apply-templates select="col" />
362            <fo:table-body>
363                <xsl:apply-templates select="*[not(self::col)]" />
364            </fo:table-body>
365        </fo:table>
366    </xsl:template>
367
368    <xsl:template match="col">
369        <fo:table-column>
370            <xsl:variable name="width" select="substring-after(@style, 'width:')" />
371            <xsl:choose>
372                <xsl:when test="$width != ''">
373                    <xsl:attribute name="column-width">
374                        <xsl:value-of select="normalize-space($width)" />
375                    </xsl:attribute>
376                </xsl:when>
377            </xsl:choose>
378            <xsl:apply-templates />
379        </fo:table-column>
380    </xsl:template>
381
382    <xsl:template match="tablerow">
383        <fo:table-row>
384            <xsl:apply-templates />
385        </fo:table-row>
386    </xsl:template>
387
388    <xsl:template match="tableheader">
389        <fo:table-cell border="thin solid black" start-indent="0" end-indent="0"
390                       background-color="#efefef" display-align="after" padding="1mm">
391            <xsl:attribute name="number-rows-spanned">
392                <xsl:choose>
393                    <xsl:when test="@rowspan">
394                        <xsl:value-of select="@rowspan" />
395                    </xsl:when>
396                    <xsl:otherwise>1</xsl:otherwise>
397                </xsl:choose>
398            </xsl:attribute>
399            <xsl:attribute name="number-columns-spanned">
400                <xsl:choose>
401                    <xsl:when test="@colspan">
402                        <xsl:value-of select="@colspan" />
403                    </xsl:when>
404                    <xsl:otherwise>1</xsl:otherwise>
405                </xsl:choose>
406            </xsl:attribute>
407            <fo:block font-weight="bold">
408                <xsl:attribute name="text-align">
409                    <xsl:choose>
410                        <xsl:when test="@align">
411                            <xsl:value-of select="@align" />
412                        </xsl:when>
413                        <xsl:otherwise>left</xsl:otherwise>
414                    </xsl:choose>
415                </xsl:attribute>
416                <xsl:apply-templates />
417            </fo:block>
418        </fo:table-cell>
419    </xsl:template>
420
421    <xsl:template match="tablecell">
422        <fo:table-cell border="thin solid black" start-indent="0" end-indent="0" padding="1mm">
423            <xsl:attribute name="number-rows-spanned">
424                <xsl:choose>
425                    <xsl:when test="@rowspan">
426                        <xsl:value-of select="@rowspan" />
427                    </xsl:when>
428                    <xsl:otherwise>1</xsl:otherwise>
429                </xsl:choose>
430            </xsl:attribute>
431            <xsl:attribute name="number-columns-spanned">
432                <xsl:choose>
433                    <xsl:when test="@colspan">
434                        <xsl:value-of select="@colspan" />
435                    </xsl:when>
436                    <xsl:otherwise>1</xsl:otherwise>
437                </xsl:choose>
438            </xsl:attribute>
439            <fo:block>
440                <xsl:attribute name="text-align">
441                    <xsl:choose>
442                        <xsl:when test="@align">
443                            <xsl:value-of select="@align" />
444                        </xsl:when>
445                        <xsl:otherwise>left</xsl:otherwise>
446                    </xsl:choose>
447                </xsl:attribute>
448                <xsl:value-of select="@rowspan" />
449                <xsl:apply-templates />
450            </fo:block>
451        </fo:table-cell>
452    </xsl:template>
453
454</xsl:stylesheet>
455