# HG changeset patch # User František Kučera <franta-hg@frantovo.cz> # Date 1318791346 -7200 # Node ID b51ab80c7a9d276cf40bac071ef0c59981c9d4f1 # Parent 1f9e5757caf4eea300fe86d68418071e130637ca 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. diff -r 1f9e5757caf4 -r b51ab80c7a9d helpers/mimeXhtmlPart-make-paragraphs.xsl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/helpers/mimeXhtmlPart-make-paragraphs.xsl Sun Oct 16 20:55:46 2011 +0200 @@ -0,0 +1,227 @@ +<?xml version="1.0" encoding="UTF-8"?> +<xsl:stylesheet version="2.0" + xmlns="http://www.w3.org/1999/xhtml" + xmlns:h="http://www.w3.org/1999/xhtml" + xmlns:xsl="http://www.w3.org/1999/XSL/Transform" + xmlns:fn="http://www.w3.org/2005/xpath-functions" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns:xs="http://www.w3.org/2001/XMLSchema" + xmlns:o="https://trac.frantovo.cz/odstavcovac-TODO-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX-/wiki/xmlns/odstavcovac" + exclude-result-prefixes="fn h xs"> + <xsl:output method="xml" indent="yes" encoding="UTF-8"/> + + + <!-- Celý dokument --> + <xsl:template match="/"> + <html> + <head> + <style type="text/css"> + .mešuge { + background-color: #afa; + border: 1px solid #55f; + } + </style> + </head> + + <body> + + <xsl:variable name="prvníKolo"> + <xsl:apply-templates select="h:html/h:body/node()" mode="prvníKolo"/> + </xsl:variable> + + <xsl:variable name="druhéKolo"> + <xsl:apply-templates select="$prvníKolo" mode="druhéKolo"/> + </xsl:variable> + + <xsl:apply-templates select="$druhéKolo" mode="třetíKolo"/> + + </body> + </html> + </xsl:template> + + + <!-- Mezi odstavci je prázdný řádek, můžou být mezery/tabulátory. --> + <xsl:variable name="oddělovač" select="'\n\s*\n\s*'"/> + + + <!-- Funkce: zda jde o XHTML inline element – může se vyskytovat uvnitř odstavců. --> + <xsl:template name="inlineElement" as="xs:boolean"> + <xsl:param name="prvek"/> + <xsl:sequence select=" + $prvek/name() = 'a' or + $prvek/name() = 'abbr' or + $prvek/name() = 'acronym' or + $prvek/name() = 'b' or + $prvek/name() = 'br' or + $prvek/name() = 'cite' or + $prvek/name() = 'code' or + $prvek/name() = 'em' or + $prvek/name() = 'i' or + $prvek/name() = 'img' or + $prvek/name() = 'q' or + $prvek/name() = 'span' or + $prvek/name() = 'strong' or + $prvek/name() = 'sub' or + $prvek/name() = 'sup' or + $prvek/name() = 'tt' or + $prvek/name() = 'u' or + $prvek/name() = 'var' + "/> + <!-- …případně další, pokud je budeme chtít podporovat. --> + </xsl:template> + + + <!-- Funkce: zda je prvek začátkem odstavce. --> + <xsl:template name="začátekOdstavce" as="xs:boolean"> + <xsl:param name="prvek"/> + + <xsl:variable name="inlineElement" as="xs:boolean"> + <xsl:call-template name="inlineElement"><xsl:with-param name="prvek" select="$prvek"/></xsl:call-template> + </xsl:variable> + + <xsl:variable name="předchůdce" select="$prvek/preceding-sibling::node()[1]"/> + + <xsl:variable name="inlineElementPředchůdce" as="xs:boolean"> + <xsl:call-template name="inlineElement"><xsl:with-param name="prvek" select="$předchůdce"/></xsl:call-template> + </xsl:variable> + + <xsl:variable name="textovýUzel" select="boolean($prvek/self::text())"/> + + <xsl:sequence select=" + ($inlineElement or $textovýUzel) + and + ( + ($inlineElementPředchůdce and matches($prvek, concat('^', $oddělovač, '.*'))) + or + not($inlineElementPředchůdce) + or + not($předchůdce) + ) + and + ( + not($předchůdce/self::text()) + or + matches($předchůdce/self::text(), concat('.*', $oddělovač, '$')) + ) + "/> + </xsl:template> + + + <!-- + V prvním kole zavřeme volný text a inline elementy do značek <o:odstavec typ=""/>, + kde typ může být "začátek", což značí, že se jedná o první část budoucího odstavce <p/>. + --> + <xsl:template match="text()" mode="prvníKolo"> + + <xsl:variable name="začátekOdstavce" as="xs:boolean"> + <xsl:call-template name="začátekOdstavce"> + <xsl:with-param name="prvek" select="."/> + </xsl:call-template> + </xsl:variable> + + <xsl:for-each select="fn:tokenize(., $oddělovač)"> + <xsl:element name="o:odstavec"> + <xsl:if test="$začátekOdstavce or not(position() = 1)"> + <xsl:attribute name="typ">začátek</xsl:attribute> + </xsl:if> + <xsl:value-of select="."/> + </xsl:element> + </xsl:for-each> + + </xsl:template> + + <!-- + Inline elementy zavíráme do <o:odstavec typ=""/>, + ostatní vkládáme, jak jsou. + --> + <xsl:template match="*" mode="prvníKolo"> + + <xsl:variable name="inlineElement" as="xs:boolean"> + <xsl:call-template name="inlineElement"> + <xsl:with-param name="prvek" select="."/> + </xsl:call-template> + </xsl:variable> + + <xsl:choose> + <!-- TODO: zvláštní šablona (match="…") pro inline elementy místo větvení? --> + <xsl:when test="$inlineElement"> + <xsl:variable name="začátekOdstavce" as="xs:boolean"> + <xsl:call-template name="začátekOdstavce"> + <xsl:with-param name="prvek" select="."/> + </xsl:call-template> + </xsl:variable> + <xsl:element name="o:odstavec"> + <xsl:if test="$začátekOdstavce"> + <xsl:attribute name="typ">začátek</xsl:attribute> + </xsl:if> + <xsl:copy-of select="."/> + </xsl:element> + </xsl:when> + <xsl:otherwise> + <xsl:copy-of select="."/> + </xsl:otherwise> + </xsl:choose> + + </xsl:template> + + <!-- V druhém kole spojíme jednotlivé části odstavců. --> + <xsl:template match="o:odstavec[@typ='začátek']" mode="druhéKolo"> + <o:odstavec> + <xsl:call-template name="spojOdstavce"> + <xsl:with-param name="část" select="."/> + </xsl:call-template> + </o:odstavec> + </xsl:template> + <!-- Následující části odstavce přeskočíme – postará se o ně vnitřní smyčka volaná z předchozí šablony. --> + <xsl:template match="o:odstavec" mode="druhéKolo"/> + <!-- Neinline (blokové) elementy vložíme, jak jsou. --> + <xsl:template match="*" mode="druhéKolo"> + <xsl:copy-of select="."/> + </xsl:template> + + + <!-- + Za první část (parametr, <o:odstavec typ="začátek"/>) resp. její vnitřek + připojíme (rekurze) všechny další části téhož odstavce (oddělíme mezerou). + Konec odstavce poznáme tak, že následovník je něco jiného než <o:odstavec/> nebo má atribut typ="začátek". + --> + <xsl:template name="spojOdstavce"> + <xsl:param name="část"/> + <xsl:copy-of select="$část/child::node()"/> + <xsl:variable name="následovník" select="$část/following-sibling::node()[1]"/> + <xsl:if test="$následovník/name() = 'o:odstavec' and not($následovník/@typ = 'začátek')"> + <xsl:text> </xsl:text> + <xsl:call-template name="spojOdstavce"> + <xsl:with-param name="část" select="$následovník"/> + </xsl:call-template> + </xsl:if> + </xsl:template> + + + <!-- Ve třetím kole smažeme prázdné mešuge odstavce. --> + <xsl:template mode="třetíKolo" match="o:odstavec[ + count(child::node()) = 0 + or + ( + count(child::node()) = 1 + and + text() + and + matches(text(), '^\s*$') + ) + ]"> + <xsl:text> </xsl:text> + </xsl:template> + <!-- Převedeme z <o:odstavec/> na <p/> --> + <xsl:template match="o:odstavec" mode="třetíKolo"> + <p class="mešuge"> + <xsl:copy-of select="child::node()"/> + </p> + </xsl:template> + <!-- Všechno ostatní zkopírujeme, jak je. --> + <xsl:template match="*" mode="třetíKolo"> + <xsl:copy-of select="."/> + </xsl:template> + + +</xsl:stylesheet> diff -r 1f9e5757caf4 -r b51ab80c7a9d helpers/mimeXhtmlPart.xsl --- a/helpers/mimeXhtmlPart.xsl Fri Oct 14 17:50:35 2011 +0200 +++ b/helpers/mimeXhtmlPart.xsl Sun Oct 16 20:55:46 2011 +0200 @@ -72,7 +72,7 @@ /** TODO: smazat */ .mešuge { background-color: #afa; - border: 1px solid #5f5; + border: 1px solid #55f; } </style> </head> @@ -162,19 +162,26 @@ Textový uzel → budeme dělat odstavce (rekurzivně se opět zavolá šablona zpracujTělo) --> - <xsl:call-template name="dělejOdstavceX"> + <xsl:call-template name="dělejOdstavce"> <xsl:with-param name="blokTextu" select="$prvek"/> <xsl:with-param name="vnořeno" select="$vnořeno"/> </xsl:call-template> - <!-- TODO: někdy zpracujTělo dalšího prvku --> + <!-- <xsl:variable name="navázat" as="xs:boolean"> <xsl:call-template name="navázat"> <xsl:with-param name="blokTextu" select="$prvek"/> </xsl:call-template> </xsl:variable> - <xsl:if test="not($navázat)">[not(navázat)]</xsl:if> + Někdy zpracujTělo dalšího prvku + <xsl:if test="not($navázat)">[další:] + <xsl:call-template name="zpracujTělo"> + <xsl:with-param name="prvek" select="$prvek/following-sibling::node()[1]"/> + <xsl:with-param name="vnořeno" select="$vnořeno"/> + </xsl:call-template> + </xsl:if> + --> </xsl:when> <xsl:otherwise> @@ -192,7 +199,7 @@ </xsl:if> </xsl:template> - <xsl:variable name="oddělovač" select="'\n\s+\n\s+'"/> + <xsl:variable name="oddělovač" select="'\n\s*\n\s*'"/> <xsl:template name="navázat" as="xs:boolean"> <xsl:param name="blokTextu"/> @@ -217,7 +224,7 @@ "/> </xsl:template> - <xsl:template name="dělejOdstavceX"> + <xsl:template name="dělejOdstavce"> <xsl:param name="blokTextu"/> <xsl:param name="vnořeno" select="false()"/> @@ -230,90 +237,55 @@ </xsl:variable> <xsl:for-each select="fn:tokenize($blokTextu, $oddělovač)"> - <xsl:if test="normalize-space(.)"> + <!-- TODO: ošetřit prázdné odstavce --> + <xsl:if test="normalize-space(.) or true()"> <xsl:choose> <xsl:when test="$vnořeno"> - <xsl:value-of select="."/> - <xsl:if test="$navázat and position() = last()"> - <xsl:call-template name="zpracujTělo"> - <xsl:with-param name="prvek" select="$dalšíUzel"/> - </xsl:call-template> - </xsl:if> - </xsl:when> - <xsl:otherwise> - <p class="mešuge"> + [ <xsl:value-of select="."/> <xsl:if test="$navázat and position() = last()"> + → <xsl:call-template name="zpracujTělo"> <xsl:with-param name="prvek" select="$dalšíUzel"/> <xsl:with-param name="vnořeno" select="true()"/> </xsl:call-template> </xsl:if> + ] + [Avril:] + <xsl:if test="not($navázat) and position() = last()"> + a→ + <xsl:call-template name="zpracujTělo"> + <xsl:with-param name="prvek" select="$dalšíUzel"/> + <xsl:with-param name="vnořeno" select="true()"/> + </xsl:call-template> + </xsl:if> + </xsl:when> + <xsl:otherwise> + <p class="mešuge"> + { + <xsl:value-of select="."/> + <xsl:if test="$navázat and position() = last()"> + s→ + <xsl:call-template name="zpracujTělo"> + <xsl:with-param name="prvek" select="$dalšíUzel"/> + <xsl:with-param name="vnořeno" select="true()"/> + </xsl:call-template> + </xsl:if> + } </p> + [sk8:] + <xsl:if test="not($navázat) and position() = last()"> + → + <xsl:call-template name="zpracujTělo"> + <xsl:with-param name="prvek" select="$dalšíUzel"/> + <xsl:with-param name="vnořeno" select="false()"/> + </xsl:call-template> + </xsl:if> </xsl:otherwise> </xsl:choose> </xsl:if> </xsl:for-each> - <xsl:if test="not($navázat)"> - <xsl:call-template name="zpracujTělo"> - <xsl:with-param name="prvek" select="$dalšíUzel"/> - </xsl:call-template> - </xsl:if> - </xsl:template> - - - - - - - <xsl:template name="dělejOdstavce"> - <xsl:param name="blokTextu"/> - <xsl:variable name="oddělovač" select="'\n\s+\n\s+'"/> - <xsl:for-each select="fn:tokenize(., $oddělovač)"> - <xsl:if test="normalize-space(.)"> - <p class="mešuge"> - <xsl:value-of select="."/> - <!-- - Toto je poslední odstavec bloku textu - a blok nekončí dvěma konci řádku → - může za ním následovat značka (např. odkaz nebo tučné písmo) - vnořená do téhož odstavce - --> - <xsl:if test=" - position() = last() and - not(fn:matches($blokTextu, concat('.*', $oddělovač ,'$'))) - "> - <xsl:variable name="n" select="$blokTextu/following-sibling::*[1]"/> - <xsl:variable name="nn" select="$n/name()"/> - <!-- - Za blokem textu nenásleduje značka, která nemůže být uvnitř odstavce. - --> - <xsl:if test="not( - $nn = 'p' or - $nn = 'div' or - $nn = 'h1' or - $nn = 'h2' or - $nn = 'h3' or - $nn = 'h4' or - $nn = 'h5' or - $nn = 'h6' or - $nn = 'pre' or - $nn = 'table' or - $nn = 'blockquote' or - $nn = 'hr' - )"> - <xsl:apply-templates select="$n"/> - </xsl:if> - - <xsl:call-template name="zpracujTělo"> - <xsl:with-param name="prvek" select="$blokTextu/following-sibling::node()[1]"/> - </xsl:call-template> - - </xsl:if> - </p> - </xsl:if> - </xsl:for-each> </xsl:template>