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 14. XSLT 2.0

14.1. XPath 2.0
14.2. Seskupování uzlů
14.3. Výstup do více souborů
14.4. Uživatelsky definované funkce
14.5. Seřazení posloupnosti uzlů
14.6. Mapování znaků na výstupu transformace
14.7. Regulární výrazy
14.8. Další novinky

Již v době uvolnění XSLT 1.0 bylo jasné, že časem vznikne další specifikace, která možnosti jazyka dále rozšíří. V určitém okamžiku však bylo potřeba možnosti XSLT 1.0 zmrazit, aby vůbec vznikl stabilní standard, který budou jednotliví producenti XSLT procesorů implementovat.

XSLT 2.0 tak standardizuje v podstatě všechna rozšíření, o kterých jsme hovořili v předchozí kapitole. Největší změnou je však přechod od XPath 1.0 k XPath 2.0. Nová verze XPathu přitom podporuje datové typy definované XML schématu – pokud je pro dokument k dispozici. Všechny XPath výrazy navíc vracejí posloupnost – ty jako své položky mohou obsahovat jak uzly, tak skalární typy. Pro posloupnosti je definováno mnoho nových převážně množinových funkcí. Přímo v XPathu lze vyhodnocovat podmínky a jednoduché cykly.

Samotné XSLT se tak revolučních změn nedočkalo, protože mnohé chybějící funkce jsou součástí XPathu 2.0. Mezi největší změny můžeme počítat standardní instrukci pro výstup do více souborů, velmi mocnou instrukci pro seskupování uzlů, možnost definování uživatelských funkcí přímo ve stylu, výstupní metodu XHTML a regulární výrazy.

Nová verze jazyka XSLT má dvě úrovně – Basic a Schema-Aware. Pokročilejší úroveň Schema-Aware podporuje W3C XML Schema – datový model dokumentu obsahuje datové typy určené na základě schématu, generovaný výstup lze průběžně validovat, díky lepší typové kontrole se v kódu mohou snáze objevit chyby a informace o typech také dává lepší prostor pro optimalizace.

V následujícím textu si na několika příkladech ukážeme, jak XSLT 2.0 usnadňuje některé úlohy obtížněji řešitelné v XSLT 1.0. Podíváme se jen na funkčnost, která je v „Basic“ úrovni jazyka XSLT 2.0.

14.1 XPath 2.0

XPath 2.0 operuje nad novým datovým typem posloupnost. Posloupnosti lze přímo v XPathu zpracovávat množstvím množinových funkcí, ale můžeme přes ně provádět i iteraci, která konstruuje novou posloupnost. S výhodou to lze použít například pro sečtení naší objednávky.

Příklad 14.1. Součet objednávky pomocí XPath 2.0 – objednavka4.xsl

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                version="2.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">
            <!-- XPath 2.0 obsahuje i příkazy pro cykly -->
            <xsl:value-of select="sum(for $n in objednavka/polozka 
                                      return $n/cena * $n/pocet)"/>
          </th>
        </tr>
      </table>
    </html>
  </xsl:template>

</xsl:stylesheet>

Nová verze XPathu konečně přidává i podmíněný výraz, takže mnoho úkolů lze zapsat kompaktnějším způsobem.

Příklad 14.2. Podmíněný výraz v XPath 2.0 – katalog-radky.xsl

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                version="2.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">
  <!-- XPath 2.0 obsahuje podmíněný výraz -->
  <tr bgcolor="{if (position() mod 2 = 0) then '#FF8000' else '#FFC0C0'}">
    <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>

Gramatika XPathu se rovněž uvolnila, takže lze zapisovat výrazy jako /kniha/(kapitola|priloha)/nazev.

Funkce mohou být aplikovány i jako součást cesty. Například si můžeme nechat vrátit seznam názvů všech položek katalogu, kde jsou názvy převedeny na velká písmena:

/katalog/polozka/nazev/upper-case(.)

