Potřebujete pomoci s XSLT?
Nabízím školení, konzultace, vývoj XSLT kódu na zakázku. Nevájte a kontaktujte mne.

Podpořte provoz stránek
Platba probíhá pomocí služby PayPal a je možné platit kartou nebo převodem z vašeho PayPal účtu.

Kapitola 3. Způsob zpracování stylu

3.1. Šablony
3.1.1. Výběr uzlů k dalšímu zpracování pomocí šablon – <xsl:apply-templates>
3.1.2. Režimy zpracování šablon
3.1.3. Řešení konfliktů mezi šablonami
3.1.4. Zabudované šablony
3.2. Vytváření výstupního dokumentu
3.2.1. Generování elementů a textového výstupu
3.2.2. Generování elementů a atributů s předem neznámým názvem
3.2.3. Opakované vkládání skupiny atributů
3.2.4. Generování komentářů – <xsl:comment>
3.2.5. Generování instrukcí pro zpracování – <xsl:processing-instruction>
3.3. Iterativní zpracování
3.4. Podmíněné zpracování
3.4.1. Podmíněný příkaz – <xsl:if>
3.4.2. Podmíněné větvení – <xsl:choose>

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.

3.1 Šablony

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.

Poznámka

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 //výraz obsahuje uzel 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="výraz">. Ta vybere pouze obsah textových uzlů, které jsou potomky elementu určeného pomocí 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ží.

3.1.1 Výběr uzlů k dalšímu zpracování pomocí šablon – <xsl:apply-templates>

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/></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/></td>
</xsl:template>

</xsl:stylesheet>

3.1.2 Režimy zpracování šablon

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/></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"/></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>

3.1.3 Řešení konfliktů mezi šablonami

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"/>

3.1.4 Zabudované šablony

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()"/>
© Jiří Kosek 2014

Tento dokument je určen výhradně pro osobní potřebu seznámení s jazykem XSLT. Jakékoliv jiné použití, včetně dalšího šíření, pořizování kopií, použití při školeních a výuce apod. je výslovně zakázáno a bude považováno za porušení autorských práv.


Copyright © 2000-2014 Jiří Kosek