Ćwiczenie 12: Transformacje XSL
Dołączanie dokumentu z transformacjami do pliku XML
<?xml-stylesheet type="text/xsl" href="nazwa pliku.xsl"?>
Budowa pliku XSL
XSL jest językiem opartym na składni XML
Definicja pliku XSL
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" >
…
Tu wstawiamy szablony (zob. dalej)
…
</xsl:stylesheet>
Tworzenie szablonów
Szablony są podstawowym elementem budulcowym transformat XSL. Deklaracja szablonu wygląda następująco:
<xsl:template match=”…”>
</xsl:template>
gdzie wartość atrybutu match może być np. (dopuszczalne są wyrażenia XPath):
match=”/” - wierzchołek drzewa dokumentu
match=”nazwa” - element o nazwie węzła =”nazwa”
match=”przodek/nazwa” - element o nazwie węzła =”nazwa” posiadający ojca o nazwie=”przodek”
match=”przodek//nazwa” - element o nazwie węzła =”nazwa” posiadający węzeł o nazwie=”przodek” gdziekolwiek nad sobą w strukturze dokumentu
match=”nazwa1 | nazwa 2 | nazwa3 …” -element pasujący do którejkolwiek z nazw
match=”nazwa-elementu[@nazwa-atrybutu=”wartość”]” - element o danej nazwie posiadający atrybut o danej nazwie i wartości=”wartość”.
match=”nazwa-elementu[@nazwa-atrybutu]” - element posiadający atrybut o danej nazwie
match=”nazwa-elementu[nazwa-elementu]” - element o danej nazwie posiadający dziecko o danej nazwie
match=”id(aaa)” -element o ID=”aaa”
► Zacznijmy od zbudowania prostej transformacji wyświetlającej prosty plik html wyświetlający tytuł dokumentu „Procesory z dnia: data” gdzie data będzie pobierana z pliku „procesory.xml”.
=> do pustego template-u w pliku procesory.xsl dopisz zawartość:
<xsl:template match="/">
<html>
<head>
<title>Procesory!!!</title>
</head>
<body>
<h1> <center>Cennik procesorow z dnia:
<xsl:value-of select="procesory/@data"/>
</center>
</h1>
</body>
</html>
</xsl:template>
► Aby obejrzeć wynik, podłącz plik ze stylami do pliku „procesory1.xml” i uruchom ten plik w IE.
=> wstaw wiersz <?xml-stylesheet type="text/xsl" href="procesory.xsl"?> do pliku „procesory.xml” Już tam jest - wystarczy go od-komentować.
=> uruchom IE i zaobserwuj zwróconą zawartość.
Przetwarzanie elementów
► Włącz przetwarzanie pozostałych elementów (w przypadku braku definicji elementu, użyte będzie standardowe przetwarzanie - jak możesz się przekonać, polega ono na wyprowadzeniu do pliku wynikowego samego tekstu zawartego w elemencie)
=> wstaw wiersz <xsl:apply-templates/> we wnętrzu elementu body (po kodzie tworzącym nagłówek „Cennik procesorów”).
=> uruchom IE i zaobserwuj zwróconą zawartość.
Co się stało? Otóż polecenie to spowodowało przetworzenie wszystkich elementów zawartych w elemencie głównym, próbując dopasować do nich jakiś szablon. Ponieważ dla elementu „procesor” nie mieliśmy żadnego szablonu, został zastosowany szablon domyślny, który do dokumentu wynikowego kopiuje cały surowy tekst zawarty w danych elementach.
<xsl:apply-templates/> pozwala na przetwarzanie wszystkich elementów, dla których zdefiniowane są wzorce. Aby w danym miejscu przetwarzać tylko wybrany rodzaj elementów należy użyć <xsl:apply-templates select=”scieżka do elementów”/>
np. <xsl:apply-templates select=”procesory/procesor”/>
► Dodaj własną obsługę elementów.
=> dodaj w szablonie głównym wywołanie:
<xsl:apply-templates select=”procesory/procesor”/>
=> dodaj do pliku z transformacjami (tj. do pliku procesory.xsl) następujące wiersze wprowadzające obsługę elementu o nazwie „typ”:
<xsl:template match="typ">
Procesor: <xsl:value-of select="."/>
<br/>
</xsl:template>
=> dodaj obsługę węzłów (mogą to być na razie puste wzorce) dla elementów „cena” oraz „link”
=> uruchom IE
► Dodaj wyświetlanie zawartości i atrybutów (hurtowa czy detaliczna) w szablonie dla elementów cena.
=> odwołanie do atrybutu poprzedzone jest znakiem @
<xsl:value-of select=”@rodzaj”/> wyświetla atrybut typ aktualnego węzła.
=> uruchom IE
►Wyświetl pogrupowane dane procesora (typ wraz z ceną i linkami).
=> Stwórz wzorzec dla elementu „procesor” i w nim zawrzyj obsługę elementów typ, cena i link w taki sposób, aby wyświetlane były one zawsze w tej samej kolejności (typ , potem cena potem link). Aby nie pozbywać się stworzonych wcześniej szablonów dla ceny i linku, możesz nie przenosić ich do wnętrza szablonu „procesor”, ale zamiast tego wywołać je z tego szablonu - np. <xsl:apply-templates select=”cena” />
=> jak poprzednio, niech wzorzec ten będzie z szablonu głównego uruchamiany poleceniem:
<xsl:apply-templates select=”procesory/procesor” />
►[Jeśli nie tworzyłeś osobnego szablonu dla elementów „cena”:] Dodaj obsługę wielu elementów typu cena (o ile jeszcze nie działa) - for-each iteruje po wszystkich elementach danego typu).
- wstaw w odpowiednie miejsce - przy elemencie procesor
<xsl:for-each select="./cena">
Cena (<xsl:value-of select="@typ"/>): <xsl:value-of select="."/> <br/>
</xsl:for-each>
►Dodaj warunkową obsługę linków.
zauważ, że nie każdy element „procesor” posiada element „link”. Jeżeli element „procesor” nie posiada elementu „link” należy wypisać stosowny komunikat. Użyj do tego tagów
<xsl:choose>
<xsl:when test=”warunek”>
</xsl:when>
<xsl:otherwise>
</xsl:otherwise>
</xsl:choose>
►Wprowadź sortowanie procesorów.
-posortuj elementy o nazwie „procesor” według typu. Zamień <xsl:apply-templates/>
<xsl:apply-templates select="procesory/procesor">
<xsl:sort select="typ"/>
</xsl:apply-templates>
Sortować można też elementy przetwarzane w pętli xsl:for-each.
►Wprowadź sortowanie cen - najpierw detaliczna potem hurtowa.
►Wprowadź numerowanie procesorów.
-użyj elementu <xsl:number value="pozycja" format="1. "/> aby wprowadzić numerowanie elementów. Należy wstawić to w szablon dla elementów „procesor”. Do aktualnej pozycji można odwołać się poprzez metodę „position()”
Formatowanie liczb
W celu sformatowania liczb należy określić właściwości formatowania (jaki znak rozdziela tysiące itp.). Używa się do tego deklaracji globalnej <xsl:decimal-format> (umieść ją nad głównym szablonem):
<xsl:decimal-format grouping-separator=" " name="polskie"/>
Formatowanie odbywa się poprzez wywołanie operacji format-number(co formatujemy,'wzorzec liczby','opcjonalnie nazwa formatu dziesiętnego')
Np.
<xsl:value-of select="format-number (current(),'### ### ###.00 zl','polskie')"/>
W celu dokładnego zapoznania się z dostępnymi formatami wejdź na stronę:
►Sformatuj sposób wyświetlania ceny.
►Zmodyfikuj wzorzec w ten sposób, aby wyświetlane w zestawieniu były tylko procesory Intel (użyj funkcji operującej na łańcuch tekstowym, umieszczając ją jako predykat [czyli w nawiasach kwadratowych] wyrażenia ścieżkowego selekcjonującego procesory).
► Pozostałe zadania (opcjonalne):
Stwórz plik xsl dla pliku sasiedzi.xml wyświetlający następujące informacje:
Ponumerowaną listę państw posortowanych według liczby mieszkańców
W ramach każdego państwa : nazwę, stolicę, obszar, ludność
Główne miasto i główne rzeki (tylko w przypadku, gdy istnieją), jeżeli nie ma głównych rzek należy wypisać odpowiednią informację
Na końcu sumaryczną liczbę mieszkańców oraz sumaryczny obszar:
Użyj operacji sum podając jako argument węzły, których zawartość chcesz sumować
Np.:
<xsl:value-of select="format-number(sum(procesory/procesor/cena),'### ###.00','polskie')"/>.
Użyteczne funkcje (z XPath)
Operacje na łańcuchach tekstowych:
concat(łańcuch1, łańcuch2, …)
contains(łańcuch, wzorzec)
normalize-space(łańcuch)
starts-with(łańcuch, wzorzec)
string-length(łańcuch)
substring(łańcuch, od, do),
substring-after(łańcuch, wzorzec),
substring-before(łańcuch, wzorzec), translate(łańcuch, stare, nowe),
string(…) => konwersja na string;
Operacje na liczbach:
ceiling(liczba), floor(liczba), round(liczba),
sum(zbiór_węzłów),
number(…) -> konwersja;
Operacje na wartościach logicznych:
false(), true(), not();
boolean(…) -> konwersja;
Operacje na węzłach:
count(zbiór_węzłów)
last()
position()
id(identyfikator) -> wyszukanie węzła według indentyfikatora;
local-name(element), name(element),
namespace-uri(element)
Składnia sortowania (z XSLT):
<xsl:sort select = wyrażenie-string
data-type = { "text" | "number" | Qname }
order = { "ascending" | "descending" }
case-order = { "upper-first" | "lower-first" } lang = { kod języka } />
Dodatkowe uwagi
Funkcja format-number może korzystać z nazwanej definicji formatu dziesiętnego (jej nazwa podawana jako trzeci, opcjonalny parametr), definiowanej następującym elementem:
<!-- Category: top-level-element -->
<xsl:decimal-format
name = qname
decimal-separator = char
grouping-separator = char
infinity = string
minus-sign = char
NaN = string
percent = char
per-mille = char
zero-digit = char
digit = char
pattern-separator = char />