1 <?xml version="1.0" encoding="UTF-8"?>
2 <xsl:stylesheet version="2.0"
3 xmlns="http://www.w3.org/1999/xhtml"
4 xmlns:h="http://www.w3.org/1999/xhtml"
5 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
6 xmlns:fn="http://www.w3.org/2005/xpath-functions"
7 xmlns:svg="http://www.w3.org/2000/svg"
8 xmlns:xs="http://www.w3.org/2001/XMLSchema"
9 xmlns:o="https://trac.frantovo.cz/odstavcovac-TODO-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX-/wiki/xmlns/odstavcovac"
10 exclude-result-prefixes="fn h xs o">
11 <xsl:output method="xml" indent="yes" encoding="UTF-8"/>
13 <xsl:param name="cssTřída"/>
15 <!-- Celý dokument -->
16 <xsl:template match="/">
20 <xsl:variable name="prvníKolo">
21 <xsl:apply-templates select="h:html/h:body/node()" mode="prvníKolo"/>
24 <xsl:variable name="druhéKolo">
25 <xsl:apply-templates select="$prvníKolo" mode="druhéKolo"/>
28 <xsl:apply-templates select="$druhéKolo" mode="třetíKolo"/>
35 <!-- Kopírujeme elementy, ale vynecháme nepoužité xmlns deklarace: -->
36 <xsl:template match="*" mode="kopíruj">
37 <xsl:element name="{name()}">
38 <xsl:copy-of select="@*"/>
39 <xsl:apply-templates/>
44 <!-- Mezi odstavci je prázdný řádek, můžou být mezery/tabulátory. -->
45 <xsl:variable name="oddělovač" select="'\n\s*\n\s*'"/>
48 <!-- Funkce: zda jde o XHTML inline element – může se vyskytovat uvnitř odstavců. -->
49 <xsl:template name="inlineElement" as="xs:boolean">
50 <xsl:param name="prvek"/>
51 <xsl:sequence select="
52 $prvek/name() = 'a' or
53 $prvek/name() = 'abbr' or
54 $prvek/name() = 'acronym' or
55 $prvek/name() = 'b' or
56 $prvek/name() = 'br' or
57 $prvek/name() = 'cite' or
58 $prvek/name() = 'code' or
59 $prvek/name() = 'em' or
60 $prvek/name() = 'i' or
61 $prvek/name() = 'img' or
62 $prvek/name() = 'q' or
63 $prvek/name() = 'span' or
64 $prvek/name() = 'strong' or
65 $prvek/name() = 'sub' or
66 $prvek/name() = 'sup' or
67 $prvek/name() = 'tt' or
68 $prvek/name() = 'u' or
71 <!-- …případně další, pokud je budeme chtít podporovat. -->
75 <!-- Funkce: zda je prvek začátkem odstavce. -->
76 <xsl:template name="začátekOdstavce" as="xs:boolean">
77 <xsl:param name="prvek"/>
79 <xsl:variable name="inlineElement" as="xs:boolean">
80 <xsl:call-template name="inlineElement"><xsl:with-param name="prvek" select="$prvek"/></xsl:call-template>
83 <xsl:variable name="předchůdce" select="$prvek/preceding-sibling::node()[1]"/>
85 <xsl:variable name="inlineElementPředchůdce" as="xs:boolean">
86 <xsl:call-template name="inlineElement"><xsl:with-param name="prvek" select="$předchůdce"/></xsl:call-template>
89 <xsl:variable name="textovýUzel" select="boolean($prvek/self::text())"/>
91 <xsl:sequence select="
92 ($inlineElement or $textovýUzel)
95 ($inlineElementPředchůdce and matches($prvek, concat('^', $oddělovač, '.*')))
97 not($inlineElementPředchůdce)
103 not($předchůdce/self::text())
105 matches($předchůdce/self::text(), concat('.*', $oddělovač, '$'))
112 V prvním kole zavřeme volný text a inline elementy do značek <o:odstavec typ=""/>,
113 kde typ může být "začátek", což značí, že se jedná o první část budoucího odstavce <p/>.
115 <xsl:template match="text()" mode="prvníKolo">
117 <xsl:variable name="začátekOdstavce" as="xs:boolean">
118 <xsl:call-template name="začátekOdstavce">
119 <xsl:with-param name="prvek" select="."/>
123 <xsl:for-each select="fn:tokenize(., $oddělovač)">
124 <xsl:element name="o:odstavec">
125 <xsl:if test="$začátekOdstavce or not(position() = 1)">
126 <xsl:attribute name="typ">začátek</xsl:attribute>
128 <xsl:value-of select="."/>
135 Inline elementy zavíráme do <o:odstavec typ=""/>,
136 ostatní vkládáme, jak jsou.
138 <xsl:template match="*" mode="prvníKolo">
140 <xsl:variable name="inlineElement" as="xs:boolean">
141 <xsl:call-template name="inlineElement">
142 <xsl:with-param name="prvek" select="."/>
147 <!-- TODO: zvláštní šablona (match="…") pro inline elementy místo větvení? -->
148 <xsl:when test="$inlineElement">
149 <xsl:variable name="začátekOdstavce" as="xs:boolean">
150 <xsl:call-template name="začátekOdstavce">
151 <xsl:with-param name="prvek" select="."/>
154 <xsl:element name="o:odstavec">
155 <xsl:if test="$začátekOdstavce">
156 <xsl:attribute name="typ">začátek</xsl:attribute>
158 <xsl:copy-of select="."/>
162 <xsl:copy-of select="."/>
168 <!-- V druhém kole spojíme jednotlivé části odstavců. -->
169 <xsl:template match="o:odstavec[@typ='začátek']" mode="druhéKolo">
171 <xsl:call-template name="spojOdstavce">
172 <xsl:with-param name="část" select="."/>
176 <!-- Následující části odstavce přeskočíme – postará se o ně vnitřní smyčka volaná z předchozí šablony. -->
177 <xsl:template match="o:odstavec" mode="druhéKolo"/>
178 <!-- Neinline (blokové) elementy vložíme, jak jsou. -->
179 <xsl:template match="*" mode="druhéKolo">
180 <xsl:copy-of select="."/>
185 Za první část (parametr, <o:odstavec typ="začátek"/>) resp. její vnitřek
186 připojíme (rekurze) všechny další části téhož odstavce (oddělíme mezerou).
187 Konec odstavce poznáme tak, že následovník je něco jiného než <o:odstavec/> nebo má atribut typ="začátek".
189 <xsl:template name="spojOdstavce">
190 <xsl:param name="část"/>
191 <xsl:copy-of select="$část/child::node()"/>
192 <xsl:variable name="následovník" select="$část/following-sibling::node()[1]"/>
193 <xsl:if test="$následovník/name() = 'o:odstavec' and not($následovník/@typ = 'začátek')">
194 <xsl:text> </xsl:text>
195 <xsl:call-template name="spojOdstavce">
196 <xsl:with-param name="část" select="$následovník"/>
202 <!-- Ve třetím kole smažeme prázdné mešuge odstavce. -->
203 <xsl:template mode="třetíKolo" match="o:odstavec[
204 count(child::node()) = 0
207 count(child::node()) = 1
211 matches(text(), '^\s*$')
214 <xsl:text> </xsl:text>
216 <!-- Převedeme z <o:odstavec/> na <p/> -->
217 <xsl:template match="o:odstavec" mode="třetíKolo">
218 <xsl:element name="p">
219 <xsl:if test="$cssTřída">
220 <xsl:attribute name="class"><xsl:value-of select="$cssTřída"/></xsl:attribute>
222 <xsl:apply-templates select="child::node()" mode="kopíruj"/>
225 <!-- Všechno ostatní zkopírujeme, jak je. -->
226 <xsl:template match="*" mode="třetíKolo">
227 <xsl:copy-of select="."/>