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 13. EXSLT

13.1. Základní funkce
13.1.1. exsl:node-set
13.1.2. exsl:object-type
13.2. Množinové operace
13.2.1. set:difference
13.2.2. set:distinct
13.2.3. set:has-same-node
13.2.4. set:intersection
13.2.5. set:leading
13.2.6. set:trailing
13.3. Matematické funkce
13.3.1. math:min
13.3.2. math:max
13.3.3. math:highest
13.3.4. math:lowest
13.3.5. Výpočetní funkce
13.4. Funkce pro práci s datem a časem
13.4.1. date:date-time
13.4.2. date:date
13.4.3. date:time
13.4.4. date:year
13.4.5. date:leap-year
13.4.6. date:month-in-year
13.4.7. date:month-name
13.4.8. date:month-abbreviation
13.4.9. date:week-in-year
13.4.10. date:day-in-year
13.4.11. date:day-in-month
13.4.12. date:day-of-week-in-month
13.4.13. date:day-in-week
13.4.14. date:day-name
13.4.15. date:day-abbreviation
13.4.16. date:hour-in-day
13.4.17. date:minute-in-hour
13.4.18. date:second-in-minute
13.5. Elementy pro definování funkcí

Již při uvolnění finální specifikace XSLT 1.0 bylo jasné, že několik důležitých funkcí ve standardu chybí – např. výstup do více souborů, operace s množinami uzlů, převod fragmentu XML zpět na množinu uzlů apod. Jednotlivé procesory proto začaly nabízet vlastní implementace, které však nebyly kompatibilní, protože se jinak jmenovaly a občas se drobně lišily svým chováním. Vývojáři XSLT se proto dohodli a definovali sadu nejpoužívanějších rozšiřujících funkcí a instrukcí. Iniciativa je známá jako EXSLT. Mnoho z těchto funkcí bylo později standardizováno v XSLT 2.0 a XPath 2.0.

EXSLT definuje nové funkce a instrukce v několika skupinách. Některé XSLT procesory (zejména Saxon a xslproc) většinu nebo i všechny funkce a instrukce implementují přímo. V jiných je možné použít implementace vytvořené pomocí různých vnořených skriptů apod. Styly používající EXSLT samozřejmě nebudou pracovat ve všech XSLT procesorech, ale budou rozhodně přenositelnější, než kdybychom používali pouze rozšíření specifická pro určitý procesor.

V následujícím přehledu se podíváme na funkce a instrukce EXSLT a u těch nejdůležitějších si na příkladech ukážeme, k čemu je použít. Funkce jsou členěny do logických kategorií, každá kategorie má svůj jmenný prostor. Zařadil jsem pouze ty funkce, které jsou povinné u EXSLT implementací. EXSLT obsahuje ještě další experimentální funkce (např. pro práci s regulárními výrazy) – jejich popis naleznete na stránkách iniciativy.

13.1 Základní funkce

Jmenný prostor

http://exslt.org/common

Typický prefix

exsl

13.1.1 exsl:node-set

Převede fragment výstupního XML dokument zpět na seznam uzlů.

seznam uzlů exsl:node-set(objekt)

Jedná se o jedno z nejpoužívanějších rozšíření. Umožňuje například provádění víceprůchodových transformací během jednoho běhu procesoru apod. My si použití ukážeme na jednoduchém příkladu výpočtu celkové hodnoty objednávky.

Příklad 13.1. Dokument s objednávkou – objednavka.xml

<?xml version="1.0" encoding="utf-8"?>
<objednavka>
  <jmeno>Pepa</jmeno>
  <datum>dnes</datum>
  <polozka>
    <nazev>Rohlík</nazev>
    <pocet>10</pocet>
    <cena>2</cena>
  </polozka>
  <polozka>
    <nazev>Pivo</nazev>
    <pocet>6</pocet>
    <cena>7.5</cena>
  </polozka>
  <polozka>
    <nazev>Týdeník Respekt</nazev>
    <pocet>1</pocet>
    <cena>20</cena>
  </polozka>
