Ice Bear SoftJak se tvoří tyto stránky

Toto je pokus o kultivované programování transformačního stylu. Co kultivované programování (literate programming) znamená? Je to přístup, kdy jeden zdrojový soubor obsahuje současně programový kód i jeho podrobnou dokumentaci. Nějaký nástroj z něj pak vybere programový kód, aby mohl být spuštěn, a jiný nástroj vytvoří krásně vytištěnou dokumentaci. Existují systémy WEB (nezaměňovat za World Wide Web) pro většinu programovacích jazyků a balíky ltxdoc a přidružený docstrip pro LaTeX. Všechny tyto nástroje lze najít na CTAN.

Zde je nutno připojit jazykovou poznámku. Někteří překladatelé anglických textů zaměňují slovo literate, které znamená gramotný, vzdělaný, kultivovaný, se slovem literary, jež znamená literární. Překlad literární programování je tedy zcestný. Z výše uvedených významů se mi v tomto kontextu nejvíce líbí kultivované programování. Opačné slovo, illiterate, znamená pouze negramotný. Neříkejte proto těm, kdo používají tradiční programátorský styl, že jejich přístup je illiterate. Nemají to rádi.

XSLT jako takové je vhodný nástroj pro kultivované programování. Několik takových systémů lze najít na webu. Neznám však žádný nástroj určený ke kultivovanému programování stylů XSLT. Přestože noweb nebo jiný konfigurovatelný nástroj by mohl být použit pro kultivované programování transformačního stylu, rozhodl jsem se zůstat u řešení vycházejícího čistě z XML. Snažil jsem se, aby zdrojový kód i styly byly co nejjednodušší. Proto atribut test v elementech <xsl:if><xsl:when> zobrazuje "<" a ">", zatímco skutečný obsah je &lt;&gt;. Testy též obsahují uvozovky uvnitř uvozovek, což je nepřípustné. Ve skutečném kódu se střídají uvozovky s apostrofy.

No oo.xml

Obsah

1. Úvod
2. Volba XML schématu
3. Formátování stránky
4. Volba procesoru XSLT
5. Bootstrapping
6. Styl pro transformaci do HTML
  6.1. Režimy
  6.2. Výběr jazyka
  6.3. Prolog stylu
  6.4. Šablony pro manuál
  6.5. Datum a čas modifikace souboru
  6.6. Kapitoly a podkapitoly
  6.7. Šablony pro obsah
  6.8. Logo s hypertextovým odkazem
  6.9. Hypertextové odkazy
  6.10. JavaScriptové obrázky
  6.11. Komentáře
  6.12. Ukrytí části obsahu
  6.13. Uživatelská informace
  6.14. Instrukce pro zpracování
  6.15. Ostatní elementy
  6.16. Šablony pro výpis příkladů kódu
  6.17. Výpis stylu pro bootstraping
  6.18. Textové uzly
7. Transformační styl pro manuál
  7.1. Modifikované šablony pro manuál
  7.2. Logo s hypertextovým odkazem pro manuál
  7.3. Zpracování kořenového elementu
  7.4. Postprocessing
  7.5. Vložení odkazu na kaskádový styl
  7.6. Zápatí stránky
8. Download
9. Automatizace zpracování
10. Aktualizace souborů na serveru

1. Úvod

Stránky mají anglickou i českou verzi. Jejich obsah by měl být týž. Není však jednoduché udržovat konzistentně dvě sady stránek. Je vhodné, když obě jazykové mutace mohou přebývat v jediném souboru. Původně měly stránky dva sloupce s anglickým textem v levém a českým textem v pravém sloupci. Společné části byly zobrazeny v jednom sloupci, který přerušoval dvousloupcovou sazbu.

Dvousloupcová prezentace má své nevýhody. Čtenář je rušen přítomností druhého jazyka. Kromě toho mají některé části textu smysl pouze v jedné jazykové verzi. Vyvážení sloupců je tím narušeno. Bylo tedy rozhodnuto, že nové uspořádání bude mít samostatné české a anglické stránky, které budou generovány ze společného zdroje zapsaného v XML.

 Začátek stránky 

2. Volba XML schématu

První otázkou je, jaký vstupní formát máme použít. Nabízí se standardní DocBook. Tento formát je však dosti komplikovaný. Poskytuje nepřeberné možnosti, které však nevyužijeme, protože text má sloužit výhradně pro webové stránky a nepředpokládá se žádné jiné zpracování. Důležitý je zejména vzhled stránek. Sice lze stáhnout nástroj, který transformuje dokument používající DocBook do HTML, ale úpravy těchto stylů by byly dosti pracné. Proto byl tento formát odmítnut.

Nejstarší verze stránek byla psána přímo v HTML. Jako nejpřirozenější se ukázalo obohacení HTML o několik elementů. Tak vznikla druhá verze v době, kdy jsem XML a XSLT ještě moc neuměl a na tomto projektu jsem se je učil. Nyní jsem dospěl do stavu, kdy si uvědomuji, že řadu věcí jsem dělal komplikovaně a nekoncepčně. Opět jsem si vytýčil smělý plán, kdy se ukázalo, že umím méně, než jsem si myslel. Opět jsem se při psaní tohoto dokumentu naučil řadu novinek. Myšlenka obohacení HTML o několik elementů však stále přežívá.

Již v první verzi, kterou jsem generoval z XML, jsem chtěl rozšiřující elementy vzít z vlastního jmenného prostoru. Nelíbilo se mi, že hlavní element <html> pak obsahoval deklaraci tohoto jmenného prostoru, přestože se do stránky žádný z mých elementů nedostal. Tehdy jsem nevěděl, že prefix mého jmenného souboru stačí uvést v elementu <xsl:stylesheet> v atributu exclude-result-prefixes. Nyní jsem znovu použití jmenného prostoru uvážil. Dospěl jsem k závěru, že vstupní formát je definován mými vlastními tagy, které se záměrně v mnoha případech shodují s elementy HTML. Tím jsem si své řešení ospravedlnil.

 Začátek stránky 

3. Formátování stránky

Při formátování stránky lze postupovat dvěma krajními způsoby:

  1. všechny formátovací příkazy uvést v kódu HTML
  2. formátování plně svěřit kaskádovému stylu (CSS)

První metoda vede k nepřehlednému kódu. Sice by to nemuselo vadit, protože stránky generujeme z XML, ale formátovacími značkami by se zaneřádil transformační styl. Druhá metoda má následující nevýhody:

  1. Implementace kaskádových stylů je v některých prohlížečích neúplná.
  2. V některých prohlížečích má implementace kaskádových stylů chyby. Dosti často se nepřenese správně údaj o rozlišení obrazovky, takže např. definice rozměrů v jiných jednotkách než v pixelech má nepředvídatelné výsledky.
  3. Některé prohlížeče nepodporují kaskádové styly vůbec.
  4. Je-li odkaz na kaskádový styl nesprávný, pak Netscape místo požadované stránky nabídne jen chybovou zprávu, že se nepodařilo najít styl. Mozilla již tuto chybu nemá a v případě, že styl nemůže najít, se chová, jako by styl nebyl požadován.
  5. Uživatel může mít z nejrůznějších důvodů podporu kaskádových stylů vypnutu. Hlavním důvodem je často náprava výše zmíněné chyby, pokud má uživatel Netscape.

Z obecného hlediska tedy musíme formátování kaskádovým stylem odmítnout. Na druhé straně nám kaskádové styly nabízejí užitečné možnosti, z nichž některé přímo v HTML nejsou. Můžeme tedy udělat kompromis: základní formátování, které musí být zachováno ve všech prohlížečích, řešit přímo prostředky HTML, a kaskádový styl využít pro zkrášlení stránek. Takto tvořené stránky zobrazí dokonce i Lynx.

V budoucnu možná i kaskádový styl bude programován kultivovaně. Nyní je psán přímo. Můžete si prohlédnout jeho textovou verzi.

 Začátek stránky 

4. Volba procesoru XSLT

Pro zpracování těchto stránek byl vybrán procesor Saxon, protože patří mezi nejrychlejší a je napsán v Javě, takže funguje ve všech operačních systémech. Transfornační styl byl původně psán pro verzi 6.5.2, nyní byl modifikován tak, aby fungoval s verzí 8, která používá XSLT 2.0. V popisu zůstává několik poznámek, jak to bylo uděláno pro XSLT 1.0.

 Začátek stránky 

5. Bootstrapping

Smyslem kultivovaného programování je udržet v synchronizaci vlastní kód a jeho dokumentaci. Proto je vše v jednom souboru. Chceme-li stejnou metodu využít při programování transformačního stylu, měli bychom jej tvořit tak, aby puštěn sám na sebe vytvořil vlastní dokumentaci. V principu by to šlo, ale zdrojový soubor by byl komplikovaný a snadno by se v něm nadělaly chyby. Proto si vytvoříme maličký styl, který z XML souboru webmake.xml vytvoří styl pro transformaci do HTML. Tento transformační styl pak použijeme nejen na tvorbu vlastních stránek, ale i na vytvoření dokumentace stylu.

Transformační styl je také XML soubor, proto jej můžeme vytvořit transformací z jiného XML souboru. Abychom to mohli provést, musíme použít drobný trik. Nestačí jen deklarace jmenného prostoru pro XSLT, musíme též deklarovat další prostor, který později použijeme jako alias:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:xslt="namespace-alias"
                version="2.0"
                xmlns:saxon="http://saxon.sf.net/"
                extension-element-prefixes="saxon">

Prefix xsl: je určen jmennému prostoru XSLT, prefix xslt: je přiřazen libovolnému jmennému prostoru. V elementu <xsl:namespace-alias> určíme, že elementy s prefixem xslt: budou mít ve výsledném souboru prefix xsl:. Tak můžeme do šablony zapsat transformační elementy, které se neprovedou, ale zkopírují do výsledného souboru. Kód vysvětlíme dodatečně.

