Szablon (template) może posiadać nazwę podaną w atrybucie name
.
Wówczas szablon ten można wywołać używając instrukcji call-template
.
Przy takim wywołaniu nie zmienia się kontekst (inaczej niż przy apply-templates
).
Szablon musi posiadać co najmniej jeden z parametrów match
i name
, może
posiadać oba.
Plik: named.xsl.
<xsl:template name="opisz-element"> <p>Element o nazwie <xsl:value-of select="name()"/>.</p> </xsl:template> <xsl:template match="/"> <html> <body> <h1>Wszystkie elementy:</h1> <xsl:for-each select="//*"> <xsl:call-template name="opisz-element"/> </xsl:for-each> <h1>Elementy poziomu głównego:</h1> <xsl:for-each select="/*/*"> <xsl:call-template name="opisz-element"/> </xsl:for-each> </body> </html> </xsl:template>
XSLT pozwala na deklarowanie parametrów i zmiennych, których następnie można używać w wyrażeniach XPath, np.: $nazwa
.
Zmienne w XSLT są deklaratywne (jak w programowaniu funkcyjnym): już w miejscu
deklaracji następuje przypisanie wartości, której następnie nie można modyfikować. Zmienne deklaruje się
w elementach variable
.
Deklaracja zmiennej lokalnej może wystąpić wewnątrz konstruktorów sekwencji.
Zmienna jest widoczna do końca elementu, w którym została zadeklarowana.
Wartość zmiennej lokalnej może być obliczana wielokrotnie (gdy szablon jest wielokrotnie używany
lub wewnątrz pętli for-each
).
Deklaracja zmiennej globalnej może wystąpić na głównym poziomie arkusza. Zmienna jest widoczna we wszystkich szablonach oraz deklaracjach innych zmiennych (i parametrów) globalnych. Cykliczne definicje są błędami. Wartość zmiennej globalnej jest obliczana tylko raz, może zależeć od parametrów lub treści dokumentu.
Wartość zmiennej można podać na dwa sposoby:
select
, wówczas przypisywana jest obliczona wartość wyrażenia,
variable
, która jest interpretowana tak jak konstruktor sekwencji,
a wynik tej interpretacji jest przypisywany na zmienną (jako sekwencja węzłów dokumentu,
chyba że podano atrybut as
).
W XSLT 1.0 istnieje różnica między wartością wyrażenia z select
a wartością uzyskaną
w wyniku interpretacji wnętrza variable
. Ta druga jest typu result tree fragment
i nie można już na niej wykonywać takich operacji jak for-each
czy apply-templates
.
To rozróżnienie nie występuje w XSLT 2.0, dzięki temu możliwe jest to.
<xsl:variable name="ile-elementow" select="count(//element())"/> <xsl:variable name="tekst"> <p>Dokument ma <xsl:value-of select="$ile-elementow"/> elementów.</p> </xsl:variable> <xsl:template match="/"> <html> <body> <xsl:sequence select="$tekst"/> </body> </html> </xsl:template>
<xsl:template match="konto"> <xsl:variable name="jakie">} <xsl:choose> <xsl:when test="saldo > 0">dodatnie</xsl:when> <xsl:when test="saldo < 0">ujemne</xsl:when> <xsl:otherwise>równe zero</xsl:otherwise> </xsl:choose> </xsl:variable> Saldo konta jest <xsl:value-of select="$jakie"/>. </xsl:template>
Parametry arkusza (globalne) są zadeklarowane w elementach param
na głównym poziomie arkusza.
Ich wartość można dostarczyć z zewnątrz przed wykonaniem przekształcenia – procesor XSLT powinien to umożliwiać.
Parametry mogą mieć wartość domyślną, którą podaje się tak samo jak wartość zmiennych. Widoczność parametrów arkusza jest taka jak zmiennych globalnych.
W XSLT 2.0 w atrybucie as
można podać typ parametru, a w atrybucie required
powiedzieć
czy parametr jest obowiązkowy.
Sparametryzować można także pojedyncze szablony, robi się to za pomocą elementów param
umieszczonych na początku treści szablonu. Tak samo jak dla parametrów globalnych można podać
wartość domyślną, typ i obowiązkowość.
Do przekazania wartości parametrów do szablonu służą elementy with-param
umieszczone
wewnątrz apply-templates
lub call-template
. Wartość określa się
tak samo jak wartość zmiennych lub domyślną wartość parametrów.
Szablony nazwane wraz z parametrami mogą działać podobnie jak procedury i pozwalają na „programowanie”.
Pliki: arkusz, dokument wejściowy.
<xsl:template name="silnia"> <xsl:param name="n"/> <xsl:param name="res" select="1"/> <xsl:choose> <xsl:when test="$n > 1"> <xsl:call-template name="silnia"> <xsl:with-param name="n" select="$n - 1"/> <xsl:with-param name="res" select="$n * $res"/> </xsl:call-template> </xsl:when> <xsl:otherwise> <xsl:value-of select="$res"/> </xsl:otherwise> </xsl:choose> </xsl:template>
Napisz i przetestuj szablon nazwany repeat
o parametrach value
i n
,
wstawiający n
razy wartość parametru value
.
Do tworzenia poszczególnych węzłów dokumentu wynikowego można użyć odpowiednich instrukcji XSLT:
<xsl:element name="elem-{$sufix}"> <xsl:attribute name="atryb">wartość atrybutu</xsl:attribute> <xsl:text>Zawartość tekstowa</xsl:text> </xsl:element> <xsl:comment>To będzie komentarz</xsl:comment> <xsl:processing-instruction target="xml-stylesheet">type="text/css" href="styl.css"</xsl:processing-instruction>
Dla takiego dokumentu napisz arkusz, który zamienia rozdziały na akapity (p
)
a ich tytuły przedstawia jako nagłówki (h1
, h2
, itd.).
Tytuł rozdziału zagnieżdżonego na poziomie N jest reprezentowany jako nagłówek stopnia min(N, 5),
a element p
ma atrybut class
równy levelN
.
Zadanie można rozwiązać na co najmniej dwa sposoby: przekazując parametry i licząc poziom zagnieżdżenia ścieżkami. Wypróbujmy oba.
W XSLT 2.0 można definiować własne funkcje, których następnie można używać w wyrażeniach XPath arkusza.
Funkcje definiuje się w elementach function
na głównym poziomie arkusza. Opcjonalny parametr
as
opisuje typ wyniku, opcjonalny parametr override
mówi czy chcemy nadpisać
ewnetualnie istniejącą definicję funkcji o takiej samej nazwie, liczbie parametrów i priorytecie (domyślnie tak).
Zawartość elementu function
jest taka jak szablonu: najpierw elementy param
określające parametry funkcji, a następnie konstruktory i instrukcje tworzące wynik funkcji.
Plik: silnia-fun.xsl.
<xsl:function name="loc:silnia"> <xsl:param name="n"/> <xsl:sequence select="if($n <= 1) then 1 else $n * loc:silnia($n - 1)"/> </xsl:function>
Napisz i przetestuj funkcję count-elems(name, node)
zwracającą liczbę wystąpień elementów o nazwie
name w poddrzewie o korzeniu node (łącznie z node).
Atrybut as
parametrów i zmiennych, a także funkcji (o czym w dalszej części zajęć) służy
do określania typu zmiennej parametru lub wyniku funkcji.
Zgodnie z modelem danych XPath 2.0, dopuszczalne są typy atomowe z XML Schema oraz kilka dodatkowych. Jednak wartością może być nie tylko wartość atomowa, ale także węzeł lub sekwencja wartości atomowych i węzłów. Do zapisywania takich skomplikowanych typów służy specjalna składnia.
Pozwala ona na zgrubne określenie długości sekwencji (0, 1, co najmniej 0 i co najmniej 1) oraz na określenie typu dla jej elementów (jednakowego dla wszystkich). Oto kilka przykładów:
xs:date
– pojedyncza wartość wbudowanego typu daty,xs:date?
– pojedyncza data lub sekwencja pusta,xs:date*
– sekwencja dowolnej liczby dat (także pusta),xs:date+
– niepusta sekwencja dat,node()
– dowolny węzeł,element()
– węzeł elementu (analogicznie dla attribute()
,
text()
, comment()
, processing-instruction()
, document-node()
),element(osoba)
– węzeł elementu osoba
,element(*, Osoba)
– węzeł elementu o dowolnej nazwie i typie Osoba
,item()+
– niepusta sekwencja dowolnych elementów (items,
nie elements :)).Do poprzedniej funkcji dodaj specyfikację typów argumentów i wyniku.
Przy okazji - to ilustracja skróconej składni dla arkuszy XSLT.
<table xsl:version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <tr> <th>Position</th> <th>Country</th> <th>City List</th> <th>Population</th> </tr> <xsl:for-each-group select="cities/city" group-by="@country"> <tr> <td><xsl:value-of select="position()"/></td> <td><xsl:value-of select="@country"/></td> <td> <xsl:value-of select="current-group()/@name" separator=", "/> </td> <td><xsl:value-of select="sum(current-group()/@pop)"/></td> </tr> </xsl:for-each-group> </table>
sklep2.xml – napisz arkusz, który wypisuje (po jednym razie) wszystkie kategorie i dla każdej kategorii średnią cenę oraz wszystkie towary z tej kategorii.
Wykonaj w wersji XSLT 2.0, używając konstrukcji for-each-group
. Można także spróbować w wersji 1.0.