</objednavka>

Předpokládejme, že chceme zjistit celkovou cenu objednávky. Funkce sum() nám v tomto případě neposlouží, protože umí sčítat jen seznam uzlů. My však potřebujeme sečíst součiny ceny a počtu kusů. V čistém XSLT 1.0 si můžeme pomoci rekurzivní funkcí.

Příklad 13.2. Součet součinů řešený pomocí rekurze – objednavka.xsl

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                version="1.0">

  <!-- Sečtení objednávky -->
  <xsl:template match="/">
    <xsl:variable name="nadpis">
      Objednávka pro <xsl:value-of select="objednavka/jmeno"/> 
      ze dne <xsl:value-of select="objednavka/datum"/>
    </xsl:variable>
    <html>
      <head>
        <title><xsl:value-of select="$nadpis"/></title>
      </head>
      <h1><xsl:value-of select="$nadpis"/></h1>
      <table border="1">
        <tr>
          <th>Název</th>
          <th>Ks</th>
          <th>Cena</th>
          <th>Celkem</th>
        </tr>
        <xsl:for-each select="objednavka/polozka">
          <tr>
            <td><xsl:value-of select="nazev"/></td>
            <td><xsl:value-of select="pocet"/></td>
            <td><xsl:value-of select="cena"/></td>
            <td><xsl:value-of select="pocet * cena"/></td>
          </tr>
        </xsl:for-each>
        <tr>
          <th>Celkem</th>
          <th colspan="3">
            <xsl:call-template name="secti">
              <xsl:with-param name="node" select="objednavka/polozka[1]"/>
            </xsl:call-template>
          </th>
        </tr>
      </table>
    </html>
  </xsl:template>

  <!-- Rekurzivní výpočet celkového součtu -->
  <xsl:template name="secti">
    <xsl:param name="node" select="."/>
    <xsl:variable name="sumazbytku">
      <xsl:choose>
        <xsl:when test="$node/following-sibling::polozka">
          <xsl:call-template name="secti">
            <xsl:with-param name="node"
              select="$node/following-sibling::polozka[1]"/>
          </xsl:call-template>
        </xsl:when>
        <xsl:otherwise>
          0
        </xsl:otherwise>
      </xsl:choose>
    </xsl:variable>
    <xsl:value-of select="($node/pocet)*($node/cena) + $sumazbytku"/>  
  </xsl:template>

</xsl:stylesheet>

Mnohem jednodušší a průhlednější řešení však používá funkci exsl:node-set(). Nejprve si dílčí součiny uložíme do proměnné jako fragment XML, pak je funkcí převedeme zpět na seznam uzlů a ten již můžeme zcela běžnými funkcemi sečíst.

Příklad 13.3. Součet součinů pomocí funkce node-set – objednavka2.xsl

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:exsl="http://exslt.org/common"
                extension-element-prefixes="exsl"
                exclude-result-prefixes="exsl"
                version="1.0">

  <!-- Sečtení objednávky -->
  <xsl:template match="/">
    <xsl:variable name="nadpis">
      Objednávka pro <xsl:value-of select="objednavka/jmeno"/> 
      ze dne <xsl:value-of select="objednavka/datum"/>
    </xsl:variable>
    <html>
      <head>
        <title><xsl:value-of select="$nadpis"/></title>
      </head>
      <h1><xsl:value-of select="$nadpis"/></h1>
      <table border="1">
        <tr>
          <th>Název</th>
          <th>Ks</th>
          <th>Cena</th>
          <th>Celkem</th>
        </tr>
        <xsl:for-each select="objednavka/polozka">
          <tr>
            <td><xsl:value-of select="nazev"/></td>
            <td><xsl:value-of select="pocet"/></td>
            <td><xsl:value-of select="cena"/></td>
            <td><xsl:value-of select="pocet * cena"/></td>
          </tr>
        </xsl:for-each>
        <tr>
          <th>Celkem</th>
          <th colspan="3">

            <!-- Uložení dílčích součtů jako seznamu čísel v XML -->
            <xsl:variable name="mezisoucty">
              <xsl:for-each select="objednavka/polozka">
                <cislo><xsl:value-of select="cena * pocet"/></cislo>
              </xsl:for-each>
            </xsl:variable>
            
            <!-- Převedení XML seznamu na seznam uzlů a jeho sečtení -->
            <xsl:value-of select="sum(exsl:node-set($mezisoucty)/cislo)"/>

          </th>
        </tr>
      </table>
    </html>
  </xsl:template>