<xsl:namespace-alias stylesheet-prefix="xslt" result-prefix="xsl"/>
<xsl:output method="xml" indent="yes" encoding="utf-8" saxon:character-representation="native"/>
<xsl:strip-space elements="*"/>
<xsl:preserve-space elements="xslt:text xsl:text"/>
<xsl:param name="mode"/>
<xsl:template match="/">
  <xslt:stylesheet version="2.0" saxon:trace="no" exclude-result-prefixes="zw xs" extension-element-prefixes="saxon">
    <xsl:apply-templates select="//zw-pre"/>
  </xslt:stylesheet>
</xsl:template>
<xsl:template match="zw-pre">
  <xsl:if test="@mode=$mode or (not($mode) and not(@mode))">
    <xsl:apply-templates/>
  </xsl:if>
</xsl:template>
<xsl:template match="zw-hide">
  <xsl:apply-templates/>
</xsl:template>
<xsl:template match="*|@*">
  <xsl:copy>
    <xsl:apply-templates select="@*"/>
    <xsl:apply-templates/>
  </xsl:copy>
</xsl:template>
<xsl:template match="text()">
  <xsl:value-of select="." disable-output-escaping="yes"/>
</xsl:template>
<xsl:template match="processing-instruction()">
  <xsl:processing-instruction name="{name()}"><xsl:value-of select="."/></xsl:processing-instruction>
</xsl:template>
<xsl:template match="zw-text">
  <xslt:text>
    <xsl:value-of select="."/>
  </xslt:text>
</xsl:template>

Výstupním formátem je vždy XML kódovaný v UTF-8. Ignorujeme mezery ve všech elementech s výjimkou <xsl:text><xslt:text>. Vlastní šablona vybírá jen obsah elementů <zw-pre> bez ohledu na to, jak hluboko jsou vnořeny. Z jednoho zdroje budeme generovat několik transformačních stylů. Odlišíme je globálním parametrem mode a stejnojmenným atributem elementu <zw-pre>. V souboru webmake.xml, z něhož výsledný styl generujeme, však musí elementy patřit do jmenného prostoru XSLT, jinak by funkční styl nevznikl. Pokud bychom vytvářeli elementy dynamicky pomocí <xsl:element>, museli bychom v šablonách použít prefix xsl:, nikoliv alias xslt:.

Element <zw-hide> slouží k tomu, abychom utajili obsah, který z bezpečnostních důvodů nechceme zveřejnit. Zde musíme jeho obsah zpracovat, ve výpisu kódu jej nahradíme alternativním textem, jak bude uvedeno později.

Při zpracování elementu <xsl:text> a instrukcí pro zpracování potřebujeme zachovat skutečné znaky a nenahrazovat je entitami. Proto použijeme atribut disable-output-escaping='yes'.

Element <zw-text> bude do výsledného stylu transformován jako <xsl:text> a musí v něm být použity znakové entity.

Všimněte si, že v elementu <xslt:stylesheet> nemusíme deklarovat jmenný prostor pro XSLT, protože jej procesor XSLT doplní automaticky. Přesněji řečeno, budou deklarovány dva identické jmenné prostory pro oba prefixy, xslt:xsl:. Nemusíme uvádět ani deklaraci jmenného prostoru pro Saxon, protože XSLT procesor jej doplní všude, kde je třeba. A v tom je kámen úrazu. Tento jmenný prostor je třeba v elementu <xsl:output>, protože obsahuje atribut saxon:character-representation. V elementu <xslt:stylesheet> však formálně nutný není. Atribut extension-element-prefixes však vyžaduje, aby prefixy byly přiřazeny platným jmenným prostorům. Proto přidáváme atribut saxon:trace='no', přestože je to default. Je to pouze donucovací prostředek pro procesor XSLT, aby vložil deklaraci jmenného prostoru.

Zde je nutno upozornit, že v následujících šablonách budeme používat rozšíření procesoru Saxon. S jiným procesorem XSLT nebudou šablony fungovat.

Na konci souboru je samozřejmě uzavírací tag.

</xsl:stylesheet>
 Začátek stránky 

6. Styl pro transformaci do HTML

6.1. Režimy
6.2. Výběr jazyka
6.3. Prolog stylu
6.4. Šablony pro manuál
6.5. Datum a čas modifikace souboru
6.6. Kapitoly a podkapitoly
6.7. Šablony pro obsah
6.8. Logo s hypertextovým odkazem
6.9. Hypertextové odkazy
6.10. JavaScriptové obrázky
6.11. Komentáře
6.12. Ukrytí části obsahu
6.13. Uživatelská informace
6.14. Instrukce pro zpracování
6.15. Ostatní elementy
6.16. Šablony pro výpis příkladů kódu
6.17. Výpis stylu pro bootstraping
6.18. Textové uzly

V předchozí části jsme si vygenerovali transformační styl z dokumentu, který právě čtete. Styl je dosti rozsáhlý. Jeho popis je tedy rozčleněn do kapitol.

6.1. Režimy

Při transformaci dokumentu bude nutno zpracovávat některé elementy opakovaně různým způsobem. Využijeme přitom atribut mode. XSLT 1.0 povoluje zpracování šablony pouze v jednom režimu. Pokud chceme stejnou činnost provádět v několika režimech, musíme si vytvořit pojmenovanou šablonu pro jeden z režimů takto:

<xsl:template match="something" mode="foo" name="something-foo">
  <xsl:text>Do something here</xsl:text>
</xsl:template>

V šablonách pro další režim pouze voláme jménem předchozí šablonu:

<xsl:template match="something" mode="bar">
  <xsl:call-template name="something-foo"/>
</xsl:template>

XSLT 2.0 umožňuje použití šablony ve více režimech. Uvedený příklad lze tedy jednoduše přepsat:

<xsl:template match="something" mode="foo bar">
  <xsl:text>Do something here</xsl:text>
</xsl:template>

Podrobnou syntaxi najdete ve specifikaci na http://www.w3.org/TR/xslt20/#modes.

 Začátek stránky 

6.2. Výběr jazyka

Jednou z hlavních úloh je rozdělení obsahu podle jazyka. Nabízí se využití standardního atributu xml:lang a funkce lang(). Tento přístup má však výhodu, pokud jsou velké části dokumentu v jednom jazyku. My chceme prolínat malé kousky textu v různých jazycích a navíc chceme mít obecné části, které patří do všech jazykových verzí. Využití standardu by nám tedy způsobovalo těžkosti.

Pro výběr obsahu podle jazyka byl tedy vytvořen element <zw>. Původně byl připraven pouze pro dvojjazyčné stránky. Obsahoval jednoduchou podmínku a elementy nemohly být vnořeny.

Zastaralý kód
<xsl:template match="zw" name="zw">
  <xsl:if test="@lang=$DocumentLanguage">
    <xsl:apply-templates/>
  </xsl:if>
</xsl:template>

Nová šablona pro zpracování elementu <zw> je multilinguální a umožňuje vnoření. Element má dva atributy: langnotlang. Oba mohou obsahovat seznam jazykových kódů oddělených mezerami nebo čárkami. Atribut notlang obsahuje seznam jazyků, v nichž se obsah objevit nemá, atribut lang určuje jazyky, v nichž se obsah elementu objeví. Nemá smysl použít oba atributy současně, ale pokud se to stane, má atribut notlang vyšší prioritu. Není-li obsah elementu vkládán do výstupu, zpracují se pouze vnořené elementy <zw>. Pokud není uveden žádný atribut, obsah elementu <zw> funguje jako komentář, který smí obsahovat jakékoliv správně formátované značkování včetně komentářů. Šablona musí fungovat stejně ve všech režimech.

<xsl:template match="zw" mode="#all">
  <xsl:choose>
    <xsl:when test="not(@lang) and not(@notlang)"/>
    <xsl:when test="contains(@notlang, $DocumentLanguage)">
      <xsl:apply-templates select="zw" mode="#current"/>
    </xsl:when>
    <xsl:when test="contains(@lang, $DocumentLanguage) or not(@lang)">
      <xsl:apply-templates mode="#current"/>
    </xsl:when>
    <xsl:otherwise>
      <xsl:apply-templates select="zw" mode="#current"/>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

Jazykovou variantu bude prohlížeč WWW vybírat metodou sjednání obsahu (content negotiation) implementovanou v PHP skriptu. Musíme tedy ke každému zdrojovému dokumentu vytvořit indexový skript. Provedeme to jednoduchým transformačním stylem, který zpracovává pouze kořenový uzel. Všimněte si, že programový kód v PHP generujeme jako text. Komentář definuje místo, kam ISP vloží reklamu. Je až za koncem programového kódu, aby nebyla na stránce dvakrát. Jak poznáte později, skutečná reklama bude vložena při zpracování elementu <document>.

mode = index
<xsl:output method="text" indent="yes" encoding="utf-8"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/">
  <zw-text><?php require 'engine.php'; if ($inc) { include $fn; }
            else virtual($fn); exit; ?>
            <!--WZ-REKLAMA-1.0--> </zw-text>
</xsl:template>
 Začátek stránky 

6.3. Prolog stylu

Výstupní metoda je html a požadujeme odsazení. Pro výběr jazyka musíme znát jeho kód, který zadáme na příkazovém řádku.

<xsl:output method="html" indent="yes" encoding="utf-8"/>
<xsl:param name="DocumentLanguage"/>

V předchozí verzi jsme používali dva maličké styly, které pouze nastavily parametry daného jazyka a načetly hlavní soubor pomocí elementu <xsl:import href="xml2html.xsl"/>.

