Pokud má styl více než jednu šablonu, je důležité vědět, jakým způsobem jsou jednotlivé šablony vyvolávány. V této části školení se podíváme na to, jak XSLT procesor určuje šablony, které se mají vyvolat, a na to, jak lze toto chování ovlivnit.
Základem každého stylu jsou šablony. Jejich základní tvar je:
<xsl:template match="vzor
">tělo šablony
</xsl:template>
Tělo šablony přitom přesně definuje, jak se části
transformovaného dokumentu vyhovující
výrazu
budou zpracovávat. V těle
šablony můžeme používat další konstrukce XSLT nebo přímo elementy
z výsledného dokumentu – nejčastěji tedy HTML tagy, protože
generujeme HTML kód.
XPath výraz použitý v atributu match
nemůže být libovolný XPath výraz,
musí to být jen tzv. vzor (pattern). Vzor je takový výraz, který
používá jen osy pro přechod na dětský uzel, atribut případně
//
. V predikátech již můžeme použít celý
repertoár XPathu. Pro každý uzel N
můžeme
zjistit, zda vyhovuje vzoru nebo ne. Pokud je
N
kontextový uzel a výsledek výrazu
//
obsahuje uzel
výraz
N
, pak uzel vzoru vyhovuje.
Mezi dva nejpoužívanější příkazy, které se používají uvnitř
šablony, patří value-of
a apply-templates
. Abychom pochopili
k čemu se mají používat a jaký je mezi rozdíl, musíme nejprve
vědět, v jakém pořadí se zpracovávají jednotlivé šablony.
XSLT procesor na začátku své práce načte do paměti vstupní XML
dokument a vytvoří si jeho stromovou reprezentaci. Tento strom je pak
postupně procházen od kořene v pořadí v jakém jsou elementy
obsaženy v dokumentu (jedná se tedy o průchod do hloubky).
V okamžiku, kdy je nalezena šablona odpovídající uzlu ve stromu,
začne se její obsah zapisovat na výstup. Důležité je, že další potomci
uzlu, pro který byla vybrána šablona, už nejsou dál automaticky
zpracováváni. Pokud tak chceme učinit, musíme uvnitř šablony použít
instrukci <xsl:apply-templates>
. Ta říká, že se
má daná větev stromu zpracovávat dále a mají se pro její uzly hledat
odpovídající šablony.
Pokud chceme v těle šablony použít jen textový obsah
nějakého elementu a jeho podelementů, ale nechceme aplikovat další
šablony, hodí se instrukce <xsl:value-of
select="
. Ta vybere
pouze obsah textových uzlů, které jsou potomky elementu určeného
pomocí výraz
">výrazu
(ten je opět zapsán pomocí
syntaxe XPath).
Pro vyvolávání šablon je tedy důležité pořadí elementů v dokumentu a nikoliv pořadí šablon ve stylu. Na uspořádání šablon ve stylu ve většině případů nezáleží.
Pokud uvnitř šablony použijeme
<xsl:apply-templates/>
začnou se hledat šablony pro všechny děti aktuálního uzlu (uzlu,
pro který se vyvolala šablona obsahující <xsl:apply-templates>
).
Pokud chceme, aby se hledaly šablony pro jinou část dokumentu,
můžeme ji určit použitím atributu select
.
<xsl:apply-templates select="výraz
"/>
Můžeme použít libovolný XPath výraz, který vybere nějakou
množinu uzlů. Můžeme se odvolávat na libovolné místo dokumentu, klidně
dopředu nebo na rodiče (musíme si však dát pozor, abychom se
nezacyklili). Pokud atribut select
nepoužijeme, je to totéž, jako volání:
<xsl:apply-templates select="node()"/>
Tento způsob automaticky nezpracuje dětské uzly, které jsou
atributy nebo jmennými prostory. Pokud je chceme zahrnout do zpracování,
musíme je ručně přidat do select
.
Využití této možnosti si ukážeme na příkladě formátování katalogu zboží do HTML. Dejme tomu, že chceme z katalogu vytvořit jednoduchou HTML stránku s tabulkou, která bude obsahovat název výrobku, jeho kategorii a cenu. Nebude nás teď zajímat popis výrobku a ani informace podrobnější informace o katalogu.
Následující ukázka obsahuje první příklad takového jednoduchého stylu.
Příklad 3.1. Jednoduché formátování katalogu – katalog-strucny.xsl
<?xml version="1.0" encoding="utf-8"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> <xsl:output method="html" encoding="utf-8"/> <xsl:template match="/"> <html> <head> <title>Katalog <xsl:value-of select="katalog/info/firma"/></title> </head> <body> <h1>Katalog <xsl:value-of select="katalog/info/firma"/></h1> <table width="100%" border="1"> <xsl:apply-templates/> </table> </body> </html> </xsl:template> <xsl:template match="polozka"> <tr> <xsl:apply-templates/> </tr> </xsl:template> <xsl:template match="nazev"> <th><xsl:apply-templates/></th> </xsl:template> <xsl:template match="kategorie"> <td align="center"><xsl:apply-templates/></td> </xsl:template> <xsl:template match="cena"> <td align="right"><xsl:apply-templates/> Kč</td> </xsl:template> </xsl:stylesheet>
Když si tento styl vyzkoušíme, zjistíme, že kromě přehledné
tabulky obsahuje spoustu zbytečných údajů. Proč? XSLT procesory mají
v sobě zabudovaných několik implicitních šablon, které mimo jiné
na výstup kopírují veškeré textové uzly, které nebyly zpracovány žádnou
uživatelem definovanou šablonou. Bezhlavé volání <xsl:apply-templates/>
není vždy to
pravé. Tento problém můžeme vyřešit dvěma způsoby. Prvním z nich
je zakázat implicitní šablony. To se však v našem případě nehodí,
protože tuto vlastnost v jiných místech využíváme. Můžeme však
u příslušných volání šablon říci, které uzly se mají zpracovávat.
Hlavní šablona vybere k dalšímu zpracování jen položky katalogu a
uvnitř každé položky vybereme k dalšímu zpracování pouze název,
kategorii a cenu.
Příklad 3.2. Opravené jednoduché formátování katalogu – katalog-strucny2.xsl
<?xml version="1.0" encoding="utf-8"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> <xsl:output method="html" encoding="utf-8"/> <xsl:template match="/"> <html> <head> <title>Katalog <xsl:value-of select="katalog/info/firma"/></title> </head> <body> <h1>Katalog <xsl:value-of select="katalog/info/firma"/></h1> <table width="100%" border="1"> <xsl:apply-templates select="//polozka"/> </table> </body> </html> </xsl:template> <xsl:template match="polozka"> <tr> <xsl:apply-templates select="nazev|kategorie|cena"/> </tr> </xsl:template> <xsl:template match="nazev"> <th><xsl:apply-templates/></th> </xsl:template> <xsl:template match="kategorie"> <td align="center"><xsl:apply-templates/></td> </xsl:template> <xsl:template match="cena"> <td align="right"><xsl:apply-templates/> Kč</td> </xsl:template> </xsl:stylesheet>
V mnoha případech potřebujeme některé uzly dokumentu zpracovat opakovaně, pokaždé však jiným způsobem. Například můžeme chtít katalog zformátovat tak, aby na začátku byla přehledná tabulka s názvem a cenou výrobku, pod ní pak však všechny podrobnosti. Většinu uzlů v dokumentu tak musíme zpracovat dvakrát, pokaždé však jinak.
Pro tyto účely můžeme u každé šablony definovat režim
pomocí atributu mode
.
<xsl:template match="výraz
" mode="název režimu
">
Takováto šablona se vyvolá jen pro ty uzly dokumentu, které
vyhovují výrazu
, a navíc bylo jejich
zpracování vyvoláno pomocí příkazu <xsl:apply-templates mode="
.název
režimu
"/>
Následující příklad ukazuje využití této vlastnosti v praxi – generujeme jednu stránku s úsporným i detailním popisem výrobku.
Příklad 3.3. Využití režimů – katalog-detaily.xsl
<?xml version="1.0" encoding="utf-8"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> <xsl:output method="html" encoding="utf-8"/> <xsl:template match="/"> <HTML> <HEAD> <TITLE>Katalog <xsl:value-of select="katalog/info/firma"/></TITLE> </HEAD> <BODY> <H1>Katalog <xsl:value-of select="katalog/info/firma"/></H1> <TABLE WIDTH="100%" BORDER="1"> <xsl:apply-templates select="//polozka"/> </TABLE> <xsl:apply-templates select="//polozka" mode="detailni"/> </BODY> </HTML> </xsl:template> <xsl:template match="polozka"> <TR> <xsl:apply-templates select="nazev|kategorie|cena"/> </TR> </xsl:template> <xsl:template match="nazev"> <TH><xsl:apply-templates/></TH> </xsl:template> <xsl:template match="kategorie"> <TD align="right"><xsl:apply-templates/></TD> </xsl:template> <xsl:template match="cena"> <TD align="right"><xsl:apply-templates/> Kč</TD> </xsl:template> <xsl:template match="polozka" mode="detailni"> <xsl:apply-templates mode="detailni"/> <HR/> </xsl:template> <xsl:template match="nazev" mode="detailni"> <H2><xsl:apply-templates mode="detailni"/></H2> </xsl:template> <xsl:template match="kategorie" mode="detailni"> <EM><xsl:apply-templates mode="detailni"/></EM> </xsl:template> <xsl:template match="cena" mode="detailni"> <STRONG> - <xsl:apply-templates mode="detailni"/> Kč</STRONG> </xsl:template> <xsl:template match="popis" mode="detailni"> <P><xsl:apply-templates mode="detailni"/></P> </xsl:template> <xsl:template match="br" mode="detailni"> <BR/> </xsl:template> </xsl:stylesheet>
Zvláště v rozsáhlejších stylech se může stát, že jeden uzel dokumentu lze zpracovat pomocí několika různých šablon. XSLT proto definuje pravidla, která se používají při řešení těchto konfliktů.
Každá šablona má svoji prioritu, kterou můžeme nastavit pomocí
atributu priority
. Pokud prioritu
nenastavíme ručně, odvodí si jí XSLT procesor sám pomocí několika
jednoduchých pravidel. Při řešení konfliktů mezi šablonami pak platí
pravidlo, že se použije šablona s vyšší prioritou. Pokud se při
zpracování ve stylu vyskytnou dvě šablony, které vyhovují uzlu a mají
stejnou prioritu, XSLT procesor buď ohlásí chybu, nebo použije
poslední definovanou šablonu.
Automatické stanovování priorit využívá následující pravidla:
prioritu -0.5 dostanou šablony, které mají výraz obsahující
divoké znaky (*
, @*
) nebo pouze testující typ uzlu (node()
, comment()
, processing-instruction()
, text()
);
prioritu -0.25 dostanou šablony, které se skládají
z prefixu jmenného prostoru a divokého znaku (prefix:*
);
prioritu 0 získají šablony, které testují pouze název uzlu;
všechny ostatní šablony dostanou prioritu 0.5.
Pokud má šablona ve vzoru několik výrazů oddělených `|
', při hledání priority se považují za
několik samostatných šablon.
Při určování priorit pro šablony většinou platí velice jednoduché pravidlo – čím specifičtější šablona, tím by měla mít vyšší prioritu.
Pokud si nejsme jisti, jaké priority podle specifikace XSLT spočítá procesor, je možná jednodušší uvést je u každé problematické šablony.
<xsl:template match="výraz
" priority="priorita
"/>
Pokud po zavolání <xsl:apply-templates>
nenalezne
procesor pro nějaký uzel žádnou uživatelem definovanou šablonu, kterou
by mohl použít, dojde na některou ze zabudovaných šablon.
<!-- Šablona pro postupné zpracování celého dokumentu --> <xsl:template match="*|/"> <xsl:apply-templates/> </xsl:template> <!-- Totéž pro libovolný režim --> <xsl:template match="*|/" mode="režim"> <xsl:apply-templates mode="režim"/> </xsl:template> <!-- Kopírování textových uzlů --> <xsl:template match="text()|@*"> <xsl:value-of select="."/> </xsl:template> <!-- Ignorování komentářů a instrukcí pro zpracování --> <xsl:template match="comment()|processing-instruction()"/>