Kompletní průvodce XSLT – řízení toku transformace

4. června 2004

Znalosti z předchozích článků nám stačí k vytváření poměrně mocných transformací, občas se však hodí mít k dispozici některé konstrukce známé z běžných programovacích jazyků, jako je podmíněné provádění a iterace. A právě s nimi se seznámíme v tomto článku.

Podmíněné provádění

Podmínky jsme částečně schopni nasimulovat již teď, například pomocí <xsl:apply-templates /> s parametrem select. Pokud je výsledkem vyhodnocení tohoto parametru nějaký uzel, aplikují se na něj další šablony, v opačném případě průběh transformace pokračuje normálně dále. Pokud je však výsledkem více uzlů, jsou zpracovány všechny, což ale někdy není vhodné. Lze to sice ošetřit XPath predikátem (select="...[1]" – vrací pouze první uzel v pořadí), jistě však souhlasíte, že to není zrovna to pravé ořechové. A proto nastupují další syntaktické prvky jazyka XSLT.

<xsl:if test=“…“>

Tato XSLT instrukce je synonymem pro příkaz if, známý z běžných programovacích jazyků. Syntaxe a použití jsou určitě zřejmé již z nadpisu. Parametr test obsahuje výraz podmínky, který se vyhodnotí a, je-li třeba, je převeden na logickou hodnotu pomocí XPath funkce boolean(). Tato funkce pracuje s různými datovými typy dle následující tabulky:

Datový typ Výsledek je true pokud…
number hodnota není nulová nebo NaN
node-set (seznam uzlů) seznam obsahuje alespoň jeden uzel
string (řetězec) řetězec má nenulovou délku
jiný typ způsob závisí na konkrétním datovém typu

Takto je podmínka vyhodnocena a pokud je její výsledek logická pravda (true), šablona uvnitř značek <xsl:if> a </xsl:if> se provede, jinak je ignorována. Malý příklad:

<?xml version=’1.0′?>
<xsl:stylesheet
  xmlns:xsl=’http://www.w3.org/1999/XSL/Transform‘
  version=’1.0′>
  <xsl:template match=’/‘>
    …
    <xsl:if test=“price“>
      cena: <xsl:value-of select=“price“ />,- Kč
    </xsl:if>
    …
  </xsl:template>
</xsl:stylesheet>

Pokud vstupní dokument obsahuje element price, například <price>660</price>, je vygenerován jeho obsah v tomto formátu: cena: 660,- Kč. V opačném případě nebude na výstupu o ceně ani zmínka.

<xsl:choose>, <xsl:when> a <xsl:otherwise>

Možná jste si všimli, že v popisu předchozí instrukce xsl:if schází popis použití sekce else, která je jinak poměrně obvyklá. Tato možnost v XSLT vůbec neexistuje – pokud chcete zpracovat i stav nesplnění podmínky, musíte použít ještě jednou instrukci xsl:if s opačnou podmínkou nebo raději použít vícenásobné větvení.

Tyto instrukce jsou obdobou příkazu switch, známého z mnoha programovacích jazyků vycházejících z C, respektive select, který možná znáte z Visual Basicu a podobných. Je zde však podstatný rozdíl – zatímco jinde je nejdříve vyhodnocen výraz a jeho hodnota je pak srovnávána s hodnotami v jednotlivých větvích, v XSLT má každá větev svou podmínku (kromě výchozí větve). Všechny větve se procházejí v tom pořadí, v jakém jsou definovány, a obsah první, jejíž podmínka je vyhodnocena jako pravdivá, je zpracován, jinak je zpracována výchozí větev (xsl:otherwise), pokud je definována. Následuje opět jednoduchý příklad:


<xsl:choose>
  <xsl:when test=“number(price) &gt; 600″>
    velmi vysoká cena
  </xsl:when>
  <xsl:when test=“number(price) &gt; 400″>
    normální cena
  </xsl:when>
  <xsl:when test=“price“>
    pozor – akční cena!!!
  </xsl:when>
  <xsl:otherwise>
    cena neurčena
  </xsl:otherwise>
</xsl:choose>

Pokud vás zarazila entita &gt; v XPath výrazu, uvědomte si, že do XML atributu nemůžeme přímo zapsat znak >. Výraz je procesorem nejdříve dekódován a teprve pak zpracován. Předposlední větev se zpracuje, pokud element price alespoň existuje, ať už je jeho hodnota jakákoli, a pokud element vůbec není přítomen, zpracuje se větev poslední. Myslím, že k příkladu už není co dodat.

Iterace

Iterace, smyčky, prostě opakované zpracování dat stejným způsobem. Ačkoli v XSLT díky šablonám je tento úkol řešitelný mnoha způsoby, které jsou schopny splnit nám téměř všechna přání, přesto zde existuje také alternativa známého příkazu for v trochu upravené podobě:

<xsl:for-each>

Zjednodušeně řečeno, šablona uvnitř této instrukce je zpracována pro každý uzel vrácený z parametru select této instrukce. Každý takový uzel se pro tuto šablonu zároveň stane aktuálním (kontextovým) uzlem. Mějme tedy například následující fragment vstupního XML dokumentu:

<price-list>
  <variant>
    <code>UF-1</code>
    <price>399</price>
  </variant>
  <variant>
    <code>UF-1a</code>
    <price>499</price>
  </variant>
</price-list>

Je to v podstatě jednoduchý ceník se dvěma položkami, který budeme chtít zpracovat do HTML tabulky. Můžeme k tomu použít tuto transformaci:

<table>
  <tr>
    <th>Varianta</th>
    <th>Cena</th>
  </tr>
  <xsl:for-each select=“price-list/variant“>
    <tr>
      <td><xsl:value-of select=“code“/></td>
      <td><xsl:value-of select=“price“/> Kč</td>
    </tr>
  </xsl:for-each>
</table>

Myslím, že je zřejmé, jak tento příklad funguje. Hodnoty code a price jsou vyhodnoceny vždy relativně vzhledem k aktuálnímu uzlu, kterým je právě zpracovávaná varianta.

Řazení uzlů

Instrukce xsl:apply-templates a xsl:for-each podporují seřazení zpracovávaných uzlů předtím, než jsou zpracovány. K tomu slouží instrukce xsl:sort, vložená jako první do jejich těla. Tato instrukce umožňuje řazení podle určitého klíče, pokud chcete řadit podle více klíčů, není nic jednoduššího, než přidat řadících instrukcí více. Přednost má ta, která je uvedena dříve.

<xsl:sort>

Instrukce má několik parametrů, kterými můžeme způsob řazení specifikovat podrobněji.

select
Klíč pro řazení. Je to XPath výraz, který je počítán relativně vzhledem k momentálně vyhodnocovanému uzlu, a podle výsledků tohoto výrazu jsou pak uzly seřazeny pro další zpracování. Výchozí hodnotou je ., tedy celý textový obsah aktuálního uzlu.
data-type
Udává, jak se má klíč vyhodnotit. Možnými hodnotami jsou text, number a nebo plně kvalifikovaný název jiného typu, který není v XSLT definován. Pro text je klíč vyhodnocen XPath funkcí string() a pro number překvapivě funkcí number().
lang
Pokud se klíč vyhodnocuje jako text, tímto parametrem lze specifikovat jazyk, dle kterého budou řetězce porovnány. Možné hodnoty jsou stejné jako pro xml:lang. Výchozí hodnotou by mělo být aktuální jazykové prostředí počítače.
case-order
Může být buď upper-first nebo lower-first. Udává, zda mají přednost nejdříve velká písmena (první případ) a nebo malá. Pokud parametr není uveden, způsob řazení závisí na nastaveném jazyce.
order
Pokud je ascending (výchozí hodnota), řazení je vzestupné, jinak descending znamená sestupné řazení.

Ukázkový vstupní dokument:

<contacts>
  <person>
    <given>Petr</given>
    <family>Bříza</family>
    <email>petr.briza@spol.cz</email>
  </person>
  <person>
    <given>Vilém</given>
    <family>Málek</family>
    <email>vilem.malek@interval.cz</email>
  </person>
</contacts>

Tato data seřadíme vzestupně podle příjmení a jména do HTML seznamu:

<ul>
  <xsl:for-each select=“contacts/person“>
    <xsl:sort select=“family“>
    <xsl:sort select=“given“>
    <li>
      <a href=“mailto:{email}“>
        <xsl:value-of select=“concat(given, ‚ ‚, family)“/>
      </a>
    </li>
  </xsl:for-each>
</ul>

Příklad opět sdružuje ukázky hned několika syntaktických prvků XSLT: iterace, řazení, generování fragmentů atributů, vkládání hodnoty a praktického využití XPath funkce concat. Výsledkem je seřazený seznam všech kontaktních osob, zahrnující interakci s aktuálním emailovým klientem uživatele.

Číslování

K číslování slouží velice mocná instrukce xsl:number, umožňující číslování například nadpisů a dalších částí výsledku podle mnoha různých formátů číselných a jiných řad. Jednoduché použití pro vstupní dokument z předchozího příkladu:

<xsl:for-each select=“contacts/person“>
  <p>
    <xsl:number value=“position()“ format=“1. „/>
    <a href=“mailto:{email}“>
      <xsl:value-of select=“concat(given, ‚ ‚, family)“/>
    </a>
  </p>
</xsl:for-each>

Parametr format může obsahovat definice známé z parametru type elementu OL v HTML 4.0, tedy například a a A znamenají řadu malých či velkých písmen, a i a I je řada římských číslic. Tato instrukce toho umí podstatně více a já ji v některém z dalších článků rozeberu podrobněji. Zájemce o toto téma prozatím odkazuji na specifikaci, nebo příručku Jiřího Koska.

Odkazy, zdroje

Starší komentáře ke článku

Pokud máte zájem o starší komentáře k tomuto článku, naleznete je zde.

Další článek zoe
Štítky: Články

Mohlo by vás také zajímat

Nejnovější

Napsat komentář

Vaše e-mailová adresa nebude zveřejněna. Vyžadované informace jsou označeny *