helpers/mimeXhtmlPart-make-paragraphs.xsl
author František Kučera <franta-hg@frantovo.cz>
Mon, 17 Oct 2011 00:54:52 +0200
changeset 84 7a3514a9e4fe
parent 83 668014315a54
child 86 92b2e3903ef1
permissions -rwxr-xr-x
Drupal: funkce pro obalování textu <html><body> značkami.
     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"/>
    12 	
    13 	<xsl:param name="cssTřída"/>
    14 	
    15 	<!-- Celý dokument -->
    16 	<xsl:template match="/">
    17 		<html>
    18 			<body>
    19 			
    20 				<xsl:variable name="prvníKolo">
    21 					<xsl:apply-templates select="h:html/h:body/node()" mode="prvníKolo"/>
    22 				</xsl:variable>
    23 				
    24 				<xsl:variable name="druhéKolo">
    25 					<xsl:apply-templates select="$prvníKolo" mode="druhéKolo"/>
    26 				</xsl:variable>
    27 				
    28 				<xsl:apply-templates select="$druhéKolo" mode="třetíKolo"/>
    29 				
    30 			</body>
    31 		</html>
    32 	</xsl:template>
    33 	
    34 	
    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/>
    40 		</xsl:element>
    41     </xsl:template>
    42     
    43     
    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*'"/>
    46     
    47 	
    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
    69 			$prvek/name() = 'var'
    70 			"/>
    71 		<!-- …případně další, pokud je budeme chtít podporovat. -->
    72 	</xsl:template>
    73 	
    74 	
    75 	<!-- Funkce: zda je prvek začátkem odstavce. -->
    76 	<xsl:template name="začátekOdstavce" as="xs:boolean">
    77 		<xsl:param name="prvek"/>
    78 		
    79 		<xsl:variable name="inlineElement" as="xs:boolean">
    80 			<xsl:call-template name="inlineElement"><xsl:with-param name="prvek" select="$prvek"/></xsl:call-template>
    81 		</xsl:variable>
    82 		
    83 		<xsl:variable name="předchůdce" select="$prvek/preceding-sibling::node()[1]"/>
    84 		
    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>
    87 		</xsl:variable>
    88 		
    89 		<xsl:variable name="textovýUzel" select="boolean($prvek/self::text())"/>
    90 				
    91 		<xsl:sequence select="
    92 			($inlineElement or $textovýUzel) 
    93 			and 
    94 			(
    95 				($inlineElementPředchůdce and matches($prvek, concat('^', $oddělovač, '.*')))
    96 				or
    97 				not($inlineElementPředchůdce)
    98 				or
    99 				not($předchůdce)
   100 			)
   101 			and
   102 			(
   103 				not($předchůdce/self::text())
   104 				or
   105 				matches($předchůdce/self::text(), concat('.*', $oddělovač, '$'))
   106 			)
   107 			"/>
   108 	</xsl:template>
   109 	
   110 	
   111 	<!--
   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/>.
   114 	-->
   115 	<xsl:template match="text()" mode="prvníKolo">
   116 	
   117 		<xsl:variable name="začátekOdstavce" as="xs:boolean">
   118 			<xsl:call-template name="začátekOdstavce">
   119 				<xsl:with-param name="prvek" select="."/>
   120 			</xsl:call-template>
   121 		</xsl:variable>
   122 		
   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>
   127 				</xsl:if>
   128 				<xsl:value-of select="."/>
   129 			</xsl:element>
   130 		</xsl:for-each>
   131 	
   132 	</xsl:template>
   133 	
   134 	<!-- 
   135 		Inline elementy zavíráme do <o:odstavec typ=""/>,
   136 		ostatní vkládáme, jak jsou.
   137 	-->
   138 	<xsl:template match="*" mode="prvníKolo">
   139 	
   140 		<xsl:variable name="inlineElement" as="xs:boolean">
   141 			<xsl:call-template name="inlineElement">
   142 				<xsl:with-param name="prvek" select="."/>
   143 			</xsl:call-template>
   144 		</xsl:variable>
   145 		
   146 		<xsl:choose>
   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="."/>
   152 					</xsl:call-template>
   153 				</xsl:variable>
   154 				<xsl:element name="o:odstavec">
   155 					<xsl:if test="$začátekOdstavce">
   156 						<xsl:attribute name="typ">začátek</xsl:attribute>
   157 					</xsl:if>
   158 					<xsl:copy-of select="."/>
   159 				</xsl:element>
   160 			</xsl:when>
   161 			<xsl:otherwise>				
   162 				<xsl:copy-of select="."/>
   163 			</xsl:otherwise>		
   164 		</xsl:choose>
   165 	
   166 	</xsl:template>
   167 	
   168 	<!-- V druhém kole spojíme jednotlivé části odstavců. -->
   169 	<xsl:template match="o:odstavec[@typ='začátek']" mode="druhéKolo">
   170 		<o:odstavec>
   171 			<xsl:call-template name="spojOdstavce">
   172 				<xsl:with-param name="část" select="."/>
   173 			</xsl:call-template>
   174 		</o:odstavec>
   175 	</xsl:template>
   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="."/>
   181 	</xsl:template>
   182 	
   183 	
   184 	<!--
   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".
   188 	-->
   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"/>
   197 			</xsl:call-template>
   198 		</xsl:if>
   199 	</xsl:template>
   200 	
   201 	
   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 
   205 		or 
   206 		(
   207 			count(child::node()) = 1 
   208 			and
   209 			text()
   210 			and
   211 			matches(text(), '^\s*$')
   212 		)
   213 		]">
   214 		<xsl:text> </xsl:text>	
   215 	</xsl:template>
   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>
   221 			</xsl:if>
   222 			<xsl:apply-templates select="child::node()" mode="kopíruj"/>
   223 		</xsl:element>
   224 	</xsl:template>
   225 	<!-- Všechno ostatní zkopírujeme, jak je. -->
   226 	<xsl:template match="*" mode="třetíKolo">
   227 		<xsl:copy-of select="."/>
   228 	</xsl:template>
   229 	
   230 	
   231 </xsl:stylesheet>