XML dokument obsahuje řadu mezer, které by rozházely formátování výsledného dokumentu, zejména výpis kódu transformačního stylu. Proto budeme všechny mezery ignorovat. Musíme však zachovat mezery v elementu <xsl:text> a některých dalších textových elementech.

<xsl:strip-space elements="*"/>
<xsl:preserve-space elements="xsl:text p i b li dt dd zw pre"/>

Při dalším zpracování budeme potřebovat jméno dokumentu bez adresářů a bez přípony. Víme, že zdrojový dokument má vždy příponu .xml, proto si do globální proměnné basename uložíme vše mezi posledním lomítkem a touto příponou.

<xsl:variable name="basename">
  <xsl:analyze-string select="saxon:systemId()" regex="[^/]+\.xml$">
    <xsl:matching-substring>
      <xsl:value-of select="."/>
    </xsl:matching-substring>
  </xsl:analyze-string>
</xsl:variable>

Verze pro XSLT 1.0 obsahovala:

Zastaralý kód
<xsl:variable name="basename" select="substring-before(saxon:tokenize(saxon:systemId(),'/')[last()],'.xml')"/>

Na všech stránkách se budeme odkazovat na hlavní stránku a kaskádový styl. Aby stránky nebyly závislé na konkrétním umístění a daly se testovat lokálně, musí být URL relativní. Musíme tedy určit počet zpětných kroků. Základní adresář s XML dokumenty je .../xml/. Zjistíme si tedy systémový identifikátor zpracovávaného souboru a vezmeme vše za tímto řetězcem. Rozdělíme ji na části podle lomítek. Adresáře pak nahradíme dvěma tečkami a výsledek si schováme pro další použití v globální proměnné backdir.

<xsl:variable name="backdir">
  <xsl:analyze-string select="substring-after(saxon:systemId(), "/xml/")" regex="[^/]+/">
    <xsl:matching-substring>
      <xsl:text>../</xsl:text>
    </xsl:matching-substring>
  </xsl:analyze-string>
</xsl:variable>

Zde je kód použitý ve staré verzi:

Zastaralý kód
<xsl:variable name="backdir">
  <xsl:variable name="ntoks" select="count(saxon:tokenize(substring-after(saxon:systemId(), '/xml/'), '/'))"/>
  <xsl:if test="$ntoks > 1">
    <xsl:for-each select="saxon:range(2, $ntoks)">
      <xsl:text>../</xsl:text>
    </xsl:for-each>
  </xsl:if>
</xsl:variable>

Odkaz na domovskou stránku je buď obsah proměnné $backdir, nebo ./.

<xsl:variable name="home">
  <xsl:choose>
    <xsl:when test="$backdir = ''">
      <xsl:text>./</xsl:text>
    </xsl:when>
    <xsl:otherwise>
      <xsl:value-of select="$backdir"/>
    </xsl:otherwise>
  </xsl:choose>
</xsl:variable>

Nakonec si do globálních proměnných uložíme text "Hlavní stránka" v příslušném jazyce. Přípona souboru je vždy .php.

<xsl:variable name="mainpage">
  <xsl:choose>
    <xsl:when test="$DocumentLanguage = 'cs'">
      <xsl:text>Hlavní stránka</xsl:text>
    </xsl:when>
    <xsl:when test="$DocumentLanguage = 'hi'">
      <xsl:text>मुख्य पृष्ठ</xsl:text>
    </xsl:when>
    <xsl:otherwise>
      <xsl:text>Main page</xsl:text>
    </xsl:otherwise>
  </xsl:choose>
</xsl:variable>
<xsl:variable name="htmlext">
  <xsl:text>.php</xsl:text>
</xsl:variable>

Nyní již můžeme zpracovat dokument. V šabloně použijeme jednoduchý trik. Kořenovým elementem v našem formátu musí být <document>. Ověření, že dokument vyhovuje této podmínce, je velmi snadné. V šabloně určíme, že se mají použít další šablony na element <document>. Pokud je tedy kořenový element jiný, bude výsledná stránka obsahovat pouze prázdný element <html>, čehož si snadno všimneme. Instrukce pro zpracování, která se generuje na počátku souboru, slouží k načtení kódu pro výběr jazyka metodou popsanou v předchozí podkapitole.

<xsl:template match="/">
  <xsl:processing-instruction name="php">
if (!function_exists('FindLanguage')) {
require 'functions.php';
EmitHeader(basename($_SERVER['SCRIPT_NAME']));
}
Expires();
?</xsl:processing-instruction>
  <html>
    <xsl:apply-templates select="document"/>
  </html>
</xsl:template>
 Začátek stránky 

6.4. Šablony pro manuál

Z některých stránek se generuje též offline manuál pro distribuční balíčky. Část obsahu má smysl pouze na webových stránkách, jiná část pouze v manuálu. Vytvoříme proto dvě šablony umožńující zápis alternativ. Předpokládáme, že v transformačním stylu pro manuál budou předefinovány.

<xsl:template match="zw-online">
  <xsl:apply-templates/>
</xsl:template>
<xsl:template match="zw-offline"/>

Tyto elementy nesmějí obsahovat elementy <section><title>, přímo ani nepřímo. V případě elementu <title> je řešení snadné, přepínače <zw-online><zw-offline> vložíme dovnitř. V elementu <section> využijeme atributu role. Podrobněji to bude vysvětleno v kapitolách "Kapitoly a podkapitoly" a "Šablony pro obsah". Pro ten účel si připravíme proměnnou obsahující název role, již máme ignorovat.

<xsl:variable name="ignore-role">
offline</xsl:variable>
 Začátek stránky 

6.5. Datum a čas modifikace souboru

XPath má nástroj na zjištění aktuálního data a času, ale neumí zjistit datum a čas modifikace souboru. Ve starší verzi tgransformačního stylu jsme si pomohliexterním programem, který prošel strom zdrojových dokumentů a vytvořil pomocný soubor s požadovanými informacemi. Jméno externího souboru bylo zadáno jako parametr a jeho dokumentní uzel byl uložen do proměnné.

Zastaralý kód
<xsl:param name="FileInfo" required="yes"/>
<xsl:variable name="filenode" select="document($FileInfo)/zw-fileinfo"/>

Výše zmíněný soubor obsahoval pouze prázdné elementy <zw-file>, které měly dva atributy. Atribut name obsahoval jméno souboru, atribut lastmod obsahoval datum a čas poslední modifikace. Datum bylo od času odděleno nezlomitelnou mezerou. Pro efektivnější použití byl definován klíč.

Zastaralý kód
<xsl:key name="flastmod" match="zw-file" use="@name"/>

Tato šablona vracela datum a čas modifikace souboru zadaného jako parametr. Defaultně vracela datum a čas souboru obsahujícího kontextový uzel.

Zastaralý kód
<xsl:template name="flastmod">
  <xsl:param name="file">
    <xsl:value-of select="saxon:system-id()"/>
  </xsl:param>
  <xsl:for-each select="$filenode">
    <xsl:value-of select="key("flastmod", $file)/@lastmod"/>
  </xsl:for-each>
</xsl:template>

Element <zw-datetime> vytvoří datum a čas modifikace souboru s využitím balíčku s rozšiřující funkcí pro Saxon. Jméno souboru se vezme buď z atributu file, nebo, v případě XML souborů, z atributu xmlfile. Pokud není zadán žádný z těchto atributů, vytvoří se datum a čas modifikace souboru obsahujícího kontextový uzel. Šablonu si pojmenujeme, abychom ji mohli použít později.

<xsl:template match="zw-datetime" name="zw-datetime">
  <xsl:choose use-when="function-available("zw:last-modified")">
    <xsl:when test="@file">
      <xsl:value-of select="zw:file-timestamp(@file)"/>
    </xsl:when>
    <xsl:when test="@xmlfile">
      <xsl:value-of select="zw:last-modified(document(@xmlfile))"/>
    </xsl:when>
    <xsl:otherwise>
      <xsl:value-of select="zw:last-modified()"/>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

Datum poslední modifikace získáme odříznutím času z údaje zjištěného předchozí šablonou.

<xsl:template match="zw-date">
  <xsl:variable name="datetime">
    <xsl:call-template name="zw-datetime"/>
  </xsl:variable>
  <xsl:value-of select="substring-before($datetime, "T")"/>
</xsl:template>
 Začátek stránky 

6.6. Kapitoly a podkapitoly

Při zpracování elementu <document> provádíme tři činnosti. Nejprve v hlavičce vytvoříme název stránky, který bude zobrazen v prohlížeči. V druhém kroku vytvoříme odkaz na kaskádový styl. Nakonec zpracujeme tělo dokumentu. Každou z těchto částí provede samostatná šablona, kterou zavoláme elementem <xsl:call-template>. Děláme to čistě z důvodů přehlednosti, neboť každá z těchto šablon je použita pouze na jednom místě.

<xsl:template match="document">
  <head>
    <meta name="google-site-verification" content="pQX0Li9frYMCGMBkoPTHoG3lgeK_Gx9i-BO8-jcjn18"/>
    <meta name="viewport" content="width=device-width, initial-scale=1"/>
    <meta name="http-equiv" content="{concat('Content-Language: ', $DocumentLanguage)}"/>
    <xsl:call-template name="doc-title"/>
    <xsl:if test="@css">
      <xsl:call-template name="doc-css"/>
    </xsl:if>
    <xsl:if test="@redirect">
      <meta http-equiv="refresh" content="{concat('1; ', @redirect)}"/>
    </xsl:if>
    <script>
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){ (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o), m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m) })(window,document,'script','https://www.google-analytics.com/analytics.js','ga'); ga('create', 'UA-98691706-1', 'auto'); ga('send', 'pageview');    </script>
  </head>
  <xsl:call-template name="doc-body"/>
