XSLT (Extensible Stylesheet Language Transformations)

O XSLT

XSLT je XML formát, který je šablonou, která popisuje, jak se má obsah (jiného) XML zobrazit. Vychází se z myšlenky, že by se měl odělovat obsah od vzhledu. Jeden XML soubor obsahuje jen data (jako v příkladu níže adresar.xml obsahuje jen jména a adresy) a XSLT obsahuje šablonu, která říká, jak se má obsah XML zobrazit.

Jde vlastně o transformaci XML souboru do jiného XML souboru, nebo do HTML souboru, nebo třeba do obyčejného textového souboru. XSLT zkrátka říká, jak se má XML vykreslit.

Pokud vás XSLT nezaujme, nic si z toho nedělejte a klidně na něj zapomeňte. Tato technologie není v současnosti zrovna IN. Příklad použití s libxml2 je ale tak jednoduchý, že jsem prostě neodolal a musel ho napsat.

Příklad v XML

Podívejte se na příklad. Nejdříve XML soubor adresar.xml. Všiměte si, že v sobě obsahuje odkaz na XSLT soubor <?xml-stylesheet type="text/xsl" href="adresar.xsl"?> Tomuto odkazu rozumí například webové prohlížeče a tak vědí, odkud si stáhnout XSLT soubor.

DTD jsem tentokrát uložil do extra souboru adresar.dtd, viz <!DOCTYPE adresare SYSTEM "adresar.dtd">.

<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="adresar.xsl"?>
<!DOCTYPE adresare SYSTEM "adresar.dtd">

<adresare>
<Adresar>
        <firstName><![CDATA[Petr]]></firstName>
        <lastName><![CDATA[Bílek]]></lastName>
        <street><![CDATA[Národní]]></street>
        <cisloPopisne><![CDATA[222]]></cisloPopisne>
        <city><![CDATA[Kladno]]></city>
        <psc><![CDATA[2545435]]></psc>
        <phone><![CDATA[]]></phone>
</Adresar>
<Adresar>
        <firstName><![CDATA[Jan]]></firstName>
        <lastName><![CDATA[Svoboda]]></lastName>
        <street><![CDATA[Bratří Trnků]]></street>
        <cisloPopisne><![CDATA[4354353]]></cisloPopisne>
        <city><![CDATA[Brno]]></city>
        <psc><![CDATA[54543543]]></psc>
        <phone><![CDATA[332 545 435]]></phone>
</Adresar>
<Adresar>
        <firstName><![CDATA[Tomáš]]></firstName>
        <lastName><![CDATA[Vomáčka]]></lastName>
        <street><![CDATA[Kosmická]]></street>
        <cisloPopisne><![CDATA[234]]></cisloPopisne>
        <city><![CDATA[Praha 4]]></city>
        <psc><![CDATA[345454]]></psc>
        <phone><![CDATA[333222444]]></phone>
</Adresar>
<Adresar>
        <firstName><![CDATA[Monika]]></firstName>
        <lastName><![CDATA[Šustrová]]></lastName>
        <street><![CDATA[Spálená]]></street>
        <cisloPopisne><![CDATA[244]]></cisloPopisne>
        <city><![CDATA[Praha 2]]></city>
        <psc><![CDATA[546654]]></psc>
        <phone><![CDATA[777444333]]></phone>
</Adresar>
<Adresar>
        <firstName><![CDATA[Patrik]]></firstName>
        <lastName><![CDATA[Kovář]]></lastName>
        <street><![CDATA[Šílená]]></street>
        <cisloPopisne><![CDATA[9]]></cisloPopisne>
        <city><![CDATA[Postoloprty]]></city>
        <psc><![CDATA[244544]]></psc>
        <phone><![CDATA[608454544]]></phone>
</Adresar>
<Adresar>
        <firstName><![CDATA[Rudolf]]></firstName>
        <lastName><![CDATA[Mrázek]]></lastName>
        <street><![CDATA[Zapadlá]]></street>
        <cisloPopisne><![CDATA[0]]></cisloPopisne>
        <city><![CDATA[Kostitřasy]]></city>
        <psc><![CDATA[]]></psc>
        <phone><![CDATA[555070070]]></phone>
</Adresar>
<Adresar>
        <firstName><![CDATA[Kristýna]]></firstName>
        <lastName><![CDATA[Vetchá]]></lastName>
        <street><![CDATA[Pod Vodou]]></street>
        <cisloPopisne><![CDATA[405]]></cisloPopisne>
        <city><![CDATA[Praha 4]]></city>
        <psc><![CDATA[454554]]></psc>
        <phone><![CDATA[303565565]]></phone>
</Adresar>
<Adresar>
        <firstName><![CDATA[Renike]]></firstName>
        <lastName><![CDATA[Gáthy]]></lastName>
        <street><![CDATA[Dunajská]]></street>
        <cisloPopisne><![CDATA[333]]></cisloPopisne>
        <city><![CDATA[Budapešť]]></city>
        <psc><![CDATA[2454]]></psc>
        <phone><![CDATA[5645455454]]></phone>
</Adresar>
<Adresar>
        <firstName><![CDATA[Vladimír]]></firstName>
        <lastName><![CDATA[Horlivý]]></lastName>
        <street><![CDATA[Líná]]></street>
        <cisloPopisne><![CDATA[3]]></cisloPopisne>
        <city><![CDATA[České Budějovice]]></city>
        <psc><![CDATA[446]]></psc>
        <phone><![CDATA[4534535]]></phone>
</Adresar>
<Adresar>
        <firstName><![CDATA[Petra]]></firstName>
        <lastName><![CDATA[Kozáková]]></lastName>
        <street><![CDATA[Zahradní]]></street>
        <cisloPopisne><![CDATA[5454]]></cisloPopisne>
        <city><![CDATA[New York]]></city>
        <psc><![CDATA[4545]]></psc>
        <phone><![CDATA[45335435]]></phone>
</Adresar>
</adresare>

Soubor adresar.dtd si můžete prohlédnout tady, ale pro tuto kapitolu je zcela bezvýznamný.

<?xml version="1.0" encoding="UTF-8"?>
<!ELEMENT adresare (Adresar)*>
<!ELEMENT Adresar (firstName,lastName,street,cisloPopisne,city,psc,phone)>
<!ELEMENT firstName (#PCDATA)>
<!ELEMENT lastName (#PCDATA)>
<!ELEMENT street (#PCDATA)>
<!ELEMENT cisloPopisne (#PCDATA)>
<!ELEMENT city (#PCDATA)>
<!ELEMENT psc (#PCDATA)>
<!ELEMENT phone (#PCDATA)>

A tady je XSLT soubor adresar.xsl. Jak asi tušíte, převádí adrsar.xml do HTML. Jazyk XSLT v této kapitole popisovat nebudu (ani jiné), na to si najděte jiný tutoriál (pokud vás XSLT vůbec zajímá). Já vám jen ukáži, jak XSLT na XML aplikovat pomocí knihovny libxml2.

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="/">
        <html>
            <head>
                <title>Adresář</title>
                <style type="text/css">
                     table {
                        border-collapse:collapse;
                     }
                     th,td {
                        padding:3px 5px;
                        text-align:left;
                     }
                     th {
                        border-bottom:3px solid black;
                     }
                </style>
            </head>
            <body>
                <h1>Adresář</h1>
                <xsl:apply-templates></xsl:apply-templates>
            </body>
        </html>
    </xsl:template>

    <xsl:template match="adresare">
        <table border="1">
        <tr style="background:#00aaff;color:#ffffff;">
            <th>Jméno</th><th>Příjmení</th>
            <th>Ulice</th><th>ČP</th><th>Město</th><th>PSČ</th>
            <th>Telefon*</th>
        </tr>
            <xsl:apply-templates select="Adresar">
            <xsl:sort select="city"></xsl:sort>
            <xsl:sort select="firstName" order="descending"></xsl:sort>
            </xsl:apply-templates>
        </table>
        <em>*Povinná položka</em>
    </xsl:template>

    <xsl:template match="Adresar">
        <xsl:if test="starts-with(city,'Praha')">
            <tr bgcolor="#00fa00">
                <xsl:for-each select="*">
                    <td><xsl:value-of select="."></xsl:value-of></td>
                </xsl:for-each>
            </tr>
        </xsl:if>
        <xsl:if test="not(starts-with(city,'Praha'))">
            <tr>
                <xsl:apply-templates></xsl:apply-templates>
            </tr>
        </xsl:if>
    </xsl:template>

    <xsl:template match="phone">
        <xsl:choose>
            <xsl:when test=". = ''">
                <td bgcolor="red"><xsl:value-of select="."></xsl:value-of></td>
            </xsl:when>
            <xsl:otherwise>
                <td><xsl:value-of select="."></xsl:value-of></td>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template>

    <xsl:template match="*">
        <td><xsl:value-of select="."></xsl:value-of></td>
    </xsl:template>

</xsl:stylesheet>

Výsledek si můžete prohlédnout v každém dobrém webovém prohlížeči (Firefoxu) zde: adresar.xml. Nebo se podívejte na obrázek:

adresar.xml

adresar.xml v prohlížeči Firefox.

Transforamce pomocí libxml2

Program funguje vcelku jednoduše. Nejdříve se nastaví nějaké globální parametry, pak se načtou XML a XSLT soubory, provede se transformace, transformace se uloží a uvolní se zdroje.

Volání funkce xmlSubstituteEntitiesDefault(1) řekne libxml2, že má nahrazovat entity. Jestli nevíte co jsou to entity, pak asi neznáte dokonale XML. Z toho si nic nedělejte :-). Nastavení globální proměnné xmlLoadExtDtdDefaultValue na 1 zase libxml2 říká, že má načítat externí XSLT soubory (pokud se na ně z XSLT odkazujete).

Volání xmlParseFile() už znáte z povídání o DOM. Funkce xsltParseStylesheetFile() parsuje XSLT soubor.
Funkce xsltApplyStylesheet() provede transformaci a odkaz na výsledek vrátí v proměnné typu xmlDocPtr. Jako třetí parametr přebírá tato funkce nějké parametry, které jsou předávány do XSLT. Je to pole ukončené NULL, obsahující dvojice název a hodnota parametrů (nebo taky nic, jako v příkladu).

Funkce xsltSaveResultToFile() uloží výsledek do souboru. V příkladu je prvním argumentem stdout, tedy standardní výstup, takže se transformace vypíše na obrazovku.

  1. /*------------------------------------------------*/
  2. /* 27dXslt/xslt.c                                 */
  3. #include <string.h>
  4. #include <libxslt/xslt.h>
  5. #include <libxslt/transform.h>
  6. #include <libxslt/xsltutils.h>
  7.  
  8. /* extern int xmlLoadExtDtdDefaultValue; */
  9.  
  10. int main(int argc, char **argv)
  11. {
  12.     xsltStylesheetPtr cur;
  13.     xmlDocPtr doc, res;
  14.     const char *params[] = { NULL};
  15.     char * xmlSoubor = "adresar.xml";
  16.     char * xslSoubor = "adresar.xsl";
  17.  
  18.     xmlSubstituteEntitiesDefault(1);
  19.     xmlLoadExtDtdDefaultValue = 1;
  20.     cur = xsltParseStylesheetFile((const xmlChar *)xslSoubor);
  21.     doc = xmlParseFile(xmlSoubor);
  22.     res = xsltApplyStylesheet(cur, doc, params);
  23.     xsltSaveResultToFile(stdout, res, cur);
  24.  
  25.     xsltFreeStylesheet(cur);
  26.     xmlFreeDoc(res);
  27.     xmlFreeDoc(doc);
  28.  
  29.     xsltCleanupGlobals();
  30.     xmlCleanupParser();
  31.  
  32.     return (0);
  33. }
  34. /*------------------------------------------------*/

Na konci se volají funkce, které mají na starosti nezbytné uvolňování prostředků.

Nainstalujte si balíčky libxslt-devel a libxml2-devel. Bez toho tento příklad nepřeložíte. Překlad může vypadat takto:

$ gcc -o xslt -g -Wall `xslt-config --cflags --libs` `xml2-config --libs` xslt.c

Po spuštění programu se vám na obrazovku vypíše výsledné HTML.

Komentář Hlášení chyby
Created: 6.9.2014
Last updated: 10.10.2014
Tato stánka používá ke svému běhu cookies, díky kterým je možné monitorovat, co tu provádíte (ne že bych to bez cookies nezvládl). Také vás tu bude špehovat google analytics. Jestli si myslíte, že je to problém, vypněte si cookies ve vašem prohlížeči, nebo odejděte a už se nevracejte :-). Prohlížením tohoto webu souhlasíte s používáním cookies. Dozvědět se více..