Hlavní navigace

Novinky v XSLT 2.0

19. 3. 2007
Doba čtení: 11 minut

Sdílet

Vývoj standardů XSLT 2.0 a XPath 2.0 trval několik let. Počátkem letošního roku byly konečně uznány konsorciem W3C a staly se oficiálně doporučovanými. Změn je skutečně hodně, a proto vám přinášíme přehled těch nejdůležitějších a nejzásadnějších novinek včetně praktických ukázek jejich použití.

V úterý 23. ledna 2007 se XSLT 2.0 a XPath 2.0 staly po několikaletém vývoji oficiálními doporučeními W3C konsorcia. Protože s jazykem XSLT 2.0 pracujeme již od vydání jeho prvních implementací v programu Saxon, rozhodli jsme se sepsat stručný přehled novinek, které tato verze přináší.

Cílem článku není kompletní přehled změn, ale spíš upozornění na funkce, které považujeme za nejdůležitější. Vzhledem k rozsahu článku nejsou u každé novinky uvedeny příklady použití, ale každá popsaná funkce obsahuje odkaz na detailní tutoriál, který najdete na zvon.org. V článku jsme se záměrně vyhnuli změnám týkajícím se zavedení typů do XSLT 2.0, protože tato funkcionalita není ve volně dostupné verzi Saxonu zahrnuta a pro naše potřeby nepřináší nic užitečného.

Bez dlouhého úvodu se tedy vrhněme rovnou na jednotlivé novinky. Seřadili jsme je ve fuzzy pořadí podle důležitosti či zajímavosti.

Novinky

Seskupování elementů

Královnou nových funkcí v XSLT 2.0 je pro nás rozhodně for-each-group. Určitě se bude líbit každému, kdo potřeboval pomocí XSLT vytvořit jakýkoli index, nebo jenom vybrat unikátní hodnoty ze seznamu.

For-each-group umožnuje seskupovat elementy a takto získané skupiny poté společně zpracovávat. Nejčastěji se seskupování provádí podle nějakého společného prvku specifikovaného pomocí atributu group-by. Tím může být nejen obsah elementu nebo atributu, ale také vypočtená hodnota (např. první písmeno, délka řetězce apod.). Seskupovat lze také např. sousedící elementy splňující nejaké pravidlo (stejný název, obsah, hodnotu atributu) pomocí atributu group-adjacent.

Následující ukázka demonstruje, jak for-each-group funguje a k čemu se hodí, na příkladu seznamu zaměstnanců. První for-each-group generuje seznam místností a pro každou z nich její osazenstvo, druhý pak seznam zaměstnanců podle prvního písmene jejich příjmení. Všimněte si použití sort pro seřazení počátečních písmen v druhém indexu. Upozornění: Z důvodu přehlednosti není vytvořený soubor platným HTML, jde pouze o ukázku použití.

XML

<seznam>

  <pracovnik>
    <mistnost>42</mistnost>
    <jmeno>Douglas</jmeno>
    <prijmeni>Adams</prijmeni>

  </pracovnik>
  <pracovnik>
    <mistnost>8</mistnost>
    <jmeno>Samuel</jmeno>
    <prijmeni>Vimes</prijmeni>

  </pracovnik>
  <pracovnik>
    <mistnost>42</mistnost>
    <jmeno>Ford</jmeno>
    <prijmeni>Prefect</prijmeni>

  </pracovnik>
  <pracovnik>
    <mistnost>42</mistnost>
    <mistnost>43</mistnost>
    <jmeno>Tricia</jmeno>

    <prijmeni>McMillan</prijmeni>
  </pracovnik>
  <pracovnik>
    <mistnost>10</mistnost>
    <jmeno>Havelock</jmeno>

    <prijmeni>Vetinari</prijmeni>
  </pracovnik>
</seznam>

XSLT

