helpers/mimeXhtmlPart-make-paragraphs.xsl
author František Kučera <franta-hg@frantovo.cz>
Sun Oct 16 20:55:46 2011 +0200 (2011-10-16)
changeset 81 b51ab80c7a9d
child 83 668014315a54
permissions -rw-r--r--
Drupal: XSL pro vytváření <p>odstavců</p> z textu přímo uvnitř html/body
hranice mezi odstavci se poznají podle prázdného řádku (případně podle blokového elementu).
Naopak inline elementy jsou zahrnuty do odstavce. Příklad

První odstavec.
Druhý řádek téhož odstavce.

Druhý odstavec obsahující <em>nějaký inline element</em>.
Stále jsme v druhém odstavci.

Třetí odstavec…
<p>skutečný odstavec, jak to má být</p>
Toto už je čtvrtý resp. pátý odstavec, přestože tu nebyl žádný prázdný řádek.
franta-hg@81
     1
<?xml version="1.0" encoding="UTF-8"?>
franta-hg@81
     2
<xsl:stylesheet version="2.0"
franta-hg@81
     3
	xmlns="http://www.w3.org/1999/xhtml"
franta-hg@81
     4
	xmlns:h="http://www.w3.org/1999/xhtml"
franta-hg@81
     5
	xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
franta-hg@81
     6
	xmlns:fn="http://www.w3.org/2005/xpath-functions"
franta-hg@81
     7
	xmlns:svg="http://www.w3.org/2000/svg"
franta-hg@81
     8
	xmlns:xs="http://www.w3.org/2001/XMLSchema"
franta-hg@81
     9
	xmlns:o="https://trac.frantovo.cz/odstavcovac-TODO-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX-/wiki/xmlns/odstavcovac"
franta-hg@81
    10
	exclude-result-prefixes="fn h xs">
franta-hg@81
    11
	<xsl:output method="xml" indent="yes" encoding="UTF-8"/>
franta-hg@81
    12
	
franta-hg@81
    13
	
franta-hg@81
    14
	<!-- Celý dokument -->
franta-hg@81
    15
	<xsl:template match="/">
franta-hg@81
    16
		<html>
franta-hg@81
    17
			<head>
franta-hg@81
    18
				<style type="text/css">
franta-hg@81
    19
					.mešuge {
franta-hg@81
    20
						background-color: #afa;
franta-hg@81
    21
						border: 1px solid #55f;
franta-hg@81
    22
					}
franta-hg@81
    23
				</style>
franta-hg@81
    24
			</head>
franta-hg@81
    25
franta-hg@81
    26
			<body>
franta-hg@81
    27
			
franta-hg@81
    28
				<xsl:variable name="prvníKolo">
franta-hg@81
    29
					<xsl:apply-templates select="h:html/h:body/node()" mode="prvníKolo"/>
franta-hg@81
    30
				</xsl:variable>
franta-hg@81
    31
				
franta-hg@81
    32
				<xsl:variable name="druhéKolo">
franta-hg@81
    33
					<xsl:apply-templates select="$prvníKolo" mode="druhéKolo"/>
franta-hg@81
    34
				</xsl:variable>
franta-hg@81
    35
				
franta-hg@81
    36
				<xsl:apply-templates select="$druhéKolo" mode="třetíKolo"/>
franta-hg@81
    37
				
franta-hg@81
    38
			</body>
franta-hg@81
    39
		</html>
franta-hg@81
    40
	</xsl:template>
franta-hg@81
    41
    
franta-hg@81
    42
    
franta-hg@81
    43
    <!-- Mezi odstavci je prázdný řádek, můžou být mezery/tabulátory. -->
franta-hg@81
    44
	<xsl:variable name="oddělovač" select="'\n\s*\n\s*'"/>
franta-hg@81
    45
    
franta-hg@81
    46
	
franta-hg@81
    47
	<!-- Funkce: zda jde o XHTML inline element – může se vyskytovat uvnitř odstavců. -->
