helpers/mimeXhtmlPart-make-paragraphs.xsl
author František Kučera <franta-hg@frantovo.cz>
Mon, 17 Oct 2011 00:56:59 +0200
changeset 86 92b2e3903ef1
parent 83 668014315a54
child 98 763472057819
permissions -rwxr-xr-x
Drupal: oprava XSL odstavců: správné zpracování vnořených značek (např. a/img) v mešuge odstavcích.
     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:xs="http://www.w3.org/2001/XMLSchema"
     8 	xmlns:o="https://trac.frantovo.cz/odstavcovac-TODO-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX-/wiki/xmlns/odstavcovac"
     9 	exclude-result-prefixes="fn h xs o">
    10 	<xsl:output method="xml" indent="yes" encoding="UTF-8" omit-xml-declaration="yes"/>
    11 	
    12 	<xsl:param name="cssTřída"/>
    13 	
    14 	<!-- Celý dokument -->
    15 	<xsl:template match="/">
    16 		<html>
    17 			<body>
    18 			
    19 				<xsl:variable name="prvníKolo">
    20 					<xsl:apply-templates select="h:html/h:body/node()" mode="prvníKolo"/>
    21 				</xsl:variable>
    22 				
    23 				<xsl:variable name="druhéKolo">
    24 					<xsl:apply-templates select="$prvníKolo" mode="druhéKolo"/>
    25 				</xsl:variable>
    26 				
    27 				<xsl:apply-templates select="$druhéKolo" mode="třetíKolo"/>
    28 				
    29 			</body>
    30 		</html>
    31 	</xsl:template>
    32 	
    33 	
    34 	<!-- Kopírujeme elementy, ale vynecháme nepoužité xmlns deklarace: -->
    35 	<xsl:template match="*" mode="kopíruj">
    36 		<xsl:element name="{name()}">
    37 			<xsl:copy-of select="@*"/>
    38 			<xsl:apply-templates mode="kopíruj"/>
    39 		</xsl:element>
    40     </xsl:template>
    41     
    42     
    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*'"/>
    45     
    46 	
    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
    68 			$prvek/name() = 'var'
    69 			"/>
    70 		<!-- …případně další, pokud je budeme chtít podporovat. -->
    71 	</xsl:template>
    72 	
    73 	
    74 	<!-- Funkce: zda je prvek začátkem odstavce. -->
    75 	<xsl:template name="začátekOdstavce" as="xs:boolean">
    76 		<xsl:param name="prvek"/>
    77 		
    78 		<xsl:variable name="inlineElement" as="xs:boolean">
    79 			<xsl:call-template name="inlineElement"><xsl:with-param name="prvek" select="$prvek"/></xsl:call-template>
    80 		</xsl:variable>
    81 		
    82 		<xsl:variable name="předchůdce" select="$prvek/preceding-sibling::node()[1]"/>
    83 		
    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>
    86 		</xsl:variable>
    87 		
    88 		<xsl:variable name="textovýUzel" select="boolean($prvek/self::text())"/>
    89 				
    90 		<xsl:sequence select="
    91 			($inlineElement or $textovýUzel) 
    92 			and 
    93 			(
    94 				($inlineElementPředchůdce and matches($prvek, concat('^', $oddělovač, '.*')))
    95 				or
    96 				not($inlineElementPředchůdce)
    97 				or
    98 				not($předchůdce)
    99 			)
   100 			and
   101 			(
   102 				not($předchůdce/self::text())
   103 				or
   104 				matches($předchůdce/self::text(), concat('.*', $oddělovač, '$'))
   105 			)
   106 			"/>
   107 	</xsl:template>
   108 	
   109 	
   110 	<!--
   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/>.
   113 	-->
   114 	<xsl:template match="text()" mode="prvníKolo">
   115 	
   116 		<xsl:variable name="začátekOdstavce" as="xs:boolean">
   117 			<xsl:call-template name="začátekOdstavce">
   118 				<xsl:with-param name="prvek" select="."/>
   119 			</xsl:call-template>
   120 		</xsl:variable>
   121 		
   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>
   126 				</xsl:if>
   127 				<xsl:value-of select="."/>
   128 			</xsl:element>
   129 		</xsl:for-each>
   130 	
   131 	</xsl:template>
   132 	
   133 	<!-- 
   134 		Inline elementy zavíráme do <o:odstavec typ=""/>,
   135 		ostatní vkládáme, jak jsou.
   136 	-->
   137 	<xsl:template match="*" mode="prvníKolo">
   138 	
   139 		<xsl:variable name="inlineElement" as="xs:boolean">
   140 			<xsl:call-template name="inlineElement">
   141 				<xsl:with-param name="prvek" select="."/>
   142 			</xsl:call-template>
   143 		</xsl:variable>
   144 		
   145 		<xsl:choose>
   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="."/>
   151 					</xsl:call-template>
   152 				</xsl:variable>
   153 				<xsl:element name="o:odstavec">
   154 					<xsl:if test="$začátekOdstavce">
   155 						<xsl:attribute name="typ">začátek</xsl:attribute>
   156 					</xsl:if>
   157 					<xsl:copy-of select="."/>
   158 				</xsl:element>
   159 			</xsl:when>
   160 			<xsl:otherwise>				
   161 				<xsl:copy-of select="."/>
   162 			</xsl:otherwise>		
   163 		</xsl:choose>
   164 	
   165 	</xsl:template>
   166 	
   167 	<!-- V druhém kole spojíme jednotlivé části odstavců. -->
   168 	<xsl:template match="o:odstavec[@typ='začátek']" mode="druhéKolo">
   169 		<o:odstavec>
   170 			<xsl:call-template name="spojOdstavce">
   171 				<xsl:with-param name="část" select="."/>
   172 			</xsl:call-template>
   173 		</o:odstavec>
   174 	</xsl:template>
   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="."/>
   180 	</xsl:template>
   181 	
   182 	
   183 	<!--
   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".
   187 	-->
   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"/>
   196 			</xsl:call-template>
   197 		</xsl:if>
   198 	</xsl:template>
   199 	
   200 	
   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 
   204 		or 
   205 		(
   206 			count(child::node()) = 1 
   207 			and
   208 			text()
   209 			and
   210 			matches(text(), '^\s*$')
   211 		)
   212 		]">
   213 		<xsl:text> </xsl:text>	
   214 	</xsl:template>
   215 	<!-- Převedeme z <o:odstavec/> na <p/> -->
   216 	<xsl:template match="o:odstavec" mode="třetíKolo">
   217 		<xsl:element name="p">
   218 			<xsl:if test="$cssTřída">
   219 				<xsl:attribute name="class"><xsl:value-of select="$cssTřída"/></xsl:attribute>
   220 			</xsl:if>
   221 			<xsl:apply-templates select="child::node()" mode="kopíruj"/>
   222 		</xsl:element>
   223 	</xsl:template>
   224 	<!-- Všechno ostatní zkopírujeme, jak je. -->
   225 	<xsl:template match="*" mode="třetíKolo">
   226 		<xsl:copy-of select="."/>
   227 	</xsl:template>
   228 	
   229 	
   230 </xsl:stylesheet>