Pomocí zápisu *:lokální_jméno se nyní můžeme odvolávat na element v libovolném jmenném prostoru. To se hodí pro zpracování formátů, které pro různé verze používají odlišné jmenné prostory, ale význam elementů přitom zůstává stejný.

Příklad 14.3. Zpracování elementů bez ohledu na jejich jmenný prostor – gpx2html.xsl

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

  <!-- Univerzální transformace pro vykreslení GPX soubou na Google Maps pomocí JS API -->
  <!-- Dokumentace ke Google Maps API: http://code.google.com/apis/maps/ -->

  <xsl:output method="html" encoding="utf-8" indent="yes"/>

  <xsl:template match="*:gpx">
    <html>
      <head>
        <title>Ukázka vykreslení GPX trasy pomocí Google Maps</title>
        <script src="http://maps.google.com/maps?file=api&amp;v=2&amp;hl=cs&amp;key=ABQIAAAA4Wxrd1ZmQfRHvggZWM0QkxSVN_sXTad_Y81zCJbFzQPF08FeYBRZ9fK6emwt6oYGCxubaLiCphkWCg" type="text/javascript"/>
        <script type="text/javascript">
          function initMap()
          {
            if (GBrowserIsCompatible())
            {
              var map = new GMap2(document.getElementById("map"));
              map.setMapType(G_HYBRID_MAP);
              var points =[];
              <xsl:apply-templates select="*:wpt|*:trk/*:trkseg/*:trkpt|*:rte/*:rtept"/>
              map.addOverlay(new GPolyline(points));
            }
          }
        </script>
      </head>
      <body onload="initMap()">
        <div id="map" style="width: 800px; height: 600px; margin-left: auto; margin-right: auto"/>
      </body>
    </html>
  </xsl:template>

  <xsl:template match="*:trkpt|*:wpt|*:rtept">
    <xsl:if test="position() = 1">
      map.setCenter(new GLatLng(<xsl:value-of select="@lat"/>, <xsl:value-of select="@lon"/> ), 10);
      map.setUIToDefault();
    </xsl:if>
    <xsl:text/>points.push(new GLatLng(<xsl:value-of select="@lat"/>, <xsl:value-of select="@lon"/> ));
  </xsl:template>

</xsl:stylesheet>

Relační operátory jako <, >, =, … fungují tak, že pokud je alespoň na jedné straně porovnání posloupnost (seznam uzlů v XPathu 1.0) stačí, aby podmínka byla splněna pro jeden prvek posloupnosti. Porovnání se tak automaticky chová jakoby před ním byl uveden existenční kvantifikátor. V XPathu 2.0 můžeme toto chování ručně kontrolovat pomocí nových konstrukcí some a every. Například následující výraz vrátí prvočísla menší než 100.

for $i in (2 to 100) return
  if (every $j in (2 to $i - 1) satisfies $i mod $j ne 0)
    then $i
    else ()

Zároveň vidíme, že pro porovnávání nepoužíváme !=, ale ne (not equal). Operátory ne, eq, … porovnávají vždy dvě hodnoty, nikdy se neprovádí porovnávání s případnými několika položkami posloupnosti jako u operátorů !=, =, ….

Nový operátor is může být použit k ověření totožnosti dvou uzlů.

Operátory << a >> umožňují testovat, zda j nějaký uzel v dokumentu před (resp. za) nějaký jiným uzlem. Například pomocí podmínky //p[1] << //h1[1] snadno otestujeme, zda je v dokumentu před prvním nadpisem nějaký odstavec.

Nad posloupnostmi lze nyní provádět běžné množinové operace. Kromě sjednocení, které lze nyní kromě operátoru | zapsat i pomocí operátoru union, můžeme nově zjišťovat i rozdíl (except) a průnik (intersect) posloupností.

Všechny funkce a operátory dostupné v XPath 2.0 jsou popsané na adrese http://www.w3.org/TR/xquery-operators/.

© 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