franta-hg@81
    48
	<xsl:template name="inlineElement" as="xs:boolean">
franta-hg@81
    49
		<xsl:param name="prvek"/>
franta-hg@81
    50
		<xsl:sequence select="
franta-hg@81
    51
			$prvek/name() = 'a' or						
franta-hg@81
    52
			$prvek/name() = 'abbr' or						
franta-hg@81
    53
			$prvek/name() = 'acronym' or						
franta-hg@81
    54
			$prvek/name() = 'b' or						
franta-hg@81
    55
			$prvek/name() = 'br' or						
franta-hg@81
    56
			$prvek/name() = 'cite' or						
franta-hg@81
    57
			$prvek/name() = 'code' or						
franta-hg@81
    58
			$prvek/name() = 'em' or						
franta-hg@81
    59
			$prvek/name() = 'i' or						
franta-hg@81
    60
			$prvek/name() = 'img' or						
franta-hg@81
    61
			$prvek/name() = 'q' or
franta-hg@81
    62
			$prvek/name() = 'span' or
franta-hg@81
    63
			$prvek/name() = 'strong' or
franta-hg@81
    64
			$prvek/name() = 'sub' or
franta-hg@81
    65
			$prvek/name() = 'sup' or
franta-hg@81
    66
			$prvek/name() = 'tt' or
franta-hg@81
    67
			$prvek/name() = 'u' or
franta-hg@81
    68
			$prvek/name() = 'var'
franta-hg@81
    69
			"/>
franta-hg@81
    70
		<!-- …případně další, pokud je budeme chtít podporovat. -->
franta-hg@81
    71
	</xsl:template>
franta-hg@81
    72
	
franta-hg@81
    73
	
franta-hg@81
    74
	<!-- Funkce: zda je prvek začátkem odstavce. -->
franta-hg@81
    75
	<xsl:template name="začátekOdstavce" as="xs:boolean">
franta-hg@81
    76
		<xsl:param name="prvek"/>
franta-hg@81
    77
		
franta-hg@81
    78
		<xsl:variable name="inlineElement" as="xs:boolean">
franta-hg@81
    79
			<xsl:call-template name="inlineElement"><xsl:with-param name="prvek" select="$prvek"/></xsl:call-template>
franta-hg@81
    80
		</xsl:variable>
franta-hg@81
    81
		
franta-hg@81
    82
		<xsl:variable name="předchůdce" select="$prvek/preceding-sibling::node()[1]"/>
franta-hg@81
    83
		
franta-hg@81
    84
		<xsl:variable name="inlineElementPředchůdce" as="xs:boolean">
franta-hg@81
    85
			<xsl:call-template name="inlineElement"><xsl:with-param name="prvek" select="$předchůdce"/></xsl:call-template>
franta-hg@81
    86
		</xsl:variable>
franta-hg@81
    87
		
franta-hg@81
    88
		<xsl:variable name="textovýUzel" select="boolean($prvek/self::text())"/>
franta-hg@81
    89
				
franta-hg@81
    90
		<xsl:sequence select="
franta-hg@81
    91
			($inlineElement or $textovýUzel) 
franta-hg@81
    92
			and 
franta-hg@81
    93
			(
franta-hg@81
    94
				($inlineElementPředchůdce and matches($prvek, concat('^', $oddělovač, '.*')))
franta-hg@81
    95
				or
franta-hg@81
    96
				not($inlineElementPředchůdce)
franta-hg@81
    97
				or
franta-hg@81
    98
				not($předchůdce)
franta-hg@81
    99
			)
franta-hg@81
   100
			and
franta-hg@81
   101
			(
franta-hg@81
   102
				not($předchůdce/self::text())
franta-hg@81
   103
				or
franta-hg@81
   104
				matches($předchůdce/self::text(), concat('.*', $oddělovač, '$'))
franta-hg@81
   105
			)
franta-hg@81
   106
			"/>
franta-hg@81
   107
	</xsl:template>
franta-hg@81
   108
	
franta-hg@81
   109
	