<?xml version="1.0" ?>
<xsl:stylesheet
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  version="2.0">
  <xsl:output indent="yes" method="html"/>

  <xsl:template match="/">
    <html>
    <xsl:for-each-group select="seznam/pracovnik" group-by="mistnost">
      <p>Místnost <xsl:value-of select="current-grouping-key()"/></p>
      <ul>

        <xsl:for-each select="current-group()">
          <li><xsl:value-of select="jmeno, prijmeni"/></li>
        </xsl:for-each>
      </ul>
    </xsl:for-each-group>

    <xsl:for-each-group select="seznam/pracovnik" group-by="substring(prijmeni,1,1)">
      <xsl:sort select="current-grouping-key()"/>
      <p><xsl:value-of select="current-grouping-key()"/></p>
      <ul>
        <xsl:for-each select="current-group()">

          <li><xsl:value-of select="jmeno, prijmeni"/></li>
        </xsl:for-each>
      </ul>
    </xsl:for-each-group>
  </html>

  </xsl:template>

</xsl:stylesheet>

VÝSTUP

<html>
   <p>Místnost 42</p>
   <ul>

      <li>Douglas Adams</li>
      <li>Ford Prefect</li>
      <li>Tricia McMillan</li>
   </ul>

   <p>Místnost 8</p>
   <ul>
      <li>Samuel Vimes</li>
   </ul>
   <p>Místnost 43</p>

   <ul>
      <li>Tricia McMillan</li>
   </ul>
   <p>Místnost 10</p>
   <ul>

      <li>Havelock Vetinari</li>
   </ul>
   <p>A</p>
   <ul>
      <li>Douglas Adams</li>

   </ul>
   <p>M</p>
   <ul>
      <li>Tricia McMillan</li>
   </ul>

   <p>P</p>
   <ul>
      <li>Ford Prefect</li>
   </ul>
   <p>V</p>

   <ul>
      <li>Samuel Vimes</li>
      <li>Havelock Vetinari</li>
   </ul>
</html>

V těle for-each-group jsou k dispozici funkce current-grouping-key(), která obsahuje aktuálně zpracovávaný klíč, a current-group(), která obsahuje zpracovávanou skupinu. Pokud element splňuje více podmínek, vyskytne se ve více skupinách.

Další čtení a příklady najdete na zvon.org.

Výstup do více dokumentů

Zatímco již XSLT 1.0 umělo načítat externí soubory, neobsahovalo podporu pro výstup do více souborů. Tento zřejmý nedostatek byl ve 2.0 odstraněn zavedením funkce result-document.

Další čtení a příklady opět najdete na zvon.org.

Načítání neparsovaných externích souborů

Čtení externích XML dokumentů pomocí funkce document() je pro každého kdo pracoval s XSLT stará vesta. XSLT 2.0 přidává podporu pro načítání neparsovaných externích souborů funkcí unparsed-text(). To umožňuje např. zpracovávat textové dokumenty pomocí regulárních výrazů a výsledek pak zařadit do výstupního XML. Všechny ukázky kódu v tomto článku do něj byly vloženy s pomocí této funkce :).

Další čtení a příklady najdete na zvon.org.

Všechno je seznam

V XSLT 2.0 je výsledkem všech XPath výrazů sekvence (list, seznam) výsledků (např. elementů či hodnot). Tím se mění chování některých základních funkcí v případě, že XPath vrátí více než jednu položku. Typickým příkladem je funkce value-of.

Funkce value-of v XSLT 1.0 vracela vždy pouze první nalezenou hodnotu odpovídající XPath výrazu zadaném pomocí atributu select. V XSLT 2.0 se její chování změnilo a vrací hodnotu všech odpovídajících hodnot.

Tato změna v chování value-of si vyžádala přidání atributu separator, který umožnuje nastavit oddělovač jednotlivých hodnot ve výstupu. Defaultní hodnota separatoru je " " (mezera).

XML

<seznam>
  <pracovnik>
    <jmeno>Douglas</jmeno>
    <prijmeni>Adams</prijmeni>

  </pracovnik>
  <pracovnik>
    <jmeno>Samuel</jmeno>
    <prijmeni>Vimes</prijmeni>
  </pracovnik>

  <pracovnik>
    <jmeno>Ford</jmeno>
    <prijmeni>Prefect</prijmeni>
  </pracovnik>
  <pracovnik>

    <jmeno>Tricia</jmeno>
    <prijmeni>McMillan</prijmeni>
  </pracovnik>
  <pracovnik>
    <jmeno>Havelock</jmeno>

    <prijmeni>Vetinari</prijmeni>
  </pracovnik>
