XSLT: transformace XML dokumentů

XSLT je jazyk pro transformaci XML dokumentů. Ze stejných dat umí vyrobit HTML stránku, jiný XML formát nebo prostý text, aniž by se zdrojový dokument jakkoli měnil.

Autor: Aktualizováno

Jak XSLT funguje

Transformace má tři účastníky: zdrojový XML dokument, šablonu XSLT (tzv. stylesheet, sama je XML dokumentem) a procesor, který je spojí a vytvoří výstup. Šablona se neskládá z příkazů „udělej krok 1, krok 2“, ale z pravidel: „když narazíš na uzel tohoto typu, vypiš tohle“. Které uzly pravidlo zachytí, určuje výraz XPath.

Procesor začne u kořene dokumentu, najde šablonu, která mu odpovídá, a vykoná ji. Instrukce xsl:apply-templates ho pošle dál ke zvoleným potomkům a celý postup se opakuje. Pro uzly bez vlastní šablony existují vestavěná pravidla, která projdou potomky a vypíšou text.

Příklad: z XML na HTML seznam

Zdrojem je stejná knihovna jako v kapitole o XPath:

knihovna.xml
<?xml version="1.0" encoding="UTF-8"?>
<knihovna>
  <kniha id="b1" jazyk="cs">
    <nazev>Saturnin</nazev>
    <autor>Zdeněk Jirotka</autor>
    <rok>1942</rok>
    <cena>249</cena>
  </kniha>
  <kniha id="b2" jazyk="cs">
    <nazev>Válka s mloky</nazev>
    <autor>Karel Čapek</autor>
    <rok>1936</rok>
    <cena>299</cena>
  </kniha>
  <kniha id="b3" jazyk="en">
    <nazev>R.U.R.</nazev>
    <autor>Karel Čapek</autor>
    <rok>1920</rok>
    <cena>199</cena>
  </kniha>
</knihovna>

Šablona z ní vyrobí HTML seznam knih seřazený podle roku vydání:

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

  <xsl:template match="/">
    <html>
      <body>
        <h1>Knihovna – počet knih: <xsl:value-of select="count(knihovna/kniha)"/></h1>
        <ul>
          <xsl:apply-templates select="knihovna/kniha">
            <xsl:sort select="rok" data-type="number"/>
          </xsl:apply-templates>
        </ul>
      </body>
    </html>
  </xsl:template>

  <xsl:template match="kniha">
    <li lang="{@jazyk}">
      <strong><xsl:value-of select="nazev"/></strong>
      <xsl:text> — </xsl:text>
      <xsl:value-of select="autor"/>
      <xsl:if test="cena &gt; 250"> (dražší)</xsl:if>
    </li>
  </xsl:template>
</xsl:stylesheet>

Výsledek (výstup procesoru xsltproc):

výstup
<html><body>
<h1>Knihovna – počet knih: 3</h1>
<ul>
<li lang="en">
<strong>R.U.R.</strong> — Karel Čapek</li>
<li lang="cs">
<strong>Válka s mloky</strong> — Karel Čapek (dražší)</li>
<li lang="cs">
<strong>Saturnin</strong> — Zdeněk Jirotka</li>
</ul>
</body></html>
  • šablona pro / vytvoří kostru stránky a nadpis s počtem knih,
  • xsl:apply-templates se xsl:sort zpracuje knihy od nejstarší,
  • šablona pro kniha vypíše jednu položku seznamu,
  • lang="{@jazyk}" je šablona hodnoty atributu — výraz ve složených závorkách se vyhodnotí a vloží do atributu,
  • znak > v podmínce se zapisuje jako entita, protože šablona musí být platné XML.

Transformaci spustíš z příkazové řádky příkazem xsltproc knihovna.xsl knihovna.xml, nebo v naší záložce XSLT přímo v prohlížeči. Záložka běží na stejné knihovně libxslt jako xsltproc, zkompilované do WebAssembly, takže výsledky obou cest se shodují a chyby v šabloně ukáže i s číslem řádku.

Nejdůležitější instrukce

InstrukceCo dělá
xsl:template match="…"šablona pro uzly odpovídající vzoru
xsl:apply-templates select="…"zpracuje vybrané uzly jejich šablonami
xsl:value-of select="…"vloží textovou hodnotu výrazu
xsl:for-each select="…"cyklus přes vybrané uzly
xsl:if test="…"podmínka bez větve „jinak“
xsl:choose / when / otherwisevícenásobná podmínka
xsl:sort select="…"řazení uvnitř apply-templates nebo for-each
xsl:copy / xsl:copy-ofmělká / úplná kopie uzlu do výstupu
xsl:variable name="…"pojmenovaná hodnota (po nastavení se nemění)
xsl:output method="…"formát výstupu: xml, html nebo text

Vícenásobná podmínka se zapisuje takto:

<xsl:choose>
  <xsl:when test="rok &lt; 1930">klasika</xsl:when>
  <xsl:when test="rok &lt; 1950">meziválečná</xsl:when>
  <xsl:otherwise>novější</xsl:otherwise>
</xsl:choose>

Proměnné v XSLT nejsou proměnné v běžném smyslu: po nastavení se nedají změnit. XSLT je deklarativní jazyk, a místo počítadel v cyklu se proto používá position(), count() nebo rekurze šablon.

Identická transformace: kopírovat a měnit jen něco

Častý úkol je vzít dokument a změnit jen malou část — přejmenovat element, vynechat citlivé údaje, přidat atribut. Základem je identická transformace, která zkopíruje vše beze změny, a k ní se přidají šablony pro výjimky:

<xsl:template match="@* | node()">
  <xsl:copy>
    <xsl:apply-templates select="@* | node()"/>
  </xsl:copy>
</xsl:template>

<!-- výjimka: element cena z výstupu vynechá -->
<xsl:template match="cena"/>

Šablona s konkrétnějším vzorem (cena) má přednost před obecnou (node()), takže ceny z výstupu zmizí a zbytek dokumentu zůstane zachován.

Verze XSLT a procesory

  • XSLT 1.0 (1999) — nad XPath 1.0; nejrozšířenější verze.
  • XSLT 2.0 (2007) — XPath 2.0, seskupování (xsl:for-each-group), regulární výrazy, více výstupních souborů, vlastní funkce.
  • XSLT 3.0 (2017) — streamování velkých dokumentů, mapy, práce s JSON, balíčky.
ProcesorVerze XSLTKde
libxslt (xsltproc)1.0Linux, macOS, PHP, Python lxml, Chrome do verze 157
Saxon3.0 (a starší)Java, .NET, JavaScript (SaxonJS), C
.NET XslCompiledTransform1.0.NET
Java JAXP (Xalan)1.0součást JDK
Prohlížeče (XSLTProcessor)1.0JavaScript API v prohlížeči — Chrome ho od verze 158 odstraňuje
xslt-polyfill1.0libxslt ve WebAssembly, náhrada XSLTProcessor v JavaScriptu

Pozor na prohlížeče: vestavěné XSLT z nich mizí, podrobnosti jsou v další sekci XSLT v prohlížeči končí.

XSLT v prohlížeči končí

Prohlížeče dlouho uměly XSLT 1.0 dvěma cestami: z JavaScriptu přes třídu XSLTProcessor a přímo při otevření XML souboru, který obsahuje instrukci <?xml-stylesheet type="text/xsl" href="…"?>. Chrome obojí odstraňuje. Důvodem je bezpečnost: podle Chromu stojí XSLT na starých a složitých knihovnách v C/C++, ve kterých se opakovaně objevují chyby práce s pamětí. Používá ho přitom jen asi 0,02 % načtení stránek.

Verze ChromeDatumCo se mění
1432. 12. 2025XSLT oficiálně zastaralé, konzole hlásí varování
14610. 3. 2026podniková zásada, kterou si firmy mohou XSLT ponechat
15225. 8. 2026origin trial, kterým si ho může ponechat web
15817. 11. 2026XSLT ve stabilní verzi přestane fungovat všem, kdo nemají zásadu nebo origin trial
17617. 8. 2027zásada i origin trial končí, XSLT je odstraněné úplně

Zdroj: Removing XSLT for a more secure browser (Chrome for Developers). Firefox a Safari (WebKit) odstranění také ohlásily, zatím ale bez data.

Co to znamená v praxi

  • Kód, který volá new XSLTProcessor(), v Chrome 158 a novějším skončí chybou, protože třída přestane existovat.
  • XML soubor s instrukcí <?xml-stylesheet type="text/xsl"?> se už netransformuje. Týká se to hlavně stylovaných map webu a RSS feedů, které se v prohlížeči zobrazovaly jako stránka.
  • Stylování přes CSS (<?xml-stylesheet type="text/css"?>) zůstává, končí jen varianta s XSLT.
  • XSLT jako jazyk nekončí. Na serveru, v příkazové řádce a v knihovnách (libxslt, Saxon, .NET, Java) funguje dál beze změny.

Čím vestavěné XSLT nahradit

  • Transformace na serveru: XML převeď na HTML předem (při sestavení webu nebo na požadavek) a prohlížeči posílej hotovou stránku. Pro většinu webů je to nejčistší řešení.
  • xslt-polyfill: libxslt zkompilované do WebAssembly, které nahradí XSLTProcessor a umí zpracovat i instrukci <?xml-stylesheet?>. Vhodné pro stávající kód v XSLT 1.0.
  • SaxonJS: XSLT 3.0 v JavaScriptu, pokud chceš novější verzi jazyka.
  • JSON a JavaScript: u nových aplikací Chrome doporučuje data posílat jako JSON a vykreslovat je ve frameworku.

Naše záložka XSLT konec nativní podpory neovlivní. Nativní XSLTProcessor nevolá a transformace běží na engine z xslt-polyfill (libxslt, XSLT 1.0 s rozšířeními EXSLT), takže funguje i v prohlížeči, kde je vestavěné XSLT vypnuté.

Parametry a výstup do textu či CSV

XSLT 1.0: jednosloupcové CSV
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="text" encoding="UTF-8"/>
  <xsl:param name="minimum" select="100"/>
  <xsl:template match="/">
    <xsl:text>cena&#10;</xsl:text>
    <xsl:for-each select="objednavka/polozka[number(@cena) &gt;= $minimum]">
      <xsl:sort select="@cena" data-type="number"/>
      <xsl:value-of select="@cena"/><xsl:text>&#10;</xsl:text>
    </xsl:for-each>
  </xsl:template>
</xsl:stylesheet>

Parametr může volající nastavit zvenčí, proměnná xsl:variable se zvenčí takto nenastavuje. Obě vazby mají hodnotu, kterou nepřepisuješ při každém průchodu. xsl:with-param předává parametr volané šabloně.

Pro vstup s cenami 199 a 49 vrátí ukázka hlavičku a cenu 199. U textových CSV sloupců musíš ošetřit oddělovače, uvozovky a konce řádků; samotné value-of pravidla CSV neimplementuje.

Seskupování a JSON v novějších verzích

Fragment XSLT 2.0: seskupení podle kategorie
<xsl:for-each-group select="objednavka/polozka" group-by="@kategorie">
  <skupina kategorie="{current-grouping-key()}">
    <xsl:copy-of select="current-group()"/>
  </skupina>
</xsl:for-each-group>

Od 2.0 existuje for-each-group, regulární výrazy, funkce a bohatší typový systém. V 1.0 se seskupování řeší jinými postupy, například klíči. Verze 3.0 přidává mimo jiné balíčky, mapy a možnosti streamování; dostupnost závisí na procesoru a jeho edici.

XSLT 3.0: JSON bez ručního escapování
<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="json"/>
  <xsl:template match="/">
    <xsl:sequence select="map { 'pocet': count(objednavka/polozka) }"/>
  </xsl:template>
</xsl:stylesheet>

JSON serializace zapisuje mapu či pole a řeší escapování. Nejde o obecný bezeztrátový převod libovolného XML. Online XSLT nástroj XML.cz používá libxslt ve WebAssembly a podporuje 1.0; ukázky 2.0 a 3.0 potřebují odpovídající procesor.

Úplný CSV výstup s escapováním uvozovek

knihy.xml
<knihy><kniha id="001"><nazev>XML, JSON a "data"</nazev></kniha></knihy>
csv.xsl — celá transformace XSLT 1.0
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output method="text" encoding="UTF-8"/>
 <xsl:template match="/">
  <xsl:text>id,nazev&#13;&#10;</xsl:text>
  <xsl:for-each select="knihy/kniha">
   <xsl:call-template name="pole"><xsl:with-param name="text" select="@id"/></xsl:call-template>
   <xsl:text>,</xsl:text>
   <xsl:call-template name="pole"><xsl:with-param name="text" select="nazev"/></xsl:call-template>
   <xsl:text>&#13;&#10;</xsl:text>
  </xsl:for-each>
 </xsl:template>
 <xsl:template name="pole"><xsl:param name="text"/>
  <xsl:text>"</xsl:text><xsl:call-template name="uvozovky"><xsl:with-param name="text" select="string($text)"/></xsl:call-template><xsl:text>"</xsl:text>
 </xsl:template>
 <xsl:template name="uvozovky"><xsl:param name="text"/>
  <xsl:choose><xsl:when test="contains($text, '&quot;')">
   <xsl:value-of select="substring-before($text, '&quot;')"/><xsl:text>""</xsl:text>
   <xsl:call-template name="uvozovky"><xsl:with-param name="text" select="substring-after($text, '&quot;')"/></xsl:call-template>
  </xsl:when><xsl:otherwise><xsl:value-of select="$text"/></xsl:otherwise></xsl:choose>
 </xsl:template>
</xsl:stylesheet>
Spuštění; online tester podporuje tuto verzi
xsltproc csv.xsl knihy.xml > knihy.csv
Očekávaný CSV obsah; skutečné konce řádků CRLF
id,nazev
"001","XML, JSON a ""data"""

Každé pole je obaleno uvozovkami a vnitřní uvozovky jsou zdvojené. Čárka ani konec řádku uvnitř textu pak nerozdělí pole. Rekurzivní šablona je názorná, pro extrémně dlouhý text s mnoha uvozovkami použij účinnější procesor nebo CSV knihovnu. Import do tabulkového procesoru může změnit text 001 na číslo; zvol typ sloupce text. CSV quoting neřeší vzorce v Excelu, jejichž riziko závisí na aplikaci příjemce.