</xsl:stylesheet>

Při použití rozšiřujících funkcí můžeme styly psát tak, že budou funkční ve všech procesorech. Před použitím rozšiřujících funkcí stačí otestovat, zda je máme k dispozici.

Příklad 13.4. Univerzální součet součinů – objednavka3.xsl

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:exsl="http://exslt.org/common"
                extension-element-prefixes="exsl"
                exclude-result-prefixes="exsl"
                version="1.0">

<!-- Sečtení objednávky -->
<xsl:template match="/">
  <xsl:variable name="nadpis">
    Objednávka pro <xsl:value-of select="objednavka/jmeno"/> 
    ze dne <xsl:value-of select="objednavka/datum"/>
  </xsl:variable>
  <html>
    <head>
      <title><xsl:value-of select="$nadpis"/></title>
    </head>
    <h1><xsl:value-of select="$nadpis"/></h1>
    <table border="1">
      <tr>
        <th>Název</th>
        <th>Ks</th>
        <th>Cena</th>
        <th>Celkem</th>
      </tr>
      <xsl:for-each select="objednavka/polozka">
        <tr>
          <td><xsl:value-of select="nazev"/></td>
          <td><xsl:value-of select="pocet"/></td>
          <td><xsl:value-of select="cena"/></td>
          <td><xsl:value-of select="pocet * cena"/></td>
        </tr>
      </xsl:for-each>
      <tr>
        <th>Celkem</th>
        <th colspan="3">

          <!-- Výběr způsobu výpočtu na základě schopností XSLT procesoru -->
          <xsl:choose>
            <xsl:when test="function-available('exsl:node-set')">
              <!-- Výpočet s využitím rozšiřující funkce -->
              <xsl:variable name="mezisoucty">
                <xsl:for-each select="objednavka/polozka">
                  <cislo><xsl:value-of select="cena * pocet"/></cislo>
                </xsl:for-each>
              </xsl:variable>
              <xsl:value-of select="sum(exsl:node-set($mezisoucty)/cislo)"/>
            </xsl:when>
            <xsl:otherwise>
              <!-- Klasická XSLT 1.0 cesta -->
              <xsl:call-template name="secti">
                <xsl:with-param name="node" select="objednavka/polozka[1]"/>
              </xsl:call-template>
            </xsl:otherwise>
          </xsl:choose>

        </th>
      </tr>
    </table>
  </html>
</xsl:template>

<!-- Rekurzivní výpočet celkového součtu -->
<xsl:template name="secti">
  <xsl:param name="node" select="."/>
  <xsl:variable name="sumazbytku">
    <xsl:choose>
      <xsl:when test="$node/following-sibling::polozka">
        <xsl:call-template name="secti">
          <xsl:with-param name="node"
            select="$node/following-sibling::polozka[1]"/>
        </xsl:call-template>
      </xsl:when>
      <xsl:otherwise>
        0
      </xsl:otherwise>
    </xsl:choose>
  </xsl:variable>
  <xsl:value-of select="($node/pocet)*($node/cena) + $sumazbytku"/>  
</xsl:template>

</xsl:stylesheet>

13.1.2 exsl:object-type

Funkce zjistí typ objektu.

řetězec exsl:object-type(objekt)

Typy objektu mohou být následující: string, number, boolean, node-set, RTF (fragment výstupního dokumentu) a external.

© 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