Article Index

Extensible Markup Language - XSL

Je stylovací a transformační prostředek pro značkovací jazyky, primárně pro XML. Rozděluje se na dva hlavní jazyky:

  • XSLT - transformace
  • XSL:FO - formátovací objekty

Začněme s XLST. Hlavní funkcí je transformace jednoho datového souboru na druhý. Příkladem je převod XML souboru na HTML výstup. XSL umožňuje nejenom převádět, ale také vybírat to, co chceme zobrazit.

XSL využívá XPath adresování částí XML dokumentu. Pomocí XPath lze vybírat jednotlivé elementy nebo atributy a určovat, na kterou značku či atribut budou transformovány. Pomocí XSL můžeme snadno prezentovat data uložená v XML na webu nebo je převádět do úspornějších formátů pro přenos (JSON, csv, ...).

Ukázkové XML:

<zaznamy>
  <mereni id="001">
    <datum>2017-02-01</datum>
 
   <teplota>-3.6</teplota>
  </mereni>
</zaznamy>

Prostřednictvím XSL můžeme z tohoto datového souboru udělat přehledný výstup do HTML tabulky:

ID Datum Teplota
001 2017-02-01 -3.6

 


Šablony

Základem XSLT jsou šablony. Šablona je aktivována výskytem vybraného uzlu v XML (element, atribut, dokument, ...) a obsahuje reakci na výskyt tohoto uzlu. Šablona za určitých podmínek reaguje na každý výskyt dané značky.

Šablona může obsahovat statické zápisy (například HTML značky) a dynamickou část (zpracování nebo prezentace hodnot). Vezmeme si krátké ukázkové XML:

<zaznamy>
  <mereni id="001">
    <datum>2017-02-01</datum>
 
   <teplota>-3.6</teplota>
  </mereni>
</zaznamy>

Pokud budeme chtít zobrazit následující tabulku:

ID Datum Teplota
001 2017-02-01 -3,6

, musíme připravit XSL zápis:

<xsl:template match="/">
  <html>  <!-- Vložíme základní značky HTML -->
    <head><title>Měření teploty</title></head>
    <body>
      <table> <!-- Vložíme pevnou část s tabulkou a prvním řádkem -->
        <tr><td>ID</td><td>Datum</td><td>Teplota</td></tr>
        <tr> <!-- Vložíme druhý řádek a do něj natáhneme hodnoty z XML -->
          <td><xsl:value-of select="mereni/@id" /></td> <!-- Vložíme atribut id ze značky mereni -->
          <td><xsl:value-of select="mereni/datum" /></td> !-- Vložíme hodnotu značky datum potomka značky mereni -->
          <td><xsl:value-of select="mereni/teplota" /></td> !-- Vložíme hodnotu značky teplota potomka značky mereni -->
        </tr>
      </table>
    </body>
  </html>
</xsl:template>

Zde tedy začínáme doporučenou cestou - tedy pro vložení osnovy HTML dokumentu dáme první šablonu na / - tedy kořen dokumentu. Ekvivaletní dokument může být i při nastavení šablony na kořenovou značku <zaznamy>.

<xsl:template match="zaznamy">
  <html>  <!-- Vložíme základní značky HTML -->
    <head><title>Měření teploty</title></head>
    <body>
      <table> <!-- Vložíme pevnou část s tabulkou a prvním řádkem -->
        <tr><td>ID</td><td>Datum</td><td>Teplota</td></tr>
        <tr> <!-- Vložíme druhý řádek a do něj natáhneme hodnoty z XML -->
          <td><xsl:value-of select="mereni/@id" /></td> <!-- Vložíme atribut id ze značky mereni -->
          <td><xsl:value-of select="mereni/datum" /></td> !-- Vložíme hodnotu značky datum potomka značky mereni -->
          <td><xsl:value-of select="mereni/teplota" /></td> !-- Vložíme hodnotu značky teplota potomka značky mereni -->
        </tr>
      </table>
    </body>
  </html>
</xsl:template>

Třetí možností je začít reakcí na značku <mereni>.

<xsl:template match="zaznamy/mereni">
  <html>  <!-- Vložíme základní značky HTML -->
    <head><title>Měření teploty</title></head>
    <body>
      <table> <!-- Vložíme pevnou část s tabulkou a prvním řádkem -->
        <tr><td>ID</td><td>Datum</td><td>Teplota</td></tr>
        <tr> <!-- Vložíme druhý řádek a do něj natáhneme hodnoty z XML -->
          <td><xsl:value-of select="./@id" /></td> <!-- Vložíme atribut id ze značky mereni -->
          <td><xsl:value-of select="datum" /></td> !-- Vložíme hodnotu značky datum potomka značky mereni -->
          <td><xsl:value-of select="teplota" /></td> !-- Vložíme hodnotu značky teplota potomka značky mereni -->
        </tr>
      </table>
    </body>
  </html>
</xsl:template>

Zde dochází k úpravě adresování, neboť šablona reaguje na jinou než kořenovou značku a tak musíme upravit adresování. Zápis ./@id vybere atribut id z aktuální značky.

Co celému dokumentu chybí? Ještě musí být celý zápis dán do souboru i s hlavičkou XSL dokumentu.

<?xml version="1.0" encoding="UTF-8"?><!-- hlavička -->
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:xs="http://www.w3.org/2001/XMLSchema"
                exclude-result-prefixes="xs"
                version="2.0">
<xsl:template match="zaznamy/mereni">
  <html>  <!-- Vložíme základní značky HTML -->
    <head><title>Měření teploty</title></head>
    <body>
      <table> <!-- Vložíme pevnou část s tabulkou a prvním řádkem -->
        <tr><td>ID</td><td>Datum</td><td>Teplota</td></tr>
        <tr> <!-- Vložíme druhý řádek a do něj natáhneme hodnoty z XML -->
          <td><xsl:value-of select="./@id" /></td> <!-- Vložíme atribut id ze značky mereni -->
          <td><xsl:value-of select="datum" /></td> <!-- Vložíme hodnotu značky datum potomka značky mereni -->
          <td><xsl:value-of select="teplota" /></td> !-- Vložíme hodnotu značky teplota potomka značky mereni -->
        </tr>
      </table>
    </body>
  </html>
</xsl:template>
</xsl:stylesheet>

A ješte musíme propojit XML soubor s XSL souborem.

<?xml version="1.0" encoding="UTF-8"?>
  <?xml-stylesheet type="text/xsl" href="/data-simple.xsl"?>
  <zaznamy>
    <mereni id="001">
      <datum>2017-02-01</datum>
      <teplota>-3.6</teplota>
    </mereni>
</zaznamy>


Kombinování šablon

Pokud bychom potřebovali udělat komplexní šablony, pak je ne úplně vhodné je psát všechny do sebe. Lepší je vytvořit dílčí šablony a ty pak nechat zpracovat. To se děje pomocí zápisu <xsl:apply-templates /> - tato značka aplikuje všechny šablony, které se nacházejí na dalších řádcích v XSL souboru.

Takže naše jednoduché XSL by mohlo vypadat takto:

<?xml version="1.0" encoding="UTF-8"?><!-- hlavička -->
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:xs="http://www.w3.org/2001/XMLSchema"
                exclude-result-prefixes="xs"
                version="2.0">

<xsl:template match="zaznamy">
  <html>
    <head><title>Měření teploty</title></head>
    <body>
      <table>
        <tr><td>ID</td><td>Datum</td><td>Teplota</td></tr>
        <tr> <!-- Vložíme druhý řádek a do něj natáhneme hodnoty z XML -->
          <xsl:apply-templates />         
        </tr>
      </table>
    </body>
  </html>
</xsl:template>

<xsl:template match="mereni">
  <td><xsl:value-of select="./@id" /></td>
  <td><xsl:value-of select="datum" /></td>
  <td><xsl:value-of select="teplota" /></td>
</xsl:template>
</xsl:stylesheet>

Takto lze udržet odřádkování na rozumné úrovni a mít stylopis v přehledné podobě.


Rozšířené možnost v šablonách

Cyklus

Výpis hodnot a provedení akce pro každý výskyt.

<xsl:template match="/">        
  <html>            
    <head><title>Výpis měření</title></head>            
    <body>
      <xsl:for-each select="mereni">
        <xsl:value-of select="@id"/><br/>
      </xsl:for-each>
    </body>            
  </html>        
</xsl:template>

Seřazení

Instrukce sort umí seřadit hodnoty, je nutné dávat pozor na datový typ. Atribut data-type u značky xsl:sort.

<xsl:template match="/">        
  <html>            
    <head><title>Výpis měření</title></head>            
    <body>
      <xsl:for-each select="mereni">
              <xsl:sort order="descending"/>
        <xsl:value-of select="@id"/><br/>
      </xsl:for-each>
    </body>            
  </html>        
</xsl:template>

Rozhodnutí

Pomocí if se rozhodneme, jaké položky budou zobrazeny.

<xsl:template match="/">        
  <html>            
    <head><title>Výpis měření</title></head>            
    <body>
      <xsl:for-each select="mereni">
        <xsl:if test="@id &gt; 5"/>
        <xsl:value-of select="@id"/><br/>

      </xsl:for-each>
    </body>            
  </html>        
</xsl:template>

Vícenásobné rozhodnutí

<xsl:template match="/">        
  <html>            
    <head><title>Výpis měření</title></head>            
    <body>
      <xsl:for-each select="mereni">
        <xsl:choose>
          <xsl:when test="@id &gt; 10"/>
            <td bgcolor="#ff0000"><xsl:value-of select="@id"/></td>
          </xsl:when>
          <xsl:when test="@id &gt; 5"/>
            <td bgcolor="#ff0000"><xsl:value-of select="@id"/></td>
          </xsl:when>

          <xsl:otherwise>
            <td><xsl:value-of select="@id"/></td>
          </xsl:otherwise>
        <xsl:choose>

      </xsl:for-each>
    </body>            
  </html>        
</xsl:template>


Výpočty v šablonách

Proměnné

V rámci XSL můžeme pracovat s proměnnými a tak výstupy "vylepšit" o vypočené hodnoty nebo o jiné proměnné. V rámci příkladu můžeme uvést počet položek, grafické znázornění poměru, ohodnocení určitým počtem grafických symbolů a podobně.

Proměnné můžeme definovat pro šablonu, část šablony nebo celý dokument.

První příklad může vypadat takto:

<xsl:param name="pozadi" select="lightblue" /> - definujeme na začátek souboru parametr pozadi s hodnotou lightgreen. Pak v kódu můžeme použít:

<table border="1" bgcolor="{$pozadi}">.

Pro vyvolání hodnoty tedy vkládáme znak $ a následně název parametru.

Do proměnné můžeme vkládat všechno možné, zde je ukázka výběru nejvyšší teploty:

<xsl:variable name="max">
  <xsl:for-each select="mereni/teplota">
    <xsl:sort select="." data-type="number" order="descending"/>
      <xsl:if test="position() = 1">
        <xsl:value-of select="."/>
      </xsl:if>
  </xsl:for-each>               
</xsl:variable>

Proměnná se jmenuje max, je vybrán element teplota, postupně jsou prohledány všechny výskyty tohoto elementu, seřazeny sestupně a do proměnné max je uložena 1. hodnota, tedy ta nejvyšší.

Variable nebo Param

Rozdíl mezi těmito značkami je obvykle udáván v tom, že <param> může být definován mimo XSL soubor, případně mimo danou šablonu. To lze i u proměnné, nicméně u níc je udáváno, že se je jích obsah nemůže dále měnit.

Výpočty

Výpočty - v XSLT můžeme počítat, například výskyty jednotlivých položek (v ukázce počet naměřených teplot vyšších než 0:

<xsl:value-of select="count(mereni[teplota<0])"/>

Takže jak vypadá XSLT pro výše uvedený příklad?

<?xml version="1.0" encoding="UTF-8"?><!-- hlavička -->
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:xs="http://www.w3.org/2001/XMLSchema"
                exclude-result-prefixes="xs"
                version="2.0">

<!-- Definujeme parametr pojmenovaný bgcolor s hodnotou lightgreen. -->
<xsl:param name="bgcolor" select="lightgreen" />

<!-- šablona pro celý dokument - obsahuje osnovu HTML + pevnou hlavičku tabulky - první řádek -->
<xsl:template match="/">
    <html>
        <head>
            <title>Měření teploty</title>
            <meta charset="UTF-8" />
        </head>
        <body>
            <h1>Měření teploty</h1>
            <table border="1">
              
<tr>
<!-- Pro použití barvy z parametru bgcolor jej zde aplikujeme. -->
                <td bgcolor="{$bgcolor}">ID</td>
                <td bgcolor="{$bgcolor}">Datum</td>
                <td bgcolor="{$bgcolor}">Teplota</td>

              </tr>           
<!-- Sem se aplikují všechny šablony pod touto. -->
              <xsl:apply-templates/>
            </table>            
        </body>        
    </html>   
</xsl:template>


<!-- pro kontakt uděláme cyklus, který vypíše řádek tabulky HTML - atribut, jmeno, prijmeni -->
<xsl:template match="mereni">

    <xsl:for-each select=".">
    <tr>
        <td>
            <xsl:value-of select="./@"/>
        </td>

        <td>
            <xsl:value-of select="datum"/>
        </td>

        <td>
            <xsl:value-of select="teplota"/>
        </td>
    </tr>
    </xsl:for-each>
</xsl:template>
</xsl:stylesheet>

Takže jak na to celé? Pojďme postupně, kdo chce komplení přehled najde ho zde: W3C recommendation - XSLT2.0.