</xsl:template>

Nadpis, který má prohlížeč zobrazit na liště, vezmeme z elementu <title>. Tento element však primárně slouží jako nadpis stránky a pro zobrazení na liště nemusí být vhodný. Pokud tedy dokument obsahuje element <titlebar>, dáme mu přednost. Všimněte si atributu mode='titlebar' v elementu <xsl:apply-templates>. Jeho význam si vysvělíme později.

Zde je také vhodné místo pro vložení dalšího obsahu do elementu <head>. Přidáme obsah všech elementů tohoto jména.

<xsl:template name="doc-title">
  <title>
    <xsl:choose>
      <xsl:when test="count(titlebar)>0">
        <xsl:apply-templates select="titlebar" mode="titlebar"/>
      </xsl:when>
      <xsl:otherwise>
        <xsl:apply-templates select="title" mode="titlebar"/>
      </xsl:otherwise>
    </xsl:choose>
  </title>
  <xsl:apply-templates select="head" mode="title"/>
</xsl:template>

Zpracování těla dokumentu je snadné. Nejprve z elementu <document> zkopírujeme všechny atributy s výjimkou topcss. Pak zobrazíme nadpis. Přidáme k němu návěští top, abychom později mohli vytvářet odkazy na začátek stránky. Šablonu pro zpracování elementu <title> voláme s atributem mode='title'. Poté aplikujeme šablony na všechny elementy. Musíme jim však předat parametr hdr, který bude využit v šabloně pro element <section>. Pokud má atribut top kladnou hodnotu, zavoláme ještě šablonu pro vytvoření odkazu na začátek stránky, kterou si uvedeme později. Na konci stránky vytvoříme standardní patičku.

<xsl:template name="doc-body">
  <body>
    <xsl:copy-of select="@* except (@top|@css)"/>
    <h1 id="top">
      <xsl:apply-templates select="title" mode="title"/>
    </h1>
    <xsl:apply-templates>
      <xsl:with-param name="hdr" select="2"/>
    </xsl:apply-templates>
    <xsl:if test="@top > 0">
      <xsl:call-template name="top-link"/>
    </xsl:if>
    <xsl:call-template name="footer"/>
  </body>
</xsl:template>

Nejprve vynecháme trochu prázdného místa, aby nám případný odkaz na začátek stránky nekolidoval se zápatím. Pak si ověříme, zda náhodou nejsme na hlavní stránce. V takovém případě bychom nezobrazovali odkaz na hlavní stránku, ale jen vodorovnou linku. Nejsme-li v hlavním adresáři, zavoláme šablonu, která přidá odkazy definované v elementech <zw-a>. Potom vložíme odkaz na hlavní dokument daného adresáře. Jeho název vezmeme z elementu <title> zpracovaného v režimu titlebar. Dále zobrazíme copyright a datum poslední modifikace získané pomocí dříve definované šablony. Až nakonec uvedeme odkaz na ostatní jazykové verze, aby to nepletlo indexovací roboty. Kaskádový styl jej přesune na začátek stránky. Komentář <!--WZ-REKLAMA-1.0--> určuje místo, kam server automaticky vloží reklamní proužek. Pod ním se může vyskytnout další reklama načítaná z dokumentu, jehož URL je určeno v atributu reklama.

<xsl:template name="footer">
  <br/>
  <br/>
  <br/>
  <xsl:variable name="urlbase" select="concat($backdir, $basename)"/>
  <xsl:choose>
    <xsl:when test="$urlbase = 'index.xml'">
      <hr/>
    </xsl:when>
    <xsl:otherwise>
      <div class="links">
        <xsl:call-template name="other-links"/>
        <xsl:if test="starts-with($urlbase, '../') and $basename != 'index.xml'">
          <a href="./">
            <xsl:attribute name="title">
              <xsl:choose>
                <xsl:when test="count(document('index.xml', /)/document/titlebar) > 0">
                  <xsl:apply-templates select="document("index.xml", /)/document/titlebar" mode="titlebar"/>
                </xsl:when>
                <xsl:otherwise>
                  <xsl:apply-templates select="document("index.xml", /)/document/title" mode="titlebar"/>
                </xsl:otherwise>
              </xsl:choose>
            </xsl:attribute>
            <xsl:apply-templates select="document("index.xml", /)/document/title" mode="titlebar"/>
          </a>
          <br/>
        </xsl:if>
        <a title="{$mainpage}" href="{$home}">
          <xsl:value-of select="$mainpage"/>
        </a>
      </div>
    </xsl:otherwise>
  </xsl:choose>
  <div id="copyright">
    <xsl:text>&#169; Z. Wagner - Ice Bear Soft, </xsl:text>
    <xsl:value-of select="zw:last-modified()" use-when="function-available("zw:last-modified")"/>
  </div>
  <xsl:text>
</xsl:text>
  <xsl:processing-instruction name="php"> LangLinks(); Counter(); ?</xsl:processing-instruction>
  <xsl:comment>WZ-REKLAMA-1.0</xsl:comment>
  <xsl:if test="@reklama">
    <hr/>
    <xsl:apply-templates select="document(@reklama)" mode="include"/>
  </xsl:if>
</xsl:template>

Tato šablona vloží obsah všech elementů <zw-a> zpracovaných v režimu footer.

<xsl:template name="other-links">
  <xsl:apply-templates select="//zw-a" mode="footer"/>
</xsl:template>

Element <zw-a> má téměř stejnou syntaxi jako element <a>. Jedinou výjimkou je, že atribut title elementu <a> může být v elementu <zw-a> zadán v elementu <title>, abychom mohli mít více jazykových verzí. V režimu footer tedy element <zw-a> nahradíme elementem <a> následovaným řádkovým zlomem, v defaultním režimu jej budeme ignorovat. Pokud je však obsah elementu <zw-a> prázdný, naplníme jej společně s atributem title z názvu odkazovaného dokumentu. Při vkládání odkazu bereme ohled na jazykovou verzi podle atributů langnotlang.

<xsl:template match="zw-a" mode="footer">
  <xsl:choose>
    <xsl:when test="@notlang eq $DocumentLanguage"/>
    <xsl:when test="@lang ne '' and @lang ne $DocumentLanguage"/>
    <xsl:otherwise>
      <xsl:call-template name="zw-a"/>
      <br/>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>
<xsl:template name="zw-a">
  <a>
    <xsl:copy-of select="@*"/>
    <xsl:call-template name="zw-a-content"/>
  </a>
</xsl:template>
<xsl:template match="zw-a"/>
<xsl:template name="zw-a-content">
  <xsl:choose>
    <xsl:when test="count(*) > 0 or string-length(.) > 0">
      <xsl:if test="title">
        <xsl:attribute name="title">
          <xsl:apply-templates select="title" mode="titlebar"/>
        </xsl:attribute>
      </xsl:if>
      <xsl:apply-templates select="*|text() except title"/>
    </xsl:when>
    <xsl:otherwise>
      <xsl:choose>
        <xsl:when test="contains(@href, "#")">
          <xsl:variable name="xml" as="xs:string" select="if (starts-with(@href, "#")) then @href else replace(replace(@href, "/#", "/index.php#"), "\.php#", ".xml#")"/>
          <xsl:variable name="root" select="if (starts-with(@href, "#")) then (/) else document(substring-before($xml, "#"), /)"/>
          <xsl:variable name="title" as="element()" select="$root//section[@label=substring-after($xml,"#")]/title"/>
          <xsl:attribute name="title">
            <xsl:apply-templates select="$title" mode="titlebar"/>
          </xsl:attribute>
          <xsl:apply-templates select="$title" mode="title"/>
        </xsl:when>
        <xsl:otherwise>
          <xsl:variable name="xml" as="xs:string" select="replace(replace(@href, "/$", "/index.php"), "\.php$", ".xml")"/>
          <xsl:attribute name="title">
            <xsl:choose>
              <xsl:when test="count(document($xml, /)/document/titlebar) > 0">
                <xsl:apply-templates select="document($xml, /)/document/titlebar" mode="titlebar"/>
              </xsl:when>
              <xsl:otherwise>
                <xsl:apply-templates select="document($xml, /)/document/title" mode="titlebar"/>
              </xsl:otherwise>
            </xsl:choose>
          </xsl:attribute>
          <xsl:apply-templates select="document($xml, /)/document/title" mode="nologo"/>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

V předchozích šablonách jsme explicitně volali šablonu pro elementy <title>, <titlebar><head>. Při zpracování těla dokumentu se již musí tyto elementy ignorovat. Vytvoříme tedy dvě šablony. První z nich bude obsahovat atribut mode='title titlebar'. Šablona provede běžné zpracování vnořených elementů ve stejném režimu, protože šablony pro vnořené elementy se také mohou lišit. Druhá šablona, která se bude volat ve standardním režimu, bude prázdná, takže elementy budou ignorovány.

<xsl:template match="title|titlebar|head" mode="title titlebar nologo">
  <xsl:apply-templates mode="#current"/>
</xsl:template>
<xsl:template match="title|titlebar|head"/>

Vytvoření odkazu na kaskádový styl je složitější. Pokud jsme v atributu css elementu <document> uvedli přímo URL, je to jednoduché. Problém nastává, pokud jsme místo URL uvedli tečku. Pak se musí vyhodnotit jméno a umístění standardního stylu. Aby stránky nebyly závislé na konkrétním umístění a daly se testovat lokálně, musí být URL relativní. Musíme tedy doplnit správný počet zpětných kroků z globální proměnné backdir a přidat jméno stylu.

