1 <?xml version="1.0" encoding="UTF-8"?>
3 Copyright © 2014 František Kučera (frantovo.cz)
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
18 <xsl:stylesheet version="2.0"
19 xmlns="http://www.w3.org/1999/xhtml"
20 xmlns:h="http://www.w3.org/1999/xhtml"
21 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
22 xmlns:fn="http://www.w3.org/2005/xpath-functions"
23 xmlns:xs="http://www.w3.org/2001/XMLSchema"
24 xmlns:o="https://trac.frantovo.cz/odstavcovac-TODO-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX-/wiki/xmlns/odstavcovac"
25 exclude-result-prefixes="fn h xs o">
26 <xsl:output method="xml" indent="yes" encoding="UTF-8" omit-xml-declaration="yes"/>
28 <xsl:param name="cssTřída"/>
30 <!-- Celý dokument -->
31 <xsl:template match="/">
35 <xsl:variable name="prvníKolo">
36 <xsl:apply-templates select="h:html/h:body/node()" mode="prvníKolo"/>
39 <xsl:variable name="druhéKolo">
40 <xsl:apply-templates select="$prvníKolo" mode="druhéKolo"/>
43 <xsl:apply-templates select="$druhéKolo" mode="třetíKolo"/>
50 <!-- Kopírujeme elementy, ale vynecháme nepoužité xmlns deklarace: -->
51 <xsl:template match="*" mode="kopíruj">
52 <xsl:element name="{name()}">
53 <xsl:copy-of select="@*"/>
54 <xsl:apply-templates mode="kopíruj"/>
59 <!-- Mezi odstavci je prázdný řádek, můžou být mezery/tabulátory. -->
60 <xsl:variable name="oddělovač" select="'\n\s*\n\s*'"/>
63 <!-- Funkce: zda jde o XHTML inline element – může se vyskytovat uvnitř odstavců. -->
64 <xsl:template name="inlineElement" as="xs:boolean">
65 <xsl:param name="prvek"/>
66 <xsl:sequence select="
67 $prvek/name() = 'a' or
68 $prvek/name() = 'abbr' or
69 $prvek/name() = 'acronym' or
70 $prvek/name() = 'b' or
71 $prvek/name() = 'br' or
72 $prvek/name() = 'cite' or
73 $prvek/name() = 'code' or
74 $prvek/name() = 'em' or
75 $prvek/name() = 'i' or
76 $prvek/name() = 'img' or
77 $prvek/name() = 'q' or
78 $prvek/name() = 'span' or
79 $prvek/name() = 'strong' or
80 $prvek/name() = 'sub' or
81 $prvek/name() = 'sup' or
82 $prvek/name() = 'tt' or
83 $prvek/name() = 'u' or
86 <!-- …případně další, pokud je budeme chtít podporovat. -->
90 <!-- Funkce: zda je prvek začátkem odstavce. -->
91 <xsl:template name="začátekOdstavce" as="xs:boolean">
92 <xsl:param name="prvek"/>
94 <xsl:variable name="inlineElement" as="xs:boolean">
95 <xsl:call-template name="inlineElement"><xsl:with-param name="prvek" select="$prvek"/></xsl:call-template>
98 <xsl:variable name="předchůdce" select="$prvek/preceding-sibling::node()[1]"/>
100 <xsl:variable name="inlineElementPředchůdce" as="xs:boolean">
101 <xsl:call-template name="inlineElement"><xsl:with-param name="prvek" select="$předchůdce"/></xsl:call-template>
104 <xsl:variable name="textovýUzel" select="boolean($prvek/self::text())"/>
106 <xsl:sequence select="
107 ($inlineElement or $textovýUzel)
110 ($inlineElementPředchůdce and matches($prvek, concat('^', $oddělovač, '.*')))
112 not($inlineElementPředchůdce)
118 not($předchůdce/self::text())
120 matches($předchůdce/self::text(), concat('.*', $oddělovač, '$'))
127 V prvním kole zavřeme volný text a inline elementy do značek <o:odstavec typ=""/>,
128 kde typ může být "začátek", což značí, že se jedná o první část budoucího odstavce <p/>.
130 <xsl:template match="text()" mode="prvníKolo">
132 <xsl:variable name="začátekOdstavce" as="xs:boolean">
133 <xsl:call-template name="začátekOdstavce">
134 <xsl:with-param name="prvek" select="."/>
138 <xsl:for-each select="fn:tokenize(., $oddělovač)">
139 <xsl:element name="o:odstavec">
140 <xsl:if test="$začátekOdstavce or not(position() = 1)">
141 <xsl:attribute name="typ">začátek</xsl:attribute>
143 <xsl:value-of select="."/>
150 Inline elementy zavíráme do <o:odstavec typ=""/>,
151 ostatní vkládáme, jak jsou.
153 <xsl:template match="*" mode="prvníKolo">
155 <xsl:variable name="inlineElement" as="xs:boolean">
156 <xsl:call-template name="inlineElement">
157 <xsl:with-param name="prvek" select="."/>
162 <!-- TODO: zvláštní šablona (match="…") pro inline elementy místo větvení? -->
163 <xsl:when test="$inlineElement">
164 <xsl:variable name="začátekOdstavce" as="xs:boolean">
165 <xsl:call-template name="začátekOdstavce">
166 <xsl:with-param name="prvek" select="."/>
169 <xsl:element name="o:odstavec">
170 <xsl:if test="$začátekOdstavce">
171 <xsl:attribute name="typ">začátek</xsl:attribute>
173 <xsl:copy-of select="."/>
177 <xsl:copy-of select="."/>
183 <!-- V druhém kole spojíme jednotlivé části odstavců. -->
184 <xsl:template match="o:odstavec[@typ='začátek']" mode="druhéKolo">
186 <xsl:call-template name="spojOdstavce">
187 <xsl:with-param name="část" select="."/>
191 <!-- Následující části odstavce přeskočíme – postará se o ně vnitřní smyčka volaná z předchozí šablony. -->
192 <xsl:template match="o:odstavec" mode="druhéKolo"/>
193 <!-- Neinline (blokové) elementy vložíme, jak jsou. -->
194 <xsl:template match="*" mode="druhéKolo">
195 <xsl:copy-of select="."/>
200 Za první část (parametr, <o:odstavec typ="začátek"/>) resp. její vnitřek
201 připojíme (rekurze) všechny další části téhož odstavce (oddělíme mezerou).
202 Konec odstavce poznáme tak, že následovník je něco jiného než <o:odstavec/> nebo má atribut typ="začátek".
204 <xsl:template name="spojOdstavce">
205 <xsl:param name="část"/>
206 <xsl:copy-of select="$část/child::node()"/>
207 <xsl:variable name="následovník" select="$část/following-sibling::node()[1]"/>
208 <xsl:if test="$následovník/name() = 'o:odstavec' and not($následovník/@typ = 'začátek')">
209 <xsl:call-template name="spojOdstavce">
210 <xsl:with-param name="část" select="$následovník"/>
216 <!-- Ve třetím kole smažeme prázdné mešuge odstavce. -->
217 <xsl:template mode="třetíKolo" match="o:odstavec[
218 count(child::node()) = 0
221 count(child::node()) = 1
225 matches(text(), '^\s*$')
228 <xsl:text> </xsl:text>
230 <!-- Převedeme z <o:odstavec/> na <p/> -->
231 <xsl:template match="o:odstavec" mode="třetíKolo">
232 <xsl:element name="p">
233 <xsl:if test="$cssTřída">
234 <xsl:attribute name="class"><xsl:value-of select="$cssTřída"/></xsl:attribute>
236 <xsl:apply-templates select="child::node()" mode="kopíruj"/>
239 <!-- Všechno ostatní zkopírujeme, jak je. -->
240 <xsl:template match="*" mode="třetíKolo">
241 <xsl:copy-of select="."/>