franta-hg@81
   110
	<!--
franta-hg@81
   111
		V prvním kole zavřeme volný text a inline elementy do značek <o:odstavec typ=""/>,
franta-hg@81
   112
		kde typ může být "začátek", což značí, že se jedná o první část budoucího odstavce <p/>.
franta-hg@81
   113
	-->
franta-hg@81
   114
	<xsl:template match="text()" mode="prvníKolo">
franta-hg@81
   115
	
franta-hg@81
   116
		<xsl:variable name="začátekOdstavce" as="xs:boolean">
franta-hg@81
   117
			<xsl:call-template name="začátekOdstavce">
franta-hg@81
   118
				<xsl:with-param name="prvek" select="."/>
franta-hg@81
   119
			</xsl:call-template>
franta-hg@81
   120
		</xsl:variable>
franta-hg@81
   121
		
franta-hg@81
   122
		<xsl:for-each select="fn:tokenize(., $oddělovač)">
franta-hg@81
   123
			<xsl:element name="o:odstavec">
franta-hg@81
   124
				<xsl:if test="$začátekOdstavce or not(position() = 1)">
franta-hg@81
   125
					<xsl:attribute name="typ">začátek</xsl:attribute>
franta-hg@81
   126
				</xsl:if>
franta-hg@81
   127
				<xsl:value-of select="."/>
franta-hg@81
   128
			</xsl:element>
franta-hg@81
   129
		</xsl:for-each>
franta-hg@81
   130
	
franta-hg@81
   131
	</xsl:template>
franta-hg@81
   132
	
franta-hg@81
   133
	<!-- 
franta-hg@81
   134
		Inline elementy zavíráme do <o:odstavec typ=""/>,
franta-hg@81
   135
		ostatní vkládáme, jak jsou.
franta-hg@81
   136
	-->
franta-hg@81
   137
	<xsl:template match="*" mode="prvníKolo">
franta-hg@81
   138
	
franta-hg@81
   139
		<xsl:variable name="inlineElement" as="xs:boolean">
franta-hg@81
   140
			<xsl:call-template name="inlineElement">
franta-hg@81
   141
				<xsl:with-param name="prvek" select="."/>
franta-hg@81
   142
			</xsl:call-template>
franta-hg@81
   143
		</xsl:variable>
franta-hg@81
   144
		
franta-hg@81
   145
		<xsl:choose>
franta-hg@81
   146
			<!-- TODO: zvláštní šablona (match="…") pro inline elementy místo větvení? -->
franta-hg@81
   147
			<xsl:when test="$inlineElement">
franta-hg@81
   148
				<xsl:variable name="začátekOdstavce" as="xs:boolean">
franta-hg@81
   149
					<xsl:call-template name="začátekOdstavce">
franta-hg@81
   150
						<xsl:with-param name="prvek" select="."/>
franta-hg@81
   151
					</xsl:call-template>
franta-hg@81
   152
				</xsl:variable>
franta-hg@81
   153
				<xsl:element name="o:odstavec">
franta-hg@81
   154
					<xsl:if test="$začátekOdstavce">
franta-hg@81
   155
						<xsl:attribute name="typ">začátek</xsl:attribute>
franta-hg@81
   156
					</xsl:if>
franta-hg@81
   157
					<xsl:copy-of select="."/>
franta-hg@81
   158
				</xsl:element>
franta-hg@81
   159
			</xsl:when>
franta-hg@81
   160
			<xsl:otherwise>
franta-hg@81
   161
				<xsl:copy-of select="."/>
franta-hg@81
   162
			</xsl:otherwise>		
franta-hg@81
   163
		</xsl:choose>
franta-hg@81
   164
	
franta-hg@81
   165
	</xsl:template>
franta-hg@81
   166
	
franta-hg@81
   167
	<!-- V druhém kole spojíme jednotlivé části odstavců. -->
franta-hg@81
   168
	<xsl:template match="o:odstavec[@typ='začátek']" mode="druhéKolo">
franta-hg@81
   169
		<o:odstavec>
franta-hg@81
   170
			<xsl:call-template name="spojOdstavce">
franta-hg@81
   171
				<xsl:with-param name="část" select="."/>
franta-hg@81
   172
			</xsl:call-template>
franta-hg@81
   173
		</o:odstavec>
franta-hg@81
   174
	</xsl:template>
franta-hg@81
   175
	<!-- Následující části odstavce přeskočíme – postará se o ně vnitřní smyčka volaná z předchozí šablony. -->
franta-hg@81
   176
	<xsl:template match="o:odstavec" mode="druhéKolo"/>
franta-hg@81
   177
	<!-- Neinline (blokové) elementy vložíme, jak jsou. -->
franta-hg@81
   178
	<xsl:template match="*" mode="druhéKolo">
franta-hg@81
   179
		<xsl:copy-of select="."/>
franta-hg@81
   180
	</xsl:template>
franta-hg@81
   181
	
franta-hg@81
   182
	
franta-hg@81
   183
	<!--
franta-hg@81
   184
		Za první část (parametr, <o:odstavec typ="začátek"/>) resp. její vnitřek
franta-hg@81
   185
		připojíme (rekurze) všechny další části téhož odstavce (oddělíme mezerou).
franta-hg@81
   186
		Konec odstavce poznáme tak, že následovník je něco jiného než <o:odstavec/> nebo má atribut typ="začátek".
franta-hg@81
   187
	-->
franta-hg@81
   188
	<xsl:template name="spojOdstavce">
franta-hg@81
   189
		<xsl:param name="část"/>
franta-hg@81
   190
		<xsl:copy-of select="$část/child::node()"/>
franta-hg@81
   191
		<xsl:variable name="následovník" select="$část/following-sibling::node()[1]"/>
franta-hg@81
   192
		<xsl:if test="$následovník/name() = 'o:odstavec' and not($následovník/@typ = 'začátek')">
franta-hg@81
   193
			<xsl:text> </xsl:text>
franta-hg@81
   194
			<xsl:call-template name="spojOdstavce">
franta-hg@81
   195
				<xsl:with-param name="část" select="$následovník"/>
franta-hg@81
   196
			</xsl:call-template>
franta-hg@81
   197
		</xsl:if>
franta-hg@81
   198
	</xsl:template>
franta-hg@81
   199
	
franta-hg@81
   200
	
franta-hg@81
   201
	<!-- Ve třetím kole smažeme prázdné mešuge odstavce. -->
franta-hg@81
   202
	<xsl:template mode="třetíKolo" match="o:odstavec[
franta-hg@81
   203
		count(child::node()) = 0 
franta-hg@81
   204
		or 
franta-hg@81
   205
		(
franta-hg@81
   206
			count(child::node()) = 1 
franta-hg@81
   207
			and
franta-hg@81
   208
			text()
franta-hg@81
   209
			and
franta-hg@81
   210
			matches(text(), '^\s*$')
franta-hg@81
   211
		)
franta-hg@81
   212
		]">
franta-hg@81
   213
		<xsl:text> </xsl:text>	
franta-hg@81
   214
	</xsl:template>
franta-hg@81
   215
	<!-- Převedeme z <o:odstavec/> na <p/> -->
franta-hg@81
   216
	<xsl:template match="o:odstavec" mode="třetíKolo">
franta-hg@81
   217
		<p class="mešuge">
franta-hg@81
   218
			<xsl:copy-of select="child::node()"/>
franta-hg@81
   219
		</p>
franta-hg@81
   220
	</xsl:template>
franta-hg@81
   221
	<!-- Všechno ostatní zkopírujeme, jak je. -->
franta-hg@81
   222
	<xsl:template match="*" mode="třetíKolo">
franta-hg@81
   223
		<xsl:copy-of select="."/>
franta-hg@81
   224
	</xsl:template>
franta-hg@81
   225
	
franta-hg@81
   226
	
franta-hg@81
   227
</xsl:stylesheet>