<xsl:template name="doc-css">
  <xsl:for-each select="tokenize(@css, '\s+')">
    <xsl:variable name="css">
      <xsl:choose>
        <xsl:when test=".='.'">
          <xsl:value-of select="$backdir"/>
          <xsl:text>css/style.css</xsl:text>
        </xsl:when>
        <xsl:otherwise>
          <xsl:value-of select="."/>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:variable>
    <link rel="stylesheet" href="{$css}" type="text/css"/>
  </xsl:for-each>
  <xsl:variable name="favicon" select="concat($backdir, 'images/favicon.ico')"/>
  <link rel="shortcut icon" type="image/x-icon" href="{$favicon}"/>
</xsl:template>

V několika šablonách budeme potřebovat číslo sekce. Vytvoříme si tedy odpovídající šablonu, kterou pak opakovaně použijeme. Element <xsl:number> nám při použití atributu level='multiple' automaticky očísluje sekce hierarchicky.

<xsl:template name="secnum">
  <xsl:number level="multiple" format="1." count="section[not(@role) or @role != $ignore-role]"/>
</xsl:template>

Podobně si vytvoříme opakovatelně použitelnou šablonu, která vytvoří návěští. Chceme-li se na kapitolu odvolávat sami z jiného místa, musíme jméno návěští uvést v elementu <section> v atributu label. Pokud nám stačí jen použití v automaticky generovaném obsahu, necháme šablonu, aby vytvořila jedinečný identifikátor.

<xsl:template name="seclabel">
  <xsl:choose>
    <xsl:when test="@label">
      <xsl:value-of select="@label"/>
    </xsl:when>
    <xsl:otherwise>
      <xsl:value-of select="generate-id()"/>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

Obsah elementu zpracujeme pouze v případě, že to není zakázáno atributem role (viz Šablony pro manuál). Nejprve si hodnotu návěští uložíme do proměnné seclabel, abychom s ní mohli pohodlněji pracovat. Pak musíme vytvořit element s nadpisem. Úroveň nadpisu získáme z parametru hdr. Vzpomeňte si, že šablona pro element <document> při volání dalších šablon tomuto parametru nastavila hodnotu 2. Element <section> nejvyšší úrovně tedy bude mít nadpis v elementu <h2>. Nadpis bude mít jedinečné návěští a bude automaticky očíslován. Všimněte si, že šablonu pro element <title> znovu voláme v režimu title. Při volání šablon pro další elementy musíme zvýšit hodnotu parametru hdr, aby vnořené sekce používaly správný element pro nadpis. Kořenový element <document> může obsahovat atribut top určující nejhlubší úroveň nadpisu elementu <section>, u něhož máme ještě vytvářet odkaz na začátek stránky. Úroveň nadpisu je uložena v hodnotě proměnné hdr. Několik vnořených sekcí může končit na stejném místě. Pak bychom dostali několik odkazů na začátek stránky za sebou. Proto podmínkou count(following-sibling::node()) > 0 ověříme, že za koncem sekce máme ještě nějaké uzly. Bílé mezery jsou ignorovány, protože jsme v šabloně použili <xsl:strip-space> všude s výjimkou elementu <xsl:text>.

<xsl:template match="section">
  <xsl:param name="hdr"/>
  <xsl:if test="not(@role) or @role != $ignore-role">
    <xsl:variable name="label">
      <xsl:call-template name="seclabel"/>
    </xsl:variable>
    <xsl:element name="{concat('h', string($hdr))}">
      <xsl:attribute name="id" select="$label"/>
      <xsl:call-template name="secnum"/>
      <xsl:text> </xsl:text>
      <xsl:apply-templates select="title" mode="title"/>
    </xsl:element>
    <xsl:apply-templates>
      <xsl:with-param name="hdr" select="$hdr + 1"/>
    </xsl:apply-templates>
    <xsl:if test="/document/@top>=$hdr and count(following-sibling::element()[name()!='zw-a'] except following-sibling::section[@role=$ignore-role]/descendant-or-self::element())>0">
      <xsl:call-template name="top-link"/>
    </xsl:if>
  </xsl:if>
</xsl:template>

Nadpis může obsahovat hypertextový odkaz, který je nutno zachovat. Zavoláme si tedy šablonu pro <zw-a>, která pracuje v požadovaném režimu.

<xsl:template match="a" mode="title">
  <xsl:call-template name="zw-a"/>
</xsl:template>
<xsl:template name="top-link">
  <xsl:variable name="top">
    <xsl:text>&#160;</xsl:text>
    <xsl:call-template name="top"/>
    <xsl:text>&#160;</xsl:text>
  </xsl:variable>
  <div>
    <table class="top" align="right" border="1" frame="box" rules="none">
      <tr>
        <td>
          <a href="#top" title="{$top}">
            <xsl:value-of select="$top"/>
          </a>
        </td>
      </tr>
    </table>
  </div>
</xsl:template>

Text, který bude zobrazen v odkazu na začátek stránky, si vytvoříme pro přehlednost v oddělené šabloně.

<xsl:template name="top">
  <xsl:choose>
    <xsl:when test="$DocumentLanguage='cs'">
      <xsl:text>Začátek&#160;stránky</xsl:text>
    </xsl:when>
    <xsl:when test="$DocumentLanguage='en'">
      <xsl:text>Top&#160;of&#160;the&#160;page</xsl:text>
    </xsl:when>
    <xsl:otherwise>
      <xsl:text>Top&#160;of&#160;the&#160;page</xsl:text>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>
 Začátek stránky 

6.7. Šablony pro obsah

Popis šablon pro obsah zahájíme opět pomocnou textovou šablonou. Všimněte si, že šablona má atribut match, aby mohla sloužit ke zpracování elementu <toc-heading>, i atribut name, aby mohla být volána jménem z jiné šablony.

<xsl:template name="toc-heading" match="toc-heading">
  <p>
    <b>
      <xsl:choose>
        <xsl:when test="$DocumentLanguage='cs'">
          <xsl:text>Obsah</xsl:text>
        </xsl:when>
        <xsl:when test="$DocumentLanguage='en'">
          <xsl:text>Contents</xsl:text>
        </xsl:when>
        <xsl:when test="$DocumentLanguage='hi'">
          <xsl:text>विषय-सूची</xsl:text>
        </xsl:when>
        <xsl:otherwise>
          <xsl:text>Contents</xsl:text>
        </xsl:otherwise>
      </xsl:choose>
    </b>
  </p>
</xsl:template>

Element <toc> slouží k zobrazení obsahu, a to jak na začátku stránky, tak obsahu konkrétní sekce. Pokud však daná sekce žádné vnořené sekce nemá, měl by se element ignorovat. Musíme tedy nejprve zjistit, zda element, v němž je <toc> uveden, nějaké sekce obsahuje. To by se dalo snadno ověřit podmínkou count(../section) > 0. My však budeme potřebovat i maximální hloubku vnoření. K jejímu určení potřebujeme XPath 2.0. Cyklem for vytvoříme sekvenci všech elementů <section>, které již žádnou sekci neobsahují, a vypočteme počet předků těchto elementů. Do sekvence jsme přidali též kořenový uzel, aby sekvence nebyla prázdná, kdyby daná sekce již žádné vnořené sekce neobsahovala. Současně jsme odebrali sekce, jež mají být ignorovány (viz Šablony pro manuál). Najdeme maximum počtu předků a od něj odečteme počet předků aktuální sekce. Je-li hloubka vnoření kladná, bude obsah zobrazen. Nejprve zpracujeme obsah elementu <toc>. Je li obsah elementu prázdný a současně má atribut heading hodnotu yes, zavoláme šablonu toc-heading. Nakonec aplikujeme šablony na rodičovský element <section>. Všimněte si, že šablony budou zpracovány v režimu toc a předáváme jako parametr pojmenovaný span hodnotu proměnné depth.

<xsl:template match="toc">
  <xsl:variable name="depth">
    <xsl:value-of select="max(for $s in ((..//section[not(section)]|/) except (//element()[role=$ignore-role]/descendant-or-self::element())) return count($s/ancestor::element())) - count(../ancestor::element())"/>
  </xsl:variable>
  <xsl:if test="$depth > 0">
    <xsl:choose>
      <xsl:when test="count(*) > 0">
        <xsl:apply-templates/>
      </xsl:when>
      <xsl:when test="@heading='yes'">
        <xsl:call-template name="toc-heading"/>
      </xsl:when>
    </xsl:choose>
    <table border="0" frame="none" rules="none" class="toc">
      <xsl:apply-templates select="../section" mode="toc">
        <xsl:with-param name="span" select="$depth"/>
      </xsl:apply-templates>
    </table>
  </xsl:if>
</xsl:template>

Stará metoda používala XPath 1.0 a rozšíření procesoru Saxon. Začínali jsme výrazem ../section a v cyklu <saxon:while> jsme do něj postupně přidávali /section a přičítali jedničku do proměnné depth. Tehdy ještě nebyl automaticky generován offline manuál, takže element <section> neměl atribut role.

Zastaralý kód
<xsl:variable name="depth" select="0" saxon:assignable="yes"/>
<xsl:variable name="path" saxon:assignable="yes">
  <xsl:text>../section</xsl:text>
</xsl:variable>
<saxon:while test="count(saxon:evaluate($path)) > 0">
  <saxon:assign name="depth" select="$depth + 1"/>
  <saxon:assign name="path">
    <xsl:value-of select="concat($path, '/section')"/>
  </saxon:assign>
</saxon:while>

Nyní jsme se dostali ke kódu, který vkládá záznamy do obsahu. Máme-li vnořené sekce, chtěli bychom, aby v obsahu byly odpovídajícím způsobem odsazeny. Toho lze dosáhnout nějakým výčtovým elementem v HTML. Bohužel, <ol> nám první úroveň očísluje, ke druhé úrovni přidá písmena, a už vůbec nezachová hierarchické číslování. Sice by to šlo vyřešit v kaskádovém stylu, ale jak již bylo řečeno, kaskádové styly nejsou všude implementovány správně, v některých prohlížečích nejsou implementovány vůbec. Obsah musíme tedy vytvořit tak, aby byl viditelný i v prohlížeči, který kaskádovému stylu nerozumí. Proto předchozí šablona založila pro obsah tabulku. Abychom mohli odsazovat nadpisy vnořených sekcí, musíme na začátku každého řádku tabulky uvést prázdnou buňku přes odpovídající počet sloupců. V následujícím sloupci je číslo zarovnané vpravo a na závěr vložíme přes odpovídající počet sloupců název sekce. Název získáme z elementu <title>, ale jeho šablonu musíme volat v režimu toc. Číslo i návěští zjistíme pomocí šablon, které jsme používali již dříve.

Parametru span byla při prvním volání předána hodnota maximálního vnoření, parametr indent měl defaultní nulovou hodnotu. Po zápisu řádku zpracujeme vnořený element <section>, přičemž indent o jedničku zvětšíme a span zmenšíme. Rekurze tedy dospěje do okamžiku, kdy budeme zpracovávat vnořenou sekci s nulovou hodnotou parametru span. Tabulka se nám pak rozjede. Jenže naštěstí k tomu nemůže dojít. Předem jsme si vypočetli maximální hloubku vnoření a taková sekce tedy v dokumentu není. Nemusíme tedy v šabloně používat podmínku, protože <xsl:apply-templates> žádný element pro nulovou hodnotu parametru span nenajde.

Podobně jako v kapitole "Kapitoly a podkapitoly" zpracujeme pouze elementy, kde to není zakázáno atributem role.

<xsl:template match="section" mode="toc">
  <xsl:param name="indent" select="0"/>
  <xsl:param name="span" select="-1"/>
  <xsl:if test="not(@role) or @role != $ignore-role">
    <xsl:variable name="label">
      <xsl:call-template name="seclabel"/>
    </xsl:variable>
    <tr>
      <xsl:if test="$indent > 0">
        <td>
          <xsl:if test="$indent > 1">
            <xsl:attribute name="colspan">
              <xsl:value-of select="$indent"/>
            </xsl:attribute>
          </xsl:if>
          <xsl:text>&#160;</xsl:text>
        </td>
      </xsl:if>
      <td align="right">
        <a href="{concat('#', $label)}">
          <xsl:call-template name="secnum"/>
        </a>
      </td>
      <td>
        <xsl:if test="$span > 1">
          <xsl:attribute name="colspan">
            <xsl:value-of select="$span"/>
          </xsl:attribute>
        </xsl:if>
        <a href="{concat('#', $label)}">
          <xsl:apply-templates select="title" mode="toc"/>
        </a>
      </td>
    </tr>
    <xsl:apply-templates select="section" mode="toc">
      <xsl:with-param name="indent" select="$indent + 1"/>
      <xsl:with-param name="span" select="$span - 1"/>
    </xsl:apply-templates>
  </xsl:if>
</xsl:template>

Hypertextové odkazy budeme v režimu toc ignorovat, bude zachován pouze jejich obsah.

<xsl:template match="a" mode="toc">
  <xsl:call-template name="zw-a-content"/>
</xsl:template>
 Začátek stránky 

6.8. Logo s hypertextovým odkazem

Ze všech stránek by mělo být jasné, komu patří. Proto budeme chtít v pravém horním rohu logo s odkazem na hlavní stránku. Vytvoříme si tedy užitečnou šablonu.

<xsl:template match="zw-logo" mode="#default title">
  <a title="{$mainpage}" href="{$home}">
    <img src="{concat($backdir, 'images/ibslogo1.gif')}" width="175" height="45" alt="Ice Bear Soft" align="right" border="0"/>
  </a>
</xsl:template>

Element <zw-logo> se bude používat na začátku elementu <title>. V režimu titlebar jej tedy budeme ignorovat.

<xsl:template match="zw-logo" mode="titlebar nologo"/>
 Začátek stránky 

6.9. Hypertextové odkazy

Často se odkazujeme na vlastní dokumenty a chtěli bychom, aby se atribut title a text doplnil z názvu příslušného dokumentu. Element <a> tedy zpracujeme stejnou šablonou, kterou jsme použili pro element <zw-a> v režimu footer. Stejně zpracujeme pomocný element <zw-label>.

<xsl:template match="a|zw-label">
  <xsl:call-template name="zw-a"/>
</xsl:template>
 Začátek stránky 

6.10. JavaScriptové obrázky

Některé obrázky chceme zobrazit v samostatném okně pomocí externí JavaScriptové funkce. Kód pro její volání vygenerujeme v PHP, takže výstupem šablony bude instrukce pro zpracování.

<xsl:template match="zw-jsimg">
  <xsl:processing-instruction name="php"><xsl:text>jsimg('</xsl:text>
<xsl:value-of select="@src"/><xsl:text>', '</xsl:text>
<xsl:value-of select="@align"/><xsl:text>');</xsl:text>
?</xsl:processing-instruction>
</xsl:template>

Funkce jsimg spoléhá na images.js a obsahuje:

# JavaScript images
function jsimg($src, $align) {
if ($align) $align = "align=\"$align\"";
$sz = GetImageSize($src);
$thsrc = '';
if (preg_match('/^(.+)(\.[^.]+)$/', $src, $parts)) {
  $thsrc = $parts[1] . '_small' . $parts[2];
  $thsz = GetImageSize($thsrc);
?>
<script language="JavaScript">
<!--
<?php printf("img('%s', %d, %d, '%s', %d, %d, '%s')",
             $thsrc, $thsz[0], $thsz[1], $src, $sz[0], $sz[1], $align); ?>
// -->
</script>
<noscript>
<a href="<?php echo $src; ?>" target="image">
<img src="<?php echo $thsrc; ?>" hspace=5 vspace=1 width=<?php
     echo $thsz[0]; ?> height=<?php printf('%d %s', $thsz[1], $align); ?>>
</a></noscript>
<?php
}}
 Začátek stránky 

6.11. Komentáře

Někdy potřebujeme do zdrojového souboru napsat text, který se má na výstupu objevit jako komentář. Vytvoříme si proto element <zw-comment>. Může se hodit například při vytváření instrukcí pro kód vkládaný na straně serveru (server side includes).

<xsl:template match="zw-comment">
  <xsl:comment><xsl:apply-templates/></xsl:comment>
</xsl:template>
 Začátek stránky 

6.12. Ukrytí části obsahu

Některé elementy nechceme z bezpečnostních důvodů zobrazit. Uzavřeme je proto do elementu <zw-hide> a přidáme náhradní text do atributu alt.

<xsl:template match="zw-hide">
  <span class="hide">
    <xsl:value-of select="@alt"/>
  </span>
</xsl:template>
 Začátek stránky 

6.13. Uživatelská informace

Někdy potřebujeme uložit do části dokumentu speciální informaci, přičemž nechceme využít jen komentáře. Hodilo by se, kdybychom části dokumentu mohli označit a jednoduchým způsobem volit, zda se mají při generování stránek zpracovat. Zavedeme si proto element <zw-info>, který může mít libovolné atributy s libovolným obsahem. Má-li atribut include hodnotu yes, bude obsah tohoto elementu zpracován. Má-li atribut include jinou hodnotu nebo zcela chybí, bude obsah elementu ignorován.

<xsl:template match="zw-info">
  <xsl:if test="@include = "yes"">
    <xsl:apply-templates/>
  </xsl:if>
</xsl:template>
 Začátek stránky 

6.14. Instrukce pro zpracování

Instrukce pro zpracování PHP budou pouze zkopírovány, avšak s připojeným otazníkem na konci.

<xsl:template match="processing-instruction("php")">
  <xsl:processing-instruction name="php"><xsl:value-of select="."/><xsl:text>?</xsl:text>
</xsl:processing-instruction>
</xsl:template>

Ostatní instrukce pro zpracování budou ignorovány.

<xsl:template match="processing-instruction()" mode="#all"/>
 Začátek stránky 

6.15. Ostatní elementy

Všechny ostatní elementy, které nemají explicitní šablony, pouze zkopírujeme včetně atributů. Nechceme zde použít <xsl:copy>, protože by se nám do výstupního elementu dostaly deklarace všech jmenných prostorů. Stejnou činnost provádíme ve standardním režimu i v režimu title.

<xsl:template match="*" mode="#default title nologo">
  <xsl:element name="{name()}">
    <xsl:apply-templates select="@*"/>
    <xsl:apply-templates mode="#current"/>
  </xsl:element>
</xsl:template>

Kopii atributů lze vytvořit snadno pomocí <xsl:copy-of>.

<xsl:template match="@*">
  <xsl:copy-of select="."/>
</xsl:template>

V některých šablonách budeme vkládat celé dokumenty, ale nechceme generovat hlavičku. Použijeme proto režim include.

<xsl:template match="/" mode="include">
  <xsl:apply-templates/>
</xsl:template>

Na závěr si uvedeme šablonu pro odkaz na stránky protestu proti SW patentům.

<xsl:template match="zw-nopatents" mode="#default title">
  <xsl:variable name="title">
    <xsl:choose>
      <xsl:when test="$DocumentLanguage = "cs"">
        <xsl:text>Žádné softwarové patenty!</xsl:text>
      </xsl:when>
      <xsl:otherwise>
        <xsl:text>No software patents!</xsl:text>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:variable>
  <a href="http://noepatents.eu.org" title="{$title}">
    <img width="480" height="60" src="{concat($backdir, 'images/swpatbanner.en.png')}">
      <xsl:copy-of select="@*"/>
    </img>
  </a>
</xsl:template>
 Začátek stránky 

6.16. Šablony pro výpis příkladů kódu

V dokumentu se často odvoláváme na nějaké elementy. Bylo by nepohodlné, kdybychom museli do elementu <code> přepisovat úhlové závorky pomocí entit &lt;&gt; a nakonec použít ukončovací tag </code>. Vytvoříme si tedy pomocnou šablonu pro element <zw-elem>. Element může mít atribut q, jehož jediná smysluplná hodnota je lomítko. Písmeno q jsme vybrali pouze proto, že je na kraji klávesnice.

<xsl:template match="zw-elem" mode="#default title toc nologo">
  <xsl:call-template name="zw-elem">
    <xsl:with-param name="prefix">
      <xsl:value-of select="@q"/>
    </xsl:with-param>
  </xsl:call-template>
</xsl:template>

Často se odvoláváme i na elementy s prefixem xsl:. Abychom jej nemuseli explicitně uvádět, vytvoříme si element <zw-xelem>, který jej doplní sám.

<xsl:template match="zw-xelem" mode="#default title toc nologo">
  <xsl:call-template name="zw-elem">
    <xsl:with-param name="prefix">
      <xsl:value-of select="@q"/>
      <xsl:text>xsl:</xsl:text>
    </xsl:with-param>
  </xsl:call-template>
</xsl:template>

Celou práci provede následující šablona. Od předchozích šablon dostane parametr prefix, který může obsahovat lomítko a/nebo prefix xsl:.

<xsl:template name="zw-elem">
  <xsl:param name="prefix"/>
  <code>
    <xsl:text>&lt;</xsl:text>
    <xsl:value-of select="$prefix"/>
    <xsl:apply-templates/>
    <xsl:text>&gt;</xsl:text>
  </code>
</xsl:template>

Styl pro bootstraping vytvářel transformační styl pro konverzi do HTML z obsahu elementů <zw-pre>. My nyní obsah těchto elementů zobrazíme jako příklady kódu. Pro větší přehlednost jim kaskádovým stylem dáme žluté pozadí. Za jistých okolností však mohou být řádky dlouhé a přesáhnou šířku okna prohlížeče. Vlastnost background-color pak nefunguje správně. Zdá se, že pozadí tabulky se obarví správně vždy. Obsah elementu <zw-pre> tedy zobrazíme v jednosloupcové jednořádkové tabulce. Prohlížeč, který nerozumí kaskádovým stylům, jej alespoň zarámuje. Pouze v případě, že element <zw-pre> má atribut lang, přidáme k tabulce nadpis.

V dokumentu nyní nemůžeme použít element <pre>, protože by se nám rozpadlo formátování tohoto příkladu. Místo něj si tedy zavedeme synonymum <verbatim>. Tento nový element se liší od <zw-pre> zejména tím, že jeho obsah se nedostane do vygenerovaného transformačního stylu. Konec řádku, vkládaný na několika místech, je estetická záležitost. Důležité je pouze to, že vnořené elementy zpracováváme v režimu verbatim.

<xsl:template match="zw-pre|verbatim" name="verbatim">
  <xsl:text>&#10;</xsl:text>
  <table border="2" frame="box" rules="rows" cellpadding="5" class="pre">
    <xsl:if test="@mode">
      <tr>
        <th>
          <xsl:choose>
            <xsl:when test="@mode="old"">
              <xsl:choose>
                <xsl:when test="$DocumentLanguage='cs'">
                  <xsl:text>Zastaralý kód</xsl:text>
                </xsl:when>
                <xsl:when test="$DocumentLanguage='en'">
                  <xsl:text>Obsolete code</xsl:text>
                </xsl:when>
                <xsl:otherwise>
                  <xsl:text>Obsolete code</xsl:text>
                </xsl:otherwise>
              </xsl:choose>
            </xsl:when>
            <xsl:otherwise>
              <xsl:text>mode = </xsl:text>
              <xsl:value-of select="@mode"/>
            </xsl:otherwise>
          </xsl:choose>
        </th>
      </tr>
    </xsl:if>
    <tr>
      <td>
        <pre>
          <xsl:if test="name() != 'verbatim'">
            <xsl:text>&#10;</xsl:text>
          </xsl:if>
          <xsl:apply-templates mode="verbatim"/>
        </pre>
      </td>
    </tr>
  </table>
  <xsl:text>&#10;</xsl:text>
</xsl:template>

Nyní zpracujeme všechny elementy. Protože v HTML musí být převedeny úhlové závorky na znakové entity, nebude procesor XSLT výstup považovat za elementy a odsazení tedy musíme vložit sami. Hodnotu odsazení máme v parametru indent, jehož hodnota je zpočátku prázdná. Za entitou označující otvírací závorku zapíšeme jméno elementu a zavoláme šablonu pro atributy, pochopitelně v režimu verbatim. Pokud je element prázdný, ukončíme jej lomítkem a pravou závorkou, v opačném případě zavoláme šablonu pro vložené elementy, přičemž zvětšíme odsazení. Pak musíme ještě zapsat ukončovací tag.

<xsl:template match="*" mode="verbatim">
  <xsl:param name="indent"/>
  <xsl:param name="amount">
    <xsl:text>  </xsl:text>
  </xsl:param>
  <xsl:param name="endline">
    <xsl:text>&#10;</xsl:text>
  </xsl:param>
  <xsl:value-of select="$indent"/>
  <xsl:text>&lt;</xsl:text>
  <xsl:value-of select="name()"/>
  <xsl:apply-templates select="@*" mode="verbatim"/>
  <xsl:choose>
    <xsl:when test="count(*)=0 and string-length(.)=0">
      <xsl:text>/&gt;</xsl:text>
      <xsl:value-of select="$endline"/>
    </xsl:when>
    <xsl:otherwise>
      <xsl:text>&gt;&#10;</xsl:text>
      <xsl:apply-templates mode="verbatim">
        <xsl:with-param name="indent">
          <xsl:value-of select="concat($indent, $amount)"/>
        </xsl:with-param>
      </xsl:apply-templates>
      <xsl:value-of select="$indent"/>
      <xsl:text>&lt;/</xsl:text>
      <xsl:value-of select="name()"/>
      <xsl:text>&gt;</xsl:text>
      <xsl:value-of select="$endline"/>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

Obsah elementu <pre> zobrazíme analogicky, ale ponecháme formátování, jaké bylo v elementu použito. Element je totiž uveden v <xsl:preserve-spaces>.

<xsl:template match="pre">
  <table border="2" frame="box" rules="rows" cellpadding="5" class="pre">
    <tr>
      <td>
        <pre>
          <xsl:apply-templates/>
        </pre>
      </td>
    </tr>
  </table>
</xsl:template>

Šablony pro zpracování elementů <xsl:text>, <zw-text>, <xsl:processing-instruction><xsl:comment> jsou mírně odlišné. Chceme totiž element z celým obsahem ponechat na jednom řádku.

<xsl:template match="xsl:text|zw-text|xsl:comment|xsl:processing-instruction" mode="verbatim">
  <xsl:param name="indent"/>
  <xsl:value-of select="$indent"/>
  <xsl:text>&lt;</xsl:text>
  <xsl:value-of select="name()"/>
  <xsl:apply-templates select="@*" mode="verbatim"/>
  <xsl:text>&gt;</xsl:text>
  <xsl:choose>
    <xsl:when test="count(*)=0">
      <xsl:value-of select="."/>
    </xsl:when>
    <xsl:otherwise>
      <xsl:apply-templates mode="verbatim">
        <xsl:with-param name="endline"/>
      </xsl:apply-templates>
    </xsl:otherwise>
  </xsl:choose>
  <xsl:text>&lt;/</xsl:text>
  <xsl:value-of select="name()"/>
  <xsl:text>&gt;&#10;</xsl:text>
</xsl:template>

Zpracování atributů je snadné. Zapíšeme jméno atributu, rovnítko a hodnotu v uvozovkách.

<xsl:template match="@*" mode="verbatim">
  <xsl:text> </xsl:text>
  <xsl:value-of select="name()"/>
  <xsl:text>="</xsl:text>
  <xsl:value-of select="normalize-space(.)"/>
  <xsl:text>"</xsl:text>
</xsl:template>

V textových uzlech požadujeme normalizaci mezer.

<xsl:template match="text()" mode="verbatim">
  <xsl:value-of select="normalize-space(.)"/>
</xsl:template>
 Začátek stránky 

6.17. Výpis stylu pro bootstraping

Relativní cesta k transformačnímu souboru pro bootstraping je definována v dokumentu jako externí entita pojmenovaná bootstrap. V kapitole Bootstrapping je styl načten uvedením &bootstrap;. Jeho kořenovým elementem je <xsl:stylesheet>. Následující šablona tedy zpracuje obsah souboru stejnou šablonou, kterou zde používáme na elementy <zw-pre>. Všimněte si, že kořenový element se ve výpisu neobjeví. Je to jediný element, který byl v dokumentaci připsán ručně.

<xsl:template match="xsl:stylesheet">
  <xsl:call-template name="verbatim"/>
</xsl:template>
 Začátek stránky 

6.18. Textové uzly

V textových uzlech v češtině chceme doplnit nezlomitelné mezery za jednopísmenné předložky a spojky. Bohužel ve výpisu není vidět ani nezlomitelná mezera za $1 ani to, že poslední hranatá závorka v druhém parametru funkce replace obsahule [ &#x0d;&#x0a;].

<xsl:template match="text()">
  <xsl:variable name="lang" as="node()*" select="(ancestor-or-self::*/@xml:lang | ancestor-or-self::*/@lang)[last()]"/>
  <xsl:choose>
    <xsl:when test="$lang = 'cs'">
      <xsl:value-of select="replace(., '([ (,][AaIiKkOoSsUuVvZz])[ ]+', '$1 ')"/>
    </xsl:when>
    <xsl:otherwise>
      <xsl:value-of select="."/>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

Nezlomitelné mezery nesmí být vkládány v elementech pro zápis kódu.

<xsl:template match="zw-pre/text()|pre/text()|code/text()|verbatim/text()">
  <xsl:value-of select="."/>
</xsl:template>
 Začátek stránky 

7. Transformační styl pro manuál

7.1. Modifikované šablony pro manuál
7.2. Logo s hypertextovým odkazem pro manuál
7.3. Zpracování kořenového elementu
7.4. Postprocessing
7.5. Vložení odkazu na kaskádový styl
7.6. Zápatí stránky

Transformační styl pro manuál importuje styl pro transformaci do HTML a pouze předefinuje několik šablon a proměnných.

mode = offline
<xsl:import href="xml2html.xsl"/>
<xsl:variable name="ignore-role">
online</xsl:variable>

7.1. Modifikované šablony pro manuál

Výklad těchto šablon byl již uveden v kapitole "Šablony pro manuál". Zde je definována modifikovaná verze s prohozenými rolemi.

mode = offline
<xsl:template match="zw-offline">
  <xsl:apply-templates/>
</xsl:template>
<xsl:template match="zw-online"/>
 Začátek stránky 

7.2. Logo s hypertextovým odkazem pro manuál

Hypertextový odkaz spojený s logem musí odkazovat na stránku na internetu. Logo musí být přidáno k manuálu, aby jej bylo možno prohlížet skutečně offline. Jeho umístění proto určíme parametrem.

mode = offline
<xsl:variable name="ibslogo">
ibslogo1.gif</xsl:variable>
<xsl:variable name="home">
http://icebearsoft.euweb.cz/</xsl:variable>
<xsl:template match="zw-logo" mode="#default title">
  <a title="{$mainpage}" href="{$home}">
    <img src="{$ibslogo}" width="175" height="45" alt="Ice Bear Soft" align="right" border="0"/>
  </a>
</xsl:template>
 Začátek stránky 

7.3. Zpracování kořenového elementu

Manuál je vždy čisté HTML bez kódu v PHP. Vytvoříme proto element <html> a v něm zpracujeme element <document>. Hypertextové odkazy mohou vznikat nejrůznějšími mechanismy. Abychom z relativních odkazů, směřujících na jiné stránky, udělali absolutní, uložíme si výsledek transformace do proměnné a následně jej budeme transformovat znovu. Předpokládáme, že obrázky i kaskádové styly jsou přiloženy, takže jejich odkazy upravovat nemusíme.

mode = offline
<xsl:template match="/">
  <xsl:variable name="offline-document" as="element()">
    <html>
      <xsl:apply-templates select="document"/>
    </html>
  </xsl:variable>
  <xsl:apply-templates select="$offline-document" mode="offline-postprocessing"/>
</xsl:template>
 Začátek stránky 

7.4. Postprocessing

Jediné, co musíme dodatečně zpracovat, je atribut href elementu <a>. Nebudeme zasahovat do odkazů uvnitř stránky ani do odkazů absolutních.

mode = offline
<xsl:template match="a" mode="offline-postprocessing">
  <a>
    <xsl:copy-of select="@*"/>
    <xsl:if test="name(..) != 'span' and name(..) != 'div' and (not(../@id) or ../@id != 'langlinks') and not(contains(@href, '://')) and not(starts-with(@href, '#'))">
      <xsl:attribute name="href">
        <xsl:call-template name="postprocess-href">
          <xsl:with-param name="href">
            <xsl:value-of select="replace(concat($referer, @href), '/\./', '/')"/>
          </xsl:with-param>
        </xsl:call-template>
      </xsl:attribute>
    </xsl:if>
    <xsl:apply-templates mode="#current"/>
  </a>
</xsl:template>

Proměnná referer obsahuje základní URL, tj. http://icebearsoft.euweb.cz/ a část jména souboru za /xml/ až k poslednímu lomítku.

mode = offline
<xsl:variable name="referer">
  <xsl:text>http://icebearsoft.euweb.cz/</xsl:text>
  <xsl:analyze-string select="substring-after(saxon:systemId(), '/xml/')" regex="^(.*?)[^/]+$">
    <xsl:matching-substring>
      <xsl:value-of select="regex-group(1)"/>
    </xsl:matching-substring>
  </xsl:analyze-string>
</xsl:variable>

Nyní se rekurzivní šablonou zbavíme odkazů do rodičovského adresáře.

mode = offline
<xsl:template name="postprocess-href">
  <xsl:param name="href" as="xs:string" required="yes"/>
  <xsl:analyze-string select="$href" regex="$(.*?)/[^/]+/\.\.(/.*)$">
    <xsl:matching-substring>
      <xsl:call-template name="postprocess-href">
        <xsl:with-param name="href">
          <xsl:value-of select="concat(regex-group(1), regex-group(2))"/>
        </xsl:with-param>
      </xsl:call-template>
    </xsl:matching-substring>
    <xsl:non-matching-substring>
      <xsl:value-of select="."/>
    </xsl:non-matching-substring>
  </xsl:analyze-string>
</xsl:template>

Ostatní elementy budou zkopírovány včetně svých atributů.

mode = offline
<xsl:template match="*" mode="offline-postprocessing">
  <xsl:copy>
    <xsl:copy-of select="@*"/>
    <xsl:apply-templates mode="#current"/>
  </xsl:copy>
</xsl:template>
 Začátek stránky 

7.5. Vložení odkazu na kaskádový styl

Podobně jako logo i kaskádový styl musí být přibalen. Jméno a umístění definujeme v parametru transformačního stylu.

mode = offline
<xsl:variable name="css">
style.css</xsl:variable>
<xsl:template name="doc-css">
  <link rel="stylesheet" href="{$css}" type="text/css"/>
</xsl:template>
 Začátek stránky 

7.6. Zápatí stránky

Zápatí bude obsahovat pouze copyright a odkazy na jazykové varianty, nic jiného se zde vyskytovat nebude. Soubory s jinými jazykovými verzemi budou určeny parametrem, kde hlavní jméno souboru (bez pomlčky a bez přípony) bude následováno dvojtečkou, za níž budou uvedeny jazykové kódy oddělené čárkami.

mode = offline
<xsl:param name="langlinks" as="xs:string" required="yes"/>
<xsl:template name="footer">
  <br/>
  <br/>
  <br/>
  <hr/>
  <div id="copyright">
    <xsl:text>&#169; Z. Wagner - Ice Bear Soft, </xsl:text>
    <xsl:value-of select="zw:last-modified()" use-when="function-available("zw:last-modified")"/>
  </div>
  <xsl:text>
</xsl:text>
  <xsl:if test="contains($langlinks, ':')">
    <div id="langlinks">
      <xsl:text>&#160;</xsl:text>
      <xsl:for-each select="tokenize(substring-after($langlinks, ':'), ',')">
        <a href="{concat(substring-before($langlinks, ':'), '-', ., '.html')}">
          <xsl:value-of select="upper-case(.)"/>
        </a>
        <xsl:text>&#160;</xsl:text>
      </xsl:for-each>
    </div>
  </xsl:if>
</xsl:template>
 Začátek stránky 

8. Download

Můžete si stáhnout vygenerované transformační styly. Budete též potřebovat modul s rozšiřující funkcí procesoru Saxon.

 Začátek stránky 

9. Automatizace zpracování

Celý postup vytváření stránek vyžaduje několik akcí, které je nutno provést ve správném pořadí. Přitom některé z nich provést nemusíme, pokud se zdrojové soubory nezměnily. Pro automatizaci celého procesu je použit Ant. Pro uživatele OS/2 mám částečně smutnou zprávu. Spouštěcí skripty byly vytvořeny pro verzi 1.6alpha. Ve verzi 1.6.1 však bylo leccos změněno, takže tyto skripty nefungují. Funkční skripty najdete ve verzi 1.6.2. Informace o změnách si můžete přečíst v Bugzille v chybě číslo 28226. Verze 1.5.x mají chyby specifické pro OS/2, proto je raději nepoužívejte.

Konkrétní antfile, použitý v tomto projektu, bude dokumentován (snad) později. Prozatím si uvedeme jen základní pravidla:

 Začátek stránky 

10. Aktualizace souborů na serveru

WWW stránky vytvářím doma na svém počítači s OS/2. Po otestování je třeba nové a modifikované stránky pomocí FTP odeslat na server. Tato činnost je automatizována pomocí PHP skriptu. PHP však musí běžet jako samostatný program. Skript očekává čtyři parametry:

  1. Kořen lokálního stromu HTML stránek
  2. FTP server
  3. Jméno uživatele pro připojení na FTP server
  4. Heslo
Skript je schopen mazat staré soubory i vytvářet nové adresáře, ale nikdy neruší prázdné adresáře na serveru.

PHP 4.0.6 pro OS/2 měl chybu ve funkci ftp_put. Chyba byla odstraněna ve verzi 4.1.0. PHP 4.2.3 (php.exe) nezná proměnnou $argc, takže nelze rozebírat parametry příkazového řádku, verze 4.3.4 tuto chybu nemá. Bohužel ve verzi 4.3.4 nefunguje ImageJPEG. Pokud potřebujete mít PHP modul v Apachi, generovat dynamicky obrázky a jiné binární soubory a současně používat php.exe, doporučuji modul 4.2.3 pro Apache a 4.3.4 pro použití z příkazového řádku. Verze 4.3.4 však vyžaduje jiný php.ini. Musíte jej specifikovat při volání php.exe pomocí parametru -c.

Zde najdete:

PHP skript používá funkce ftp_sizeftp_mdtm, které nemusí na některých FTP serverech fungovat.

 Začátek stránky