Obsah
XSLT (eXtensible Stylesheet Language Transformation) je jazyk pro specifikaci transformací XML dokumentů na (obvykle) XML výstupy, případně textové, HTML či jiné výstupní formáty.
Původní aplikační oblastí byla transformace XML dat na XSL:FO (formátovací objekty), tedy vizualizace XML.
XSLT byl tedy součástí specifikací XSL (eXtensible Stylesheet Language).
Později se z XSL vyčlenil a začal být chápán jako univerzální jazyk popisu obecných XML->XML(txt, HTML) transformací.
Aktuální verze je dána specifikací XSLT 1.0.
Práce na verzi 1.1 byly zastaveny ve prospěch vývoje XSLT 2.0.
XSLT je funkcionálním jazykem, kde redukční pravidla mají podobu šablon, které předepisují, jak se uzly zdrojového dokumentu přepisují do výstupního dokumentu.
Specifikace XSLT transformace je obsažena v tzv. stylu (stylesheet), což je XML dokument tvořený podle syntaxe XSLT. Kořenovým elementem je stylesheet nebo transformation (to jsou synonyma).
XSLT styl obsahuje tzv. šablony (template).
Šablony mají výběrovou část - která reprezentuje levou stranu funkcionálního redukčního pravidla a konstrukční část představující pravou stranu red. prav.
Výběrovou část tvoří atribut match šablony.
Konstrukční část představuje tělo elementu šablony.
Vlastní transformace pak znamená, že interpreter XSLT stylů (XSLT procesor, XSLT engine) bere uzly vstupního dokumentu, vyhledá k nim vhodnou šablonu - podle její výběrové části - a vyprodukuje výsledek odpovídající konstrukční části pravidla daného touto šablonou.
XSLT 1.0 W3C Recommendation: http://www.w3.org/TR/xslt
What is XSLT? na XML.COM: http://www.xml.com/pub/a/2000/08/holman/index.html
Mulberrytech.com XSLT Quick Reference (2xA4, PDF): http://www.mulberrytech.com/quickref/XSLTquickref.pdf
Dr. Pawson XSLT FAQ: http://www.dpawson.co.uk/xsl/xslfaq.html
Zvon XSLT Tutorial: http://zvon.org/xxl/XSLTutorial/Books/Book1/index.html
Kořenový element xsl:transform nebo xsl:stylesheet uzavírá celý XSLT styl a specifikuje NS prefix pro XSLT elementy.
Deklarace parametrů (a jejich implic. hodnoty) - elt. xsl:param . Parametry lze nastavit při volání XSLT procesoru - např. java net.sf.saxon.Transform -o outfile.xml infile.xml style.xsl -Dparam=paramvalue
Deklarace a inicializace proměnných - elt. xsl:variable - proměnné jsou de facto totéž, co parametry, ale nejsou nastavitelné zvenčí.
Je třeba si uvědomit, že XSLT (bez procesorově-specifických rozšíření) je čistý funkcionální jazyk, tj. aplikace šablony nemá vedlejší efekt -> proměnné lze přiřadit jednou, pak už jen číst!
Deklarace (formátu) výstupu - elt. xsl:output
...kromě toho tam mohou být další, méně používané XSL elementy - viz např. dokumentace SAXONu
pak následují vlastní šablony - elt. xsl:template
Nejdříve se za aktuální uzel zvolí kořen, tj. uzel odpovídající XPath výrazu /
Najde se šablona (explicitní nebo implicitní - viz např. XSLT/XPath Quick Reference), jejíž match atribut chápaný jako XPath predikát vrátí v kontextu aktuálního uzlu true (tedy tzn. "matchuje" aktuální uzel).
Pokud je jich více - nastává nejednoznačnost - pak je indikována chyba.
Pokud je taková šablona právě jedna, aplikuje se, což znamenápřenesení jejího obsahu do výstupního result tree fragmentu.
Přímo/explicitně voláním (pojmenované) šablony - což ale odpovídá spíše přístupu procedurálních jazyků, takže se tomu spíše vyhýbáme.
Nepřímo/implicitně tím, že se zavolá šablona, jejíž vzor (obsah atr. match ) "pasuje" ("matchuje") na vybraný uzel - funkcionální přístup. Výběr uzlu se přitom děje opět:
Explicitně ("řízeně") uvedením atributu select u apply-templates . Takto můžeme vybrat jak dceřinné elementy, tak dceřinné uzly, tak jakékoli jiné uzly odpovídající XPath výrazu uvedenému v select .
Implicitně, necháme-li procesor sám "si uzel vybrat" (u apply-templates neuvádíme select ). V tomto případě se ale vybírají pouze dceřinné elementy kontextového uzlu.
Výstupem aplikace šablony je část tzv. result tree fragmentu.
Výstupy jednotlivých šablon se "skládají" na to místo result tree fragmentu, který odpovídá pořadí volání šablon.
Výstup celé transformace pak směřuje standardně do jednoho proudu, kde se z výstupního proudu událostí generuje výsledný (XML, text, HTML) dokument.
Výstup bývá procesorem primárně generován jako sled událostí (např. SAX2), které jsou až druhotně převáděny na výsledný dokument - s uplatněním výstupního kódování, atd.
Jak dostat text (textový uzel) na výstup?
Vepsat text přímo (jako literál) do výstupu (konstrukční části) šablony. Pozor na bílé znaky (mezery, CR/LF)!
vepsat text přímo (jako literál) do výstupu šablony. Pozor na bílé znaky (mezery, CR/LF)!
do speciálního elt. <xsl:text>textový uzel</xsl:text> . Bílé znaky jsou v něm vždy zachovány/respektovány!
Implicitní šablony jsou "vestavěné" v každém korektním procesoru XSLT:
aby byly (alespoň jistým standardním "fallback" způsobem) zpracovány základní struktury (procházení stromu dokumentu)
abychom "ušetřili psaní" často používaných šablon (ignorování komentářů a PI).
Jsou překrytelné, abychom mohli chování změnit uvedením vlastní šablony, která bude mít stejnou (nebo překrývající se) klauzuli match= .
<xsl:template match="*|/">
<xsl:apply-templates/>
<xsl:template>
<xsl:template match="*|/" mode="...">
<xsl:apply-templates mode="..."/>
<xsl:template>
Cíl: Vygenerovat na výstup předem daný element (s předem známým jménem), ale s atributy s hodnotami kalkulovanými při transformaci.
Řešení: Použít normální postup - literal result element - a hodnoty atributy specifikovat jako tzv. attribute value templates (AVT):
<link ref="odkaz_dovnitr_dok">
...
</link>
<xsl:template match="link">
<a href="#{@ref}"> ... </a>
</xsl:template>
Transformuje odkaz link na a , hodnotu atributu href spočte tak, že před hodnotu původního atributu ref přidá znak #
Cíl: Vygenerovat na výstup element, jehož název, atributy i obsah předem - při psaní stylu - neznáme.
Řešení: Použít do konstrukční části šablony xsl:element :
<generate element="elt_name"> ... </generate>
<xsl:template match="generate">
<xsl:element name="@element">
<xsl:attribute name="id">ID1</xsl:attribute>
</xsl:element>
</xsl:template>
Vytvoří element s názvem elt_name , opatří jej atributem id="ID1" .
Cíl: Větvit generování výstupu na základě podmínky.
Řešení: Použít do konstrukční části šablony větvení - jednoduché xsl:if nebo vícecestné xsl:choose / xsl:when / xsl:otherwise :
<rohlik cena="5"> ... </rohlik>
<xsl:template match="rohlik">
<p>
<xsl:if test="cena>2">
<span class="expensive">Drahý</span>
</xsl:if> rohlík - cena <xsl:value-of select="@cena"/> Kč </p>
</xsl:template>
Vytvoří element p , do něj vloží info o rohlíku - se zvýrazněním, je-li drahý.
<rohlik cena="5"> ... </rohlik>
<rohlik cena="2"> ... </rohlik>
<rohlik cena="0.9"> ... </rohlik>
<xsl:template match="rohlik">
<p>
<xsl:when test="cena>2">
<span class="expensive">Drahý</span>
</xsl:when>
<xsl:when test="cena<1">
<span class="strangely-cheap">Podezřele levný</span>
</xsl:when>
<xsl:otherwise>
<span class="normal-price">Běžný</span>
</xsl:otherwise> rohlík - cena <xsl:value-of select="@cena"/> Kč </p>
</xsl:template>
Odfiltruje dvě extrémní úrovně ceny - pro xsl:otherwise zůstane „normální“ cena.
Cíl: Větvit generování výstupu na základě podmínky.
Řešení: Použít do konstrukční části šablony větvení - jednoduché xsl:if nebo vícecestné xsl:choose / xsl:when / xsl:otherwise :
<pecivo>
<rohlik cena="5"> ... </rohlik>
<rohlik cena="2"> ... </rohlik>
<rohlik cena="0.9"> ... </rohlik>
</pecivo>
<xsl:template match="pecivo">
<xsl:for-each select="rohlik">
<p>Rohlík - cena <xsl:value-of select="@cena"/> Kč</p>
</xsl:for-each>
</xsl:template>
Vytvoří element p , do něj vloží info o rohlíku - se zvýrazněním, je-li drahý.
Pozor: Konstrukce xsl:for-each má typicky procedurální charakter, je dobré s ní šetřit. Dává totiž minumum flexibility na obsah iterované množiny uzlů - tj. předem musím vědět, co tam bude.
Populárními volně dostupnými procesory XSLT v javovém prostředí jsou:
... další free i komerční procesory k nalezení na XML Software
Motivace: Módy umožňují mít paralelně sadu šablon se stejnými vzory match , používaných ale pro různé účely, např.:
Při explicitním vyvolání aplikace šablon ( apply-templates ) lze uvést mód (atributem mode= ):
Deklarace - xsl:template name="jmeno_sablony"
Šablona smí obsahovat deklarace parametrů:
Vložíme-li do konstrukční části šablony (do těla šablony) element xsl:number , zajistí nám vygenerování čísla daného čítačem.
Je možné uvést, podle čeho se má číslovat, např.:
pořadového čísla zdrojového elementu v rámci jeho rodičovského elementu
- a to i víceúrovňově, např. číslo kapitoly 1.1. apod.
Příklad 1.1. Automatické číslování podle pozice elementu
Aplikujeme-li tento styl
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:template match="/">
<html>
<body>
<xsl:for-each select="devguru_staff/programmer">
<xsl:number value="position()" format="1. " />
<xsl:value-of select="name" />
<br/>
</xsl:for-each>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
na následující zdrojový soubor
<devguru_staff>
<programmer>
<name>Bugs Bunny</name>
<dob>03/21/1970</dob>
<age>31</age>
<address>4895 Wabbit Hole Road</address>
<phone>865-111-1111</phone>
</programmer>
<programmer>
<name>Daisy Duck</name>
<dob>08/09/1949</dob>
<age>51</age>
<address>748 Golden Pond</address>
<phone>865-222-2222</phone>
</programmer>
<programmer>
<name>Minnie Mouse</name>
<dob>04/13/1977</dob>
<age>24</age>
<address>4064 Cheese Factory Blvd</address>
<phone>865-333-3333</phone>
</programmer>
</devguru_staff>
dostaneme výslednou HTML stránku (nebrat v úvahu odsazení - to bude jiné...)
<html>
<body>1. Bugs Bunny<br>
2. Daisy Duck<br>
3. Minnie Mouse<br>
</body>
</html>
Příklad 1.2. Automatické víceúrovňové číslování
Aplikujeme-li tento styl
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:template match="/book">
<html>
<body>
<xsl:for-each select="chapter">
<h2>
<xsl:number count="chapter" format="1. "/>
<xsl:value-of select="title" />
</h2>
<xsl:for-each select="sect1">
<h3>
<xsl:number count="chapter" format="1. "/>
<xsl:number count="sect1" format="a. "/>
<xsl:value-of select="title" />
</h3>
<xsl:apply-templates select="para"/>
</xsl:for-each>
</xsl:for-each>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
na následující zdrojový soubor
<book>
<title>Moje nová kniha</title>
<chapter>
<title>První kapitola</title>
<sect1>
<title>První sekce první kapitoly</title>
<para>Text</para>
</sect1>
<sect1>
<title>Druhá sekce první kapitoly</title>
<para>Text druhé sekce</para>
</sect1>
</chapter>
<chapter>
<title>Druhá kapitola</title>
<sect1>
<title>První sekce druhé kapitoly</title>
<para>Text</para>
</sect1>
<sect1>
<title>Druhá sekce druhé kapitoly</title>
<para>Text druhé sekce</para>
</sect1>
</chapter>
</book>
dostaneme výslednou HTML stránku
Preferovat funkcionální přístup - např. xsl:template match= a xsl:apply-templates select=
před procedurálním přístupem - xsl:template name= a xsl:call-template name=
Používat módy zpracování ( xsl:template ... mode= a xsl:apply-templates ... mode= )
Členit styly do menších znovupoužitelných celků (souborů) a podle potřeby je vřazovat pomocí xsl:include a nebo, ještě lépe, xsl:import - protože import upřednostňuje šablony uvedené přímo v základním stylu nad šablonami importovanými.
Podrobněji viz příspěvek TP pro DATAKON 2001 - fulltext příspěvku a slidy.
Identická transformace 1 (nepřevede do výsledku atributy kořenového elementu!) http://wwbota.free.fr/XSLT_models/identquery.xslt
Identická transformace 2 http://wwbota.free.fr/XSLT_models/identquery2.xslt
Identická transformace s potlačením elementů, které nemají na ose // (v dceřinných uzlech ani jejich potomcích) žádné textové uzly http://wwbota.free.fr/XSLT_models/suppressEmptyElements.xslt
Nahradí atributy pomocí elementů http://wwbota.free.fr/XSLT_models/attributes2elements.xslt
Dtto, ale elementy vzniklé z atributů jsou ve zvláštním jmenném prostoru xslt/attributes2elements.xslt
Reverzní transformace xslt/elements2attributes.xslt
Proudové transformace pro XML (Streaming Transformations for XML, STX) jsou alternativním mechanizmem, jak specifikovat i prakticky vykonávat netriviální transformace XML zdrojů na XML a dalších formátů.
STX nabízejí transformační postup založený na jednoprůchodovém, tedy proudovém (=streaming), zpracování XML vstupu bez nutnosti budovat stromovou podobu zdrojového dokumentu, což:
SAX (Simple API for XML Processing) určuje proudové rozhraní pro zpracování XML;
proudové transformace XML bychom tedy mohli psát jako tzv. SAX filtry -
tento postup je ale programátorsky náročný a nepohodlný:
je to hodně nízkoúrovňová záležitost,
ve filtru je třeba explicitně udržovat stav zpracování,
vytvářet pomocné datové struktury... atd.
udržovatelnost a rozšiřitelnost netriviálních filtrů je obtížná, proto
vznikaly různé "berličky" jako Programmable SAX Filter (open-source, Raritan Technologies);
všechny měly společný imperativní přístup ke specifikaci transformace.
STX nabízí možnost popsat transformace deklarativně, podobně jako v jazyce XSLT, na nějž jsou programátoři již zvyklí,
STX se také nazývá "SAX se syntaxí XSLT".
STX popisují proudové transformace,
SAX (Simple API for XML Processing) určuje proudové rozhraní.
STX jsou budovány jako nadstavba SAX a mohou být se SAX kombinovány,
programovat (psát transformační styly) pro STX je méně náročné než programovat SAX (transformační) filtry.
Dobrým podrobnějším zdrojem info je http://www.informatik.hu-berlin.de/~obecker/Docs/EML2003/.
Charakteristika STX transformačního stylu a zpracování je podobná XSLT:
styl je XML dokument obsahující šablony podobné jako XSLT
šablony jsou voleny a aplikovány podle vzorů v klauzulích match
v šablonách mohou být buďto:
"literal result elements", čili přímo napsaný text, elementy mimo jmenný prostor XSLT... nebo
instrukce XSLT
namísto XPath jako pro XSLT je u STX používán jazyk STXPath.
Příklad převzat z Extended SAX Filter Processing with STX by Oliver Becker
„Modify the input by adding a consecutive ID attribute to certain elements (footnotes that appear within chapters):“
<stx:transform xmlns:stx="http://stx.sourceforge.net/2002/ns"
xmlns:ex="http://www.example.com/"
version="1.0" pass-through="all">
<stx:variable name="count" select="1" />
<stx:template match="chapter//footnote">
<stx:copy attributes="@*">
<stx:attribute name="ex:id" select="$count" />
<stx:assign name="count" select="$count + 1" />
<stx:process-children />
</stx:copy>
</stx:template>
</stx:transform>
STX podporuje rozhraní JAXP, čili STX procesor lze nastavit jako transformační nástroj v JAXP a následně místo XSLT stylů používat STX styly:
// use Joost as transformation engine
System.setProperty("javax.xml.transform.TransformerFactory",
"net.sf.joost.trax.TransformerFactoryImpl");
// the remaining code is known area
TransformerFactory tFactory = TransformerFactory.newInstance();
SAXTransformerFactory saxTFactory = (SAXTransformerFactory) tFactory;
// of course the transformation source must be different
TransformerHandler tHandler1 =
saxTFactory.newTransformerHandler(new StreamSource("trans.stx"));
...
myReader.setContentHandler(tHandler1);
myReader.setProperty("http://xml.org/sax/properties/lexical-handler",
tHandler1);
tHandler1.setResult(new SAXResult(tHandler2));
...
Vzhledem k novosti standardu je počet implementujících procesorů dosud malý.
open-source javová implementace dostupná na http://stx.sourceforge.net/
open-source implementace pro čistý Perl dostupná na http://www.gingerall.org/charlie/ga/xml/p_stx.xml
Odkaz na většinu publikovaných článků i disertaci O. Beckera je na http://stx.sourceforge.net/.