Initial commit.
[wl2pdf.git] / xslt / normalize.xslt
1 <?xml version="1.0" encoding="utf-8"?>
2 <!-- 
3     Copyright © 2009,2010 Łukasz Rekucki
4
5     This file is part of WL2PDF
6
7     WL2PDF is free software: you can redistribute it and/or modify
8     it under the terms of the GNU Affero General Public License as published by
9     the Free Software Foundation, either version 3 of the License, or
10     (at your option) any later version.
11
12     WL2PDF is distributed in the hope that it will be useful,
13     but WITHOUT ANY WARRANTY; without even the implied warranty of
14     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15     GNU Affero General Public License for more details.
16
17     You should have received a copy of the GNU Affero General Public License
18     along with WL2PDF.  If not, see <http://www.gnu.org/licenses/>.
19  -->
20 <xsl:stylesheet version="2.0"
21     xmlns="http://nowoczesnapolska.org.pl/ML/Lektury/1.1"
22
23         xmlns:xs="http://www.w3.org/2001/XMLSchema"        
24     xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
25     
26     xmlns:wlf="http://wolnelektury.pl/functions"
27
28     xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" 
29     xmlns:dc="http://purl.org/dc/elements/1.1/"
30
31     exclude-result-prefixes="wlf xsl xs"
32 >
33
34     <!-- Normalization Stylsheet for Wolne Lektury XML -->
35     <xsl:output method="xml" encoding="utf-8" indent="yes" />     
36     <xsl:strip-space elements="rdf:RDF rdf:Description meta doc main-text strofa stanza drama-line" />
37     
38     <xsl:variable name="punctuation" select="'.,;:!?'" />    
39     
40     <xsl:function name="wlf:fix-dialog-line">
41         <xsl:param name="text" />
42         <xsl:choose>
43                 <xsl:when test="starts-with($text, '---')">
44                         <xsl:value-of select="wlf:normalize-text(substring-after($text, '---'))" />
45                 </xsl:when>
46                 <xsl:otherwise>
47                         <xsl:value-of select="$text" />
48                 </xsl:otherwise>        
49         </xsl:choose>
50     </xsl:function>    
51     
52     <xsl:function name="wlf:normalize-text">
53         <xsl:param name="text" />
54         <!--  The normalization step doesn't change the entities - it only normalizes whitespace -->
55         <xsl:value-of select="string-join(tokenize($text, '\s+'), ' ')" />      
56     </xsl:function>   
57        
58         
59     <!-- Main entry point -->
60     <xsl:template match="/">
61         <doc>
62             <meta>
63                 <xsl:apply-templates select="//rdf:RDF" mode="meta"/>
64             </meta>
65
66             <xsl:variable name="body" select="/utwor/*[local-name() = name()]" />
67
68             <main-text class="{name($body)}">
69                 <xsl:apply-templates select="$body/node()" />
70             </main-text>
71
72             <annotations>
73                 <xsl:apply-templates select="//pr|//pt|//pe|//pa" mode="annotations" />
74             </annotations>
75         </doc>
76     </xsl:template>    
77
78     <xsl:template match="strofa">
79         <xsl:element name="stanza" namespace="http://nowoczesnapolska.org.pl/ML/Lektury/1.1">
80             <!-- normalize verses -->
81             <xsl:choose>
82                 <xsl:when test="count(br) > 0">
83                     <!-- First, collect all the tags up to first BR -->
84                     <xsl:call-template name="verse">
85                         <xsl:with-param name="verse-content" select="br[1]/preceding-sibling::node()" />
86                         <xsl:with-param name="verse-type" select="br[1]/preceding-sibling::*[name() = 'wers_wciety' or name() = 'wers_akap' or name() = 'wers_cd'][1]" />
87                     </xsl:call-template>
88
89                     <!-- Collect the rest of verses -->
90                     <xsl:for-each select="br">
91                                 <!-- Each BR tag "consumes" text after it -->
92                         <xsl:variable name="lnum" select="count(preceding-sibling::br)" />
93                         <xsl:call-template name="verse">
94                             <xsl:with-param name="verse-content"
95                                 select="following-sibling::node()[count(preceding-sibling::br) = $lnum+1 and name() != 'br']" />
96                             <xsl:with-param name="verse-type" select="following-sibling::*[count(preceding-sibling::br) = $lnum+1 and (name() = 'wers_wciety' or name() = 'wers_akap' or name() = 'wers_cd')][1]" />
97                         </xsl:call-template>
98                     </xsl:for-each>
99                 </xsl:when>
100
101                 <!-- No BR's - collect the whole content -->
102                 <xsl:otherwise>                 
103                     <xsl:call-template name="verse">
104                         <xsl:with-param name="verse-content" select="child::node()" />
105                         <xsl:with-param name="verse-type" select="wers_wciety|wers_akap|wers_cd[1]" />
106                     </xsl:call-template>
107                 </xsl:otherwise>
108
109             </xsl:choose>
110         </xsl:element>
111     </xsl:template>
112
113     <xsl:template name="verse">
114         <xsl:param name="verse-content" />
115         <xsl:param name="verse-type" />
116
117         <xsl:choose>
118             <xsl:when test="not($verse-type)">
119                 <xsl:element name="v" namespace="http://nowoczesnapolska.org.pl/ML/Lektury/1.1">
120                     <xsl:apply-templates select="$verse-content" />
121                 </xsl:element>
122             </xsl:when>
123
124             <xsl:otherwise>
125                 <xsl:apply-templates select="$verse-content" />
126             </xsl:otherwise>
127         </xsl:choose>
128     </xsl:template>
129
130
131     <!-- akapity -->
132     <xsl:template match="akap">
133         <xsl:element name="p">
134             <xsl:apply-templates select="@*|node()" />
135         </xsl:element>
136     </xsl:template>
137
138     <xsl:template match="akap_cd">
139         <xsl:element name="pc">
140             <xsl:apply-templates select="@*|node()" />
141         </xsl:element>
142     </xsl:template>
143
144     <xsl:template match="akap_dialog">
145         <xsl:element name="pd">
146             <xsl:variable name="prolog" select="./text()[1]" />            
147             <xsl:value-of select="wlf:fix-dialog-line($prolog)" />
148             <xsl:apply-templates select="@*|*|text()[. != $prolog]" />
149         </xsl:element>
150     </xsl:template>
151
152     <!-- wersy -->
153     <xsl:template match="wers_cd">
154         <xsl:element name="vc">
155             <xsl:apply-templates select="@*|node()" />
156         </xsl:element>
157     </xsl:template>
158
159     <xsl:template match="wers_akap">
160         <xsl:element name="vi">
161             <xsl:attribute name="size">p</xsl:attribute>
162             <xsl:apply-templates select="@*|node()" />
163         </xsl:element>
164     </xsl:template>
165
166     <xsl:template match="wers_wciety">
167         <xsl:element name="vi">
168             <xsl:if test="@typ">
169             <xsl:attribute name="size"><xsl:value-of select="@typ" /></xsl:attribute>
170             </xsl:if>
171             <xsl:apply-templates select="@*[name() != 'typ']|node()" />
172         </xsl:element>
173     </xsl:template>
174
175     <xsl:template match="zastepnik_wersu">
176         <xsl:element name="verse-skip">
177             <xsl:choose>
178                 <xsl:when test="starts-with(., '.')">
179                     <xsl:attribute name="type">dot</xsl:attribute>
180                 </xsl:when>
181             </xsl:choose> 
182         </xsl:element>
183     </xsl:template>
184
185     <!-- Przypisy i motywy -->
186     <xsl:template match="begin" />
187         <!-- <xsl:element name="mark">
188             <xsl:attribute name="starts">
189                 <xsl:value-of select="substring(@id, 2)" />
190             </xsl:attribute>
191             <xsl:attribute name="themes">
192                 <xsl:value-of select="following-sibling::motyw[1]/text()" />
193             </xsl:attribute>
194         </xsl:element>
195     </xsl:template> -->
196
197     <xsl:template match="motyw" />
198
199     <xsl:template match="end" />
200     <!--
201         <xsl:element name="mark">
202             <xsl:attribute name="ends">
203                 <xsl:value-of select="substring(@id, 2)" />
204             </xsl:attribute>
205         </xsl:element>
206     </xsl:template> -->
207
208     <xsl:template match="pa|pe|pr|pt">
209         <!-- fetch the next text node -->
210         <xsl:variable name="tail" select="following-sibling::text()[1]" />
211         <xsl:variable name="tail-text" select="wlf:normalize-text($tail)" />
212         <xsl:variable name="first-char" select="substring($tail-text, 1, 1)" />
213         
214         <xsl:if test="contains($punctuation, $first-char)">             
215         <xsl:value-of select="$first-char" />
216         </xsl:if>       
217         <anchor id="{generate-id(.)}" />                
218     </xsl:template>
219
220
221     <xsl:template match="pa|pe|pr|pt" mode="annotations">
222         <annotation refs="{generate-id(.)}" type="{name(.)}">
223                 <xsl:apply-templates select="@*" />             
224                 <xsl:variable name="text-node" 
225                         select="text()[not(matches(., '^\s*$'))][1]" />
226                         
227                 <xsl:variable name="normalized-text" select="normalize-space($text-node)" />            
228                 <xsl:choose>            
229                 <xsl:when test="slowo_obce[1] and slowo_obce[1] &lt;&lt; $text-node">
230                 <!--  <slowo_obce>Definition</slowo_obce> some stuff -->
231                 <definition>                    
232                         <xsl:apply-templates select="child::slowo_obce[1]/node()" />                     
233                 </definition>
234                 <body>                                           
235                         <xsl:value-of select="
236                                 if (starts-with($normalized-text, '---')) 
237                                 then 
238                                         wlf:normalize-text(substring-after($normalized-text, '---'))
239                                 else 
240                                         $text-node" 
241                         />                      
242                         <xsl:apply-templates select="$text-node/following-sibling::node()" />   
243                 </body>
244                 </xsl:when>
245                 <xsl:when test="not(contains($normalized-text, '---'))">
246                 <body>
247                         <xsl:value-of select="wlf:normalize-text($text-node)" />
248                         <xsl:apply-templates select="$text-node/following-sibling::node()" />
249                 </body>
250                 </xsl:when>
251                         <xsl:otherwise>                                 
252                 <definition>                    
253                         <xsl:value-of select="wlf:normalize-text(substring-before($normalized-text, '---'))" />
254                 </definition>
255                 <body>       
256                 <xsl:value-of select="wlf:normalize-text(substring-after($normalized-text, '---'))" />
257                 <xsl:apply-templates select="$text-node/following-sibling::node()" />
258             </body>
259             </xsl:otherwise>
260             </xsl:choose>
261         </annotation>
262     </xsl:template>
263
264
265     <!-- Tytuły -->
266     <xsl:template match="autor_utworu">
267         <xsl:element name="author">
268             <xsl:apply-templates select="@*|node()" />
269         </xsl:element>
270     </xsl:template>
271
272     <xsl:template match="nazwa_utworu">
273         <xsl:element name="title">
274             <xsl:apply-templates select="@*|node()" />
275         </xsl:element>
276     </xsl:template>
277
278     <xsl:template match="naglowek_czesc">
279         <chapter>
280             <xsl:apply-templates select="@*|node()" />
281         </chapter>
282     </xsl:template>
283
284     <xsl:template match="naglowek_akt">
285         <act>
286             <xsl:apply-templates select="@*|node()" />
287         </act>
288     </xsl:template>
289
290     <xsl:template match="naglowek_scena">
291         <scene>
292             <xsl:apply-templates select="@*|node()" />
293         </scene>
294     </xsl:template>
295
296     <xsl:template match="podtytul">
297         <second-title>
298             <xsl:apply-templates select="@*|node()" />
299         </second-title>
300     </xsl:template>
301
302     <xsl:template match="srodtytul">
303         <part-title>
304             <xsl:apply-templates select="@*|node()" />
305         </part-title>
306     </xsl:template>
307
308     <!-- elementy dramatu -->
309     <xsl:template match="miejsce_czas">
310         <xsl:element name="time-and-date">
311             <xsl:apply-templates select="@*|node()" />
312         </xsl:element>
313     </xsl:template>
314
315
316     <xsl:template match="didaskalia|didask_tekst">
317         <xsl:element name="stage-directions">
318             <xsl:apply-templates select="@*|node()" />
319         </xsl:element>
320     </xsl:template>
321
322     <xsl:template match="motto">
323         <xsl:element name="motto">
324             <xsl:apply-templates select="@*|node()" />
325         
326         <xsl:variable name="sign" select="following-sibling::*[1][name() = 'motto_podpis']" />
327         <signature>
328             <xsl:apply-templates select="$sign/node()" />
329         </signature>
330         </xsl:element>
331     </xsl:template>
332
333     <xsl:template match="motto_podpis[preceding-sibling::*[1][name() = 'motto']]" />
334         
335     <xsl:template match="lista_osob">
336         <person-list>
337             <xsl:apply-templates select="@*|node()" />
338         </person-list>
339     </xsl:template>
340
341     <xsl:template match="naglowek_listy">
342         <caption>
343             <xsl:apply-templates select="@*|node()" />
344         </caption>
345     </xsl:template>
346
347     <xsl:template match="lista_osoba">
348         <person>
349             <xsl:apply-templates select="@*|node()" />
350         </person>
351     </xsl:template>
352
353     <!-- Odstępy i prześwity -->
354     <xsl:template match="sekcja_swiatlo">
355         <vertical-space />
356     </xsl:template>
357     
358     <xsl:template match="sekcja_asterysk">
359         <vertical-space type="asterisk" />
360     </xsl:template>
361
362     <xsl:template match="sekcja_asterysk">
363         <vertical-space type="line" />
364     </xsl:template>
365
366     <!-- pozostałe elementy blokowe -->
367     <xsl:template match="dlugi_cytat">
368         <block-quote>
369             <xsl:apply-templates select="@*|node()" />
370         </block-quote>`
371     </xsl:template>
372
373     <xsl:template match="poezja_cyt">
374         <block-quote>
375             <xsl:apply-templates select="@*|node()" />
376         </block-quote>`
377     </xsl:template>
378
379     <xsl:template match="kwestia">
380         <xsl:variable name="person" select="preceding-sibling::*[1][name() = 'naglowek_osoba']" />
381         <drama-line>
382             <person>
383                 <xsl:apply-templates select="$person/node()" />
384             </person>
385             <xsl:apply-templates select="node()[. != $person]" />
386         </drama-line>
387     </xsl:template>
388
389     <xsl:template match="naglowek_osoba[following-sibling::*[1][name() = 'kwestia']]" />
390         
391     <!-- Inne -->
392     <xsl:template match="osoba">
393         <xsl:element name="person-ref">
394             <xsl:apply-templates select="@*|node()" />
395         </xsl:element>
396     </xsl:template>
397
398     <xsl:template match="slowo_obce">
399         <xsl:element name="foreign">
400             <xsl:apply-templates select="@*|node()" />
401         </xsl:element>
402     </xsl:template>
403
404     <xsl:template match="wyroznienie">
405         <xsl:element name="em">
406             <xsl:apply-templates select="@*|node()" />
407         </xsl:element>
408     </xsl:template>
409
410     <xsl:template match="mat">
411         <xsl:element name="math">
412             <xsl:apply-templates select="@*|node()" />
413         </xsl:element>
414     </xsl:template>
415
416     <!-- oznaczenie tytulu innego utworu, wymienionego w tym -->
417     <xsl:template match="tytul_dziela">
418         <xsl:element name="book-ref">
419             <xsl:apply-templates select="@*|node()" />
420         </xsl:element>
421     </xsl:template>
422
423     <xsl:template match="extra">
424         <xsl:element name="comment">
425             <xsl:apply-templates select="@*|node()" />
426         </xsl:element>
427     </xsl:template>
428
429     <xsl:template match="uwaga">
430         <xsl:element name="edit-comment">
431             <xsl:apply-templates select="@*|node()" />
432         </xsl:element>
433     </xsl:template>
434
435     <!-- Copy attributes -->
436     <xsl:template match="@*|comment()">
437         <xsl:copy />
438     </xsl:template>    
439
440     <!-- Inside RDF meta-data, leave the text unchanged -->
441     <xsl:template match="rdf:RDF//text()">
442         <xsl:value-of select="." />
443     </xsl:template>
444
445     <!-- Normalize text in other nodes -->
446     <xsl:template match="text()">
447         <xsl:variable name="normalized" select="wlf:normalize-text(.)" />
448         <xsl:variable name="first-char" select="substring($normalized, 1, 1)" />
449         <xsl:variable name="siblings-before" select="preceding-sibling::pr|preceding-sibling::pa|preceding-sibling::pe|preceding-sibling::pt|preceding-sibling::text()" />                      
450         <xsl:choose>
451                 <xsl:when test="contains($punctuation, $first-char) and $siblings-before[last()]">
452                         <xsl:value-of select="substring($normalized, 2)" />
453                 </xsl:when>
454                 <xsl:otherwise>
455                         <xsl:value-of select="$normalized" />                                                   
456                 </xsl:otherwise>
457         </xsl:choose>                   
458     </xsl:template>    
459     
460     <!-- Ignoruj RDF poza meta -->
461     <xsl:template match="rdf:*|dc:*" />
462    
463     <xsl:template match="@*|node()" mode="meta">
464         <xsl:copy>
465             <xsl:apply-templates select="@*|node()" mode="meta" />
466         </xsl:copy>
467     </xsl:template>
468
469     <!-- Warn about non-matched elements -->
470     <xsl:template match="node()" priority="-1">        
471         <unparsed-node>
472             <xsl:copy-of select="." />
473         </unparsed-node>
474     </xsl:template>   
475     
476     
477 </xsl:stylesheet>