</seznam>

XSLT

<?xml version="1.0" ?>
<xsl:stylesheet
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  version="2.0">
  <xsl:output method="text"/>

  <xsl:template match="/">
    <xsl:value-of select="seznam/pracovnik/prijmeni"/>
    <xsl:text>
</xsl:text>  <!-- tohle jen zprehlednuje vystup -->
    <xsl:value-of select="seznam/pracovnik/prijmeni" separator=", "/>

  </xsl:template>

</xsl:stylesheet>

VÝSTUP

Adams Vimes Prefect McMillan Vetinari
Adams, Vimes, Prefect, McMillan, Vetinari

Pro jednoduché případy usnadňuje toto pojetí value-of spoustu práce s výstupem více hodnot.

Další čtení a příklady najdete na zvon.org.

Uživatelem definované funkce

XSLT 2.0 umožňuje vytváření uživatelských funkcí. I když se podobná funkcionalita dá implementovat pomocí pojmenovaných šablon v kombinaci s parametry, volání funkcí je přece jen pohodlnější.

Funkce je nutno zařadit do vlastního jmenného prostoru (namespace) a jejich tělo vypadá podobně jako u šablony, která používá parametry.

Následující kód demonstruje vytvoření funkce, která z elementu ‚pracovnik‘ vytvoří zformátované jméno.

XML

<seznam>
  <pracovnik>
    <jmeno>Douglas</jmeno>

    <prijmeni>Adams</prijmeni>
  </pracovnik>
  <pracovnik>
    <jmeno>Samuel</jmeno>
    <prijmeni>Vimes</prijmeni>

  </pracovnik>
  <pracovnik>
    <jmeno>Ford</jmeno>
    <prijmeni>Prefect</prijmeni>
  </pracovnik>

  <pracovnik>
    <jmeno>Tricia</jmeno>
    <prijmeni>McMillan</prijmeni>
  </pracovnik>
  <pracovnik>

    <jmeno>Havelock</jmeno>
    <prijmeni>Vetinari</prijmeni>
  </pracovnik>
</seznam>

XSLT

<?xml version="1.0" ?>

<xsl:stylesheet
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:bk="namespace nemusi byt URI!"
  version="2.0"
  exclude-result-prefixes="bk">
  <xsl:output method="xml" indent="yes"/>

  <xsl:template match="/">
    <vystup>
      <xsl:for-each select="seznam/pracovnik">
        <jmeno><xsl:value-of select="bk:format-name(.)"/></jmeno>

      </xsl:for-each>
    </vystup>
  </xsl:template>

  <xsl:function name="bk:format-name">
    <xsl:param name="pracovnik"/>
    <xsl:value-of select="concat( $pracovnik/prijmeni, ', ', substring( $pracovnik/jmeno, 1, 1), '.')"/>

  </xsl:function>

</xsl:stylesheet>

VÝSTUP

<?xml version="1.0" encoding="UTF-8"?>
<vystup>
   <jmeno>Adams, D.</jmeno>

   <jmeno>Vimes, S.</jmeno>
   <jmeno>Prefect, F.</jmeno>
   <jmeno>McMillan, T.</jmeno>
   <jmeno>Vetinari, H.</jmeno>

</vystup>

Další čtení a příklady najdete na zvon.org.

Regulární výrazy

XSLT 2.0 obsahuje všechny obvyklé funkce pro práci s regulárními výrazy. Funkce matches testuje zda zadaný text odpovídá regulárnímu výrazu, funkce replace se stará o nahrazování a funkce tokenize provádí rozdělení řetězce v místech odpovídajících zadanému výrazu.

Další čtení a příklady najdete na zvon.org.

Proměnné

Na rozdíl od verze 1.0 je možné s proměnnou pracovat jako s externím dokumentem. To znamená, že je možné používat XPath výrazy pro zpracování částí proměnné a dokonce je možné i uvnitř proměnné vyhledávat s pomocí klíčů.

Další čtení a příklady najdete na zvon.org.

Tunelování parametrů

Parametry jsou výborným nástrojem jak mezi šablonami předávat informace. Bohužel se často stane, že mezi dvěma šablonami, které by si potřebovaly předat nějakou hodnotu pomocí parametru, se nachází ještě jedna šablona, kterou tento parametr vůbec nezajímá. V takovém případě skončíte u toho, že celý problém buď obejdete, a nebo pro každou šablonu, která vám stojí v cestě, zavedete parametr, který tato šablona nijak nezpracovává, jen ho pošle dál. To v kombinaci s relativně upovídanou syntaxí pro předávání parametrů vede k nepřehlednému a zbytečně nabubřelému kódu.

XSLT 2.0 řeší tento problém pomocí tunelovaných prametrů – pokud má parametr atribut tunnel nastaven na yes, není třeba ho v každé šabloně posílat dál, ale automaticky je k dispozici všem šablonám, které jsou zavolány „uvnitř“ volání spuštěném s tímto parametrem.

Další čtení a příklady najdete na zvon.org.

XPath 2.0

Novinky v XPath 2.0 by samy o sobě vydaly minimálně na jeden tučný článek. Abychom vám však dali alespoň ochutnat, co nového obsahuje, uvádíme několik příkladů.

Jednoduché podmínky v rámci XPath – pokud element obsahuje atribut lang vrať jeho hodnotu, jinak vrať ‚en‘:

<xsl:value-of select="if (not(@lang)) then 'en' else @lang"/>

Předchozí kód není problém přepsat pomocí XSLT a choose, ale pokud je to něco jednoduchého, bude vám těch několik řádek navíc zbytečně znepřehledňovat kód.

Jednoduchý for cyklus také ušetří spoustu psaní.

XML

<seznam>
  <pracovnik>
    <jmeno>Douglas</jmeno>
    <prijmeni>Adams</prijmeni>

  </pracovnik>
  <pracovnik>
    <jmeno>Samuel</jmeno>
    <prijmeni>Vimes</prijmeni>
  </pracovnik>

  <pracovnik>
    <jmeno>Ford</jmeno>
    <prijmeni>Prefect</prijmeni>
  </pracovnik>
  <pracovnik>

    <jmeno>Tricia</jmeno>
    <prijmeni>McMillan</prijmeni>
  </pracovnik>
  <pracovnik>
    <jmeno>Havelock</jmeno>

    <prijmeni>Vetinari</prijmeni>
  </pracovnik>
</seznam>

XSLT

<?xml version="1.0" ?>
<xsl:stylesheet
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  version="2.0">
  <xsl:output method="text"/>

  <xsl:template match="/">
    <xsl:value-of select="for $e in seznam/pracovnik/prijmeni return substring($e,1,2)"/>
    <xsl:text>
</xsl:text>  <!-- tohle jen zprehlednuje vystup -->
    <xsl:value-of select="for $e in 1 to 10 return $e*$e"/>

  </xsl:template>

</xsl:stylesheet>

VÝSTUP

root_podpora

Ad Vi Pr Mc Ve
1 4 9 16 25 36 49 64 81 100

Implementace

Finální verze XSLT 2.0 je zatím zcela implementována pouze v Saxonu 8, který píše Michael Kay, editor XSLT specifikace. Tento procesor souběžně vychází ve dvou verzích – Saxon-B, publikovaný pod otevřenou licencí, a komerční Saxon-A, který je schema-aware. Volně dostupnou verzi tohoto programu používáme již přes dva roky a je velmi stabilní a rychlá.


Oba autoři vyučují programování na VŠCHT Praha v rámci oboru Informatika a chemie. XSLT 2.0 patří spolu s Pythonem mezi základní předměty tohoto oboru. Pokud byste chtěli na této škole studovat, uzávěrka přihlášek na VŠCHT Praha je 31. března.

Byl pro vás článek přínosný?

Autor článku

Bedřich Košata je vedoucím Laboratoří CZ.NIC, výzkumného a vývojového centra sdružení CZ.NIC, správce české národní domény.