Wprowadzenie do XSLT

Transkrypt

Wprowadzenie do XSLT
Wprowadzenie do XSLT
Tomasz Przechlewski
Spis treści
1.
2.
3.
4.
5.
6.
7.
8.
Struktura arkusza XSLT .................................................................................
Działanie arkusza XSLT ..................................................................................
Polecenia języka XSLT ....................................................................................
Zmienne ..........................................................................................................
Tworzenie dokumentu wynikowego ................................................................
Wbudowane funkcje .......................................................................................
Przykłady ........................................................................................................
Dokumentacja/oprogramowanie .....................................................................
1
2
3
5
5
6
7
9
1. Struktura arkusza XSLT
XSLT (XSL Transformations) to język służący do transformacji XML-XML. Procesor
XSLT zamienia wejściowy dokument XML (source tree) na podstawie arkusza XSLT
tworząc wynikowy dokument XML (result tree).
Arkusz (stylesheet) składa się z szablonów (templates). Każdy szablon opisuje jak należy przekształcić fragment dokumentu wejściowego na fragment dokumentu wyjściowego. Wykonanie transformacji polega na wywołaniu (instantiate) szablonu pasującego (match) do elementu głównego.
Cały arkusz zawarty jest wewnątrz elementu stylesheet; elementami-dziećmi stylesheet mogą być wyłącznie tzw. polecenia najwyższego poziomu (top-level): template, output, include, import oraz param i variable.
<?xml version="1.0" encoding="iso-8859-2" ?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:import href="tpext.xsl" /> <!-- niższy priorytet -->
<xsl:include href="tpdef.xsl" />
<!-- top level elements: -->
<xsl:output
method = { "xml" | "html" | "text" | "QName" }
encoding = "iso-8859-2"
doctype-public="-//W3C//DTD HTML 4.01 Transitional//EN"
doctype-system="..."
indent={"yes" | "no"}
saxon:character-representation="native:decimal"
xmlns:saxon="http://icl.com/saxon" />
<xsl:template
name="QName" match="Pattern" mode="QName" priority="Number">
1
Wprowadzenie do XSLT
<xsl:param>*
...
</xsl:template>
<xsl:variable name="QName" select="Expression"> ... </xsl:variable>
<xsl:param name="QName" select="Expression"> ... </xsl:param>
<xsl:key name="QName" match="Pattern" use="Expression" />
W powyższym zapisie QName oznacza qualified name (nazwę kwalifikowaną, tj. nazwa lokalna poprzedzona prefiksem zakończonym dwukropkiem). Zamiast stylesheet można użyć elementu transform.
Treść szablonu jest wyrażeniem opisującym zawartość dokumentu wynikowego. Wynikiem transformacji jest dokument XML. Standard (XSLT 1.0) określa trzy sposoby
serializacji (zapisania jako tekstu) wynikowych dokumentów: xml, text, html.
Wszystkie pozostałe polecenia XSLT (XSLT instructions) muszą być zawarte wewnątrz elementów top-level.
Tryby przetwarzania (modes) pozwalają na przetwarzanie tego samego węzła wielokrotnie. Podczas przetwarzania zawsze obowiązuje jeden tryb bieżący, który może
się zmieniać przy wywołaniach apply-templates. Por. przykład poniżej.
Szablony nazwane. Szablon może posiadać nazwę podaną jako wartość atrybutu
name. Taki szablon można wywołać za pomocą instrukcji call-template (pełna analogia do deklarowania/uruchamiania funkcji w językach proceduralnych). Szablon
musi posiadać co najmniej jeden z atrybutów match lub/i name, może posiadać oba.
Polecenia include i import różnią się priorytetem: deklaracje oraz szablony arkusza
importującego mają piorytet nad deklaracjami/szablonami arkusza importowanego.
2. Działanie arkusza XSLT
Wywoływanie szablonów może być wykonywane na dwa sposoby:
<!-- XSLT instructions: -->
<xsl:apply-templates select="Expression" mode="QName" >
( <xsl:with-param> | <xsl:sort> ) *
</xsl:apply-templates>
<xsl:call-template name="QName" >
<xsl:with-param> *
</xsl:call-template>
<xsl:with-param name="QName" select="Expression"> ... </xsl:with-param>
Polecenie <apply-templates select="Expression"/> powoduje obliczenie wartości wyrażenie, przy czym wynikiem musi być zbiór węzłów (node-set). Dla każdego węzła ze zbioru następuje: 1. dopasowanie szablonu najlepiej pasującego do wę2
Wprowadzenie do XSLT
zła. 2. wykonanie dopasowanego szablonu z węzłem ze zbioru-węzłów jako węzłem
bieżącym. 3. wstawienie do wynikowego drzewa wynikowego (aka dokumentu wynikowego).
Instrukcja <call-template name="nazwa"/>, umożliwia wywołanie szablonów nazwanych (named templates). W tym przypadku węzeł bieżący się nie zmienia.
Atrybut match w elemencie template określa do jakich węzłów szablon zostanie
zastosowany. Jego wartością musi być wzorzec (pattern). Wzorzec jest podzbiorem
wyrażenia ścieżkowego języka XPath, tj. każdy wzorzec jest poprawnym wyrażeniem
XPath ale odwrotnie nie jest prawdziwe.
Kiedy wykonywany jest szablon dla węzła, to węzeł staje się węzłem bieżącym (current node). Instrukcje, które zmieniają węzeł bieżący to: apply-templates i foreach. W wyrażeniach XPath funkcja current() zwraca węzeł bieżący.
W wyrażeniach XPath wyrażenia ścieżkowe są obliczane względem węzła kontekstowego (context node). Mówiąc precyzyjniej: każdy krok wyrażenia ścieżkowego
wyznacza zbiór-węzłów względem węzła kontekstowego. Każdy węzeł w tym zbiorze jest węzłem kontekstowym dla wyznaczenia zbioru węzłów w następnym kroku.
Innymi słowy węzeł kontekstowy jest równy węzłowi bieżącemu na początku obliczania wyrażenia ścieżkowego XPath, a dalej -- w miarę przechodzenia kolejnych
kroków ścieżki XPath -- zmienia się. Węzeł kontekstowy jest oznaczany kropką . (co
jest skrótem od self::node())
3. Polecenia języka XSLT
Do tworzenia poszczególnych węzłów dokumentu wynikowego służą odpowiednie
następujące szablonu:
<xsl:value-of select="Expression" />
<xsl:attribute name="QName">...</xsl:attribute>
<xsl:comment> ... </xsl:comment>
<xsl:element name="QName"> ... </xsl:element>
<xsl:text> ... </xsl:text>
<xsl:copy> ... </xsl:copy>
<xsl:copy-of select='Expression'> ... </xsl:copy-of>
Polecenie value-of oblicza wartość wyrażenia a następnie konwertuje tą wartość
do napisu i wypisuje do drzewa wynikowego (jako węzeł tekstowy). Zasady konwersji są identyczne jak zaimplementowane w funkcji string() języka XPath. Jeżeli obliczoną wartością jest zbiór węzłów, to wszystkie węzły za wyjątkiem pierwszego
(w porządku dokumentu) są ignorowane. Dla pliku z przykładu Sekcja 7, „Przykłady” :
3
Wprowadzenie do XSLT
<value-of select='//name' /> <!-- wypisze tylko pierwszą nazwę -->
<value-of select='/zestawienie/@rok' /> <!-- wypisze 2003
-->
Atrybuty elementów XSLT, których wartości są wyrażeniami XPath zaznaczono podając jako wartość atrybutu słowo Expression. W przypadku pozostałych atrybutów
można wstawić wyrażenie XPath używając notacji {Expression} (nazywa się to attribute value template). Takie wyrażenie jest obliczane w wynik zamieniany na napis
i wstawiany do drzewa wynikowego. (Por. Sekcja 7, „Przykłady” ):
<template match='czesc'>
<img src='{@zdjecie}' alt='{nazwa}'/>
</template>
Polecenie copy kopiuje węzeł bieżący z drzewa źródłowego do drzewa wynikowego. Kopiowanie jest powierzchowne (shallow copy) tj. nie są kopiowane elementy
potomne ani atrybuty; aby skopiować wszystkie węzły potomne należy albo użyć
copy-of (kopiuje zbiór-węzłów) albo trzeba posłużyć się następujących szablonem:
<xsl:template match='@*|node()' mode='copy'/>
<xsl:copy>
<xsl:apply-templates select='@*' mode='copy'/>
<xsl:apply-templates mode='copy'/>
</xsl:copy>
<xsl:template>
W szczególności powyższy przykład pozwala zgrabie rozwiązać problem pn. skopiuj
cały dokument XML za wyjątkiem ...
Polecenia sterujące (if, choose, for-each). Pętla for-each iteruje po zbiorze węzłów określonym za pomocą atrybutu select. W każej iteracji kolejny węzeł ze zbioru staje się węzłem bieżącym. Jeśli pierwszymi podelementami for-each będą sort,
elementy zbioru-węzłów zostaną posortowane.
<xsl:if test="Expression"> ... </xsl:if>
<xsl:choose>
<xsl:when test='Expression'>+
<xsl:otherwise>?
</xsl:choose>
<xsl:for-each select="Expression">
<xsl:sort select='Expression' ... >*
</xsl:for-each>
<xsl:sort select="Expression" order= {"ascending" | "descending" }
data-type={ "text" | "number" | "QName" } />
4
Wprowadzenie do XSLT
4. Zmienne
Zmienne w XSLT są deklaratywne (jak w programowaniu funkcyjnym): po przypisaniu wartości zmiennym nie mogą być one zmienione. W rezultacie zmienne w XSLT
przypominają bardziej stałe z proceduralnych języków programowania. Zmienne zadeklarowane za pomocą variable/param mogą być wykorzystanie w wyrażeniach
XPath; należy nazwę zmiennej poprzedzić znakiem $, np. $czesci.
Deklaracja zmiennej lokalnej może wystąpić wewnątrz szablonów (wszędzie tam,
gdzie mogą występować inne instrukcje XSLT). Zmienna jest widoczna do końca
elementu, w którym została zadeklarowana. Zmienne globalne deklarowane są jako
polecenia top-level. Zmienna globalna jest widoczna we wszystkich szablonach oraz
deklaracjach innych zmiennych globalnych.
Wartość zmiennej i/lub parametru można podać na dwa sposoby: 1. poprzez wyrażenie XPath w atrybucie select, wówczas przypisywana jest obliczona wartość wyrażenia; 2. poprzez zawartość elementu variable, która jest interpretowana tak jak
fragment szablonu; wynik tej interpretacji jest przypisywany jako wartość zmiennej
(jako węzeł z ewentualnym węzłami potomnymi).
W XSLT 1.0 istnieje różnica między wartością wyrażenia z atrybutu select a wartością uzyskaną w wyniku interpretacji zawartości 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 i ten typ danych zniknął już w wersji 1.1 XSLT
jako niepotrzebna komplikacja.
Parametry arkusza (globalne) są zadeklarowane w elementach param na głównym
poziomie arkusza. Elementy param umieszczonych na początku szablonu są parametrami szablonu. 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 wraz z parametrami są odpowiednikiem funkcji w proceduralnych językach programowania.
5. Tworzenie dokumentu wynikowego
Polecenie document tworzy nowe drzewo wynikowe, które zostanie zapisane do odrębnego pliku. Pozwala to na zapisanie dokumentu wynikowego do wielu plików.
Polecenie document zostało wprowadzone w wersji 1.1 standardu XSLT.
<xsl:document href='URI' <!-- nazwa pliku -->
method='xml|html|text|Qname' <!-- znaczenie jak w elemencie output -->
encoding='String' <!-- kodowanie pliku -->
doctype-public = "..."
doctype-system = "..."/>
Przy serializacji XML i XHTML procesor XSLT zapisuje czasami do dokumentu wynikowego zbędne deklaracje przestrzeni nazw. Aby tego uniknąć, można wykorzystać
atrybut exclude-result-prefixes. W atrybucie tym można umieścić: listę rozdzielonych spacjami prefiksów (związanych z przestrzeniami nazw, które mają być pominięte), dodatkowo na liście może znajdować się napis #default odnoszący się do
5
Wprowadzenie do XSLT
domyślnej w danym miejscu przestrzeni nazw. Atrybut exclude-result-prefixes
może wystąpić: -- w każdym elemencie XSLT, bez prefiksu xsl, -- w każdym elemencie wynikowym, z prefiksem xsl (lub innym wskazującym na przestrzeń nazw XSLT).
Wyłączenie przestrzeni nazw obowiązuje w całym poddrzewie elementu w którym
występuje atrybut exclude-result-prefixes. To rozwiązanie nie gwarantuje, że
deklaracja przestrzeni nazw nie pojawi się w wyniku. W szczególności deklaracja
pojawi się, jeżeli jakiś element lub atrybut wyniku należy do danej przestrzeni nazw.
6. Wbudowane funkcje
XSLT rozszerza o kilka nowych zestaw funkcji dostępnych w wyrażeniach XPath:
current()
zwraca węzeł bieżący (opisane wyżej).
document(URI), document(URI, base-uri)
Dokument wskazany przez URI jest parsowany; zwracany jest węzeł-korzeń (root node) tego dokumentu. Argument URI nie musi być napisem, może być zbiorem węzłów (w tym przypadku nastąpi konwersja, szczegółowo opisana w specyfikacji). Gdy zbiór węzłów sprowadza się do pojedynczego węzła, np.: document
(@href), to działanie funkcji polega na zwróceniu węzła głównego dokumentu
określonego przez wartość atrybutu @href.
Jeżeli URI zawiera adres względny to jest on interpretowany względem dokumentu zawierającego go (tzn. jeżeli URI jest w arkuszu to wzlędem arkusza; jeżeli jest w dokumencie źródłowym, to względem dokumentu źródłowego). Drugi
argument funkcji pozwala zmienić domyślny adres bazowy. Ten drugi argument
także może być zbiorem węzłów. Jeżeli tak jest, to adresem bazowym będzie
URI dokumentu, z którego wybrano zbiór węzłów. Przykład: document("@href",
"/") -- jako adres bazowy przyjmie URI dokumentu źródłowego (bo / oznacza
korzeń dokumentu źródłowego dokumentu).
Często używany zapis document() oznacza URI arkusza XSLT.
generate-id(Node-set?)
zwraca napis jednoznacznie identyfikujący węzeł (mówiąc precyzyjniej zwraca
xs:Name). Jeżeli nie podano Node-set domyślną wartością jest węzeł kontekstowy. Funkcja umożliwia tworzenie wszelkiej maści odsyłaczy. Przykładowo załóżmy, że dokument XML zawiera elementy title zawierający tytuł punktu, wówczas:
<xsl:template match='title' mod='toc'>
<!-- formatuje tytuł punktu w spisie treści: -->
<div class='toc.item' ><a href='{#generate-id()}'>
<xsl-value-of select='.'/></a></div>
</xsl:template>
<!-- . . . . -->
<xsl:template match='title' >
<!-- formatuje tytuł punktu w treści dokumentu: -->
<h3 id='{generate-id()}'> <xsl-value-of select='.'/> </h3>
6
Wprowadzenie do XSLT
</xsl:template>
Atrybut mode, co pozwala na dwukrotne przetworzenie dokumentu. Zwróć też
uwagę na użycie notacji { ... } (attribute value templates)
7. Przykłady
Plik ramy.xml ma następującą prostą strukturę:
<zestawienie rok="2003">
<czesc id="m1201" typ="rama" zdjecie='gx2_carbon.jpg'>
<nazwa>GX2 Carbon</nazwa>
<firma>Merckx</firma>
<cena>3300</cena>
<sprzedaz>2</sprzedaz>
</czesc>
<czesc id="m2345" typ="rama" zdjecie='merckx_teamsc.jpg'>
<nazwa>Team SC</nazwa>
<firma>Merckx</firma>
<cena>2150</cena>
<sprzedaz>2</sprzedaz>
</czesc>
...
</zestawienie>
Bardzo prosty arkusz: wykorzystywane jest tylko polecenia xsl:template,
xsl:value-of oraz xsl:apply-templates Wypisanie zawartosci pliku ramy.xml w
postaci tabelki:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:output method="html"
encoding="iso-8859-2"
doctype-public="-//W3C//DTD HTML 4.01 Transitional//EN"
indent="yes" />
<xsl:template match="/">
<html>
<head> <title>Przykład 1</title> </head>
<body bgcolor="#FFFFFF">
<xsl:apply-templates/>
</body>
</html>
</xsl:template>
<xsl:template match="zestawienie">
<table>
<thead>
<tr><td>Id</td><td>Nazwa</td><td>Firma</td><td>USD</td></tr>
</thead>
7
Wprowadzenie do XSLT
<tbody>
<xsl:apply-templates/>
</tbody>
</table>
</xsl:template>
<xsl:template match="czesc">
<tr>
<td><xsl:value-of select="@id"/></td>
<td><xsl:value-of select="nazwa"/></td>
<td><xsl:value-of select="firma"/></td>
<td><xsl:value-of select="cena"/></td>
</tr>
</xsl:template>
</xsl:stylesheet>
Znajduje ramy droższe od 2000, wypisuje w porzadku od najdroższej do najtańszej:
<?xml version="1.0" encoding="iso-8859-2"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:output method="text" encoding="iso-8859-2" />
<xsl:template match="zestawienie">
<xsl:for-each select="//czesc[@typ='rama'][./cena &gt; 2000]">
<xsl:sort select="./cena" data-type="number" order='descending'/>
<xsl:value-of select="./nazwa"/>
<xsl:text> </xsl:text>
<xsl:value-of select="./firma"/>
<xsl:text> : </xsl:text>
<xsl:value-of select="./cena"/>
<xsl:text>&#10;</xsl:text>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
Ile sprzedano ram firmy $firma?:
<?xml version="1.0" encoding="iso-8859-2"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:output method="text" encoding="iso-8859-2" />
<xsl:param name="firma" select="Colnago"/> <!-- źle -->
<xsl:variable name="obrot"
select="sum(//czesc[@typ='rama'][./firma=$firma]/sprzedaz)" />
<xsl:template match='/'>
<xsl:text>Sprzedano: </xsl:text>
<xsl:value-of select="$obrot" />
8
Wprowadzenie do XSLT
<xsl:text> ram firmy: </xsl:text>
<xsl:value-of select="$firma" />
<xsl:text>&#10;</xsl:text>
</xsl:template>
</xsl:stylesheet>
8. Dokumentacja/oprogramowanie
• James Clark: XSL Transformations (XSLT), W3C Recommendation, 16 November 1999 http://www.w3.org/TR/xslt/
• James Clark, Steve DeRose: XML Path Language (XPath), W3C Recommendation,
16 November 1999 http://www.w3.org/TR/xpath/
• Michael
Kay:
SAXON
saxon.sourceforge.net/.
The
XSLT
and
XQuery
Processor
http://
• Daniel Veillard: The XML C parser and toolkit of Gnome http://xmlsoft.org/.
Ten dokument w formacie: pdf [./xml-xslt.pdf] oraz xml [./xml-xslt.xml].
9