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">
11 <xsl:output method="xml" indent="yes" encoding="UTF-8"/>
14 <!-- Celý dokument -->
15 <xsl:template match="/">
18 <style type="text/css">
20 background-color: #afa;
21 border: 1px solid #55f;
28 <xsl:variable name="prvníKolo">
29 <xsl:apply-templates select="h:html/h:body/node()" mode="prvníKolo"/>
32 <xsl:variable name="druhéKolo">
33 <xsl:apply-templates select="$prvníKolo" mode="druhéKolo"/>
36 <xsl:apply-templates select="$druhéKolo" mode="třetíKolo"/>
43 <!-- Mezi odstavci je prázdný řádek, můžou být mezery/tabulátory. -->
44 <xsl:variable name="oddělovač" select="'\n\s*\n\s*'"/>
47 <!-- Funkce: zda jde o XHTML inline element – může se vyskytovat uvnitř odstavců. -->
48 <xsl:template name="inlineElement" as="xs:boolean">
49 <xsl:param name="prvek"/>
50 <xsl:sequence select="
51 $prvek/name() = 'a' or
52 $prvek/name() = 'abbr' or
53 $prvek/name() = 'acronym' or
54 $prvek/name() = 'b' or
55 $prvek/name() = 'br' or
56 $prvek/name() = 'cite' or
57 $prvek/name() = 'code' or
58 $prvek/name() = 'em' or
59 $prvek/name() = 'i' or
60 $prvek/name() = 'img' or
61 $prvek/name() = 'q' or
62 $prvek/name() = 'span' or
63 $prvek/name() = 'strong' or
64 $prvek/name() = 'sub' or
65 $prvek/name() = 'sup' or
66 $prvek/name() = 'tt' or
67 $prvek/name() = 'u' or
70 <!-- …případně další, pokud je budeme chtít podporovat. -->
74 <!-- Funkce: zda je prvek začátkem odstavce. -->
75 <xsl:template name="začátekOdstavce" as="xs:boolean">
76 <xsl:param name="prvek"/>
78 <xsl:variable name="inlineElement" as="xs:boolean">
79 <xsl:call-template name="inlineElement"><xsl:with-param name="prvek" select="$prvek"/></xsl:call-template>
82 <xsl:variable name="předchůdce" select="$prvek/preceding-sibling::node()[1]"/>
84 <xsl:variable name="inlineElementPředchůdce" as="xs:boolean">
85 <xsl:call-template name="inlineElement"><xsl:with-param name="prvek" select="$předchůdce"/></xsl:call-template>
88 <xsl:variable name="textovýUzel" select="boolean($prvek/self::text())"/>
90 <xsl:sequence select="
91 ($inlineElement or $textovýUzel)
94 ($inlineElementPředchůdce and matches($prvek, concat('^', $oddělovač, '.*')))
96 not($inlineElementPředchůdce)
102 not($předchůdce/self::text())
104 matches($předchůdce/self::text(), concat('.*', $oddělovač, '$'))
111 V prvním kole zavřeme volný text a inline elementy do značek <o:odstavec typ=""/>,
112 kde typ může být "začátek", což značí, že se jedná o první část budoucího odstavce <p/>.
114 <xsl:template match="text()" mode="prvníKolo">
116 <xsl:variable name="začátekOdstavce" as="xs:boolean">
117 <xsl:call-template name="začátekOdstavce">
118 <xsl:with-param name="prvek" select="."/>
122 <xsl:for-each select="fn:tokenize(., $oddělovač)">
123 <xsl:element name="o:odstavec">
124 <xsl:if test="$začátekOdstavce or not(position() = 1)">
125 <xsl:attribute name="typ">začátek</xsl:attribute>
127 <xsl:value-of select="."/>
134 Inline elementy zavíráme do <o:odstavec typ=""/>,
135 ostatní vkládáme, jak jsou.
137 <xsl:template match="*" mode="prvníKolo">
139 <xsl:variable name="inlineElement" as="xs:boolean">
140 <xsl:call-template name="inlineElement">
141 <xsl:with-param name="prvek" select="."/>
146 <!-- TODO: zvláštní šablona (match="…") pro inline elementy místo větvení? -->
147 <xsl:when test="$inlineElement">
148 <xsl:variable name="začátekOdstavce" as="xs:boolean">
149 <xsl:call-template name="začátekOdstavce">
150 <xsl:with-param name="prvek" select="."/>
153 <xsl:element name="o:odstavec">
154 <xsl:if test="$začátekOdstavce">
155 <xsl:attribute name="typ">začátek</xsl:attribute>
157 <xsl:copy-of select="."/>
161 <xsl:copy-of select="."/>
167 <!-- V druhém kole spojíme jednotlivé části odstavců. -->
168 <xsl:template match="o:odstavec[@typ='začátek']" mode="druhéKolo">
170 <xsl:call-template name="spojOdstavce">
171 <xsl:with-param name="část" select="."/>
175 <!-- Následující části odstavce přeskočíme – postará se o ně vnitřní smyčka volaná z předchozí šablony. -->
176 <xsl:template match="o:odstavec" mode="druhéKolo"/>
177 <!-- Neinline (blokové) elementy vložíme, jak jsou. -->
178 <xsl:template match="*" mode="druhéKolo">
179 <xsl:copy-of select="."/>
184 Za první část (parametr, <o:odstavec typ="začátek"/>) resp. její vnitřek
185 připojíme (rekurze) všechny další části téhož odstavce (oddělíme mezerou).
186 Konec odstavce poznáme tak, že následovník je něco jiného než <o:odstavec/> nebo má atribut typ="začátek".
188 <xsl:template name="spojOdstavce">
189 <xsl:param name="část"/>
190 <xsl:copy-of select="$část/child::node()"/>
191 <xsl:variable name="následovník" select="$část/following-sibling::node()[1]"/>
192 <xsl:if test="$následovník/name() = 'o:odstavec' and not($následovník/@typ = 'začátek')">
193 <xsl:text> </xsl:text>
194 <xsl:call-template name="spojOdstavce">
195 <xsl:with-param name="část" select="$následovník"/>
201 <!-- Ve třetím kole smažeme prázdné mešuge odstavce. -->
202 <xsl:template mode="třetíKolo" match="o:odstavec[
203 count(child::node()) = 0
206 count(child::node()) = 1
210 matches(text(), '^\s*$')
213 <xsl:text> </xsl:text>
215 <!-- Převedeme z <o:odstavec/> na <p/> -->
216 <xsl:template match="o:odstavec" mode="třetíKolo">
218 <xsl:copy-of select="child::node()"/>
221 <!-- Všechno ostatní zkopírujeme, jak je. -->
222 <xsl:template match="*" mode="třetíKolo">
223 <xsl:copy-of select="."/>