XML – ćwiczenia 9: XSLT (1)

Wprowadzenie

Extensible Stylesheet Language to sposób prezentacji dokumentów XML oparty o transformacje dokumentów. Arkusz określa sposób zamiany dokumentu XML na inny dokument XML, dla którego określony jest już sposób prezentacji. Zgodnie z ideą standardu XSL, dokumentem wyjściowym powinien być dokument XSL Formatting Objects, ale w praktyce najczęściej dokonuje się transformacji do (X)HTML.

XSL Transformations to język (zastosowanie XML) służący do pisania arkuszy dokonujących transformacji XML → XML. Procesor XSLT to aplikacja, która potrafi interpretować XSLT i mając dane wejściowy dokument XML oraz arkusz XSLT potrafi wygenerować wynikowy dokument XML.

Zastosowania XSLT są znacznie szersze niż wizualizacja XML. Jest to doskonałe narzędzie do przepisywania dokumentów XML z jednego formatu do innego, do wyciągania danych z dokumentów, do przepisywania dokumentów do innych niż XML formatów. Wiele funkcjonalności pokrywa się z XQuery.

Narzędzia

XML Spy

Podczas ćwiczeń w labie najwygodniej korzystać z XML Spy.

Należy napisać lub otworzyć arkusz XSLT, a następnie wcisnąć przycisk "XSL". Aplikacja poprosi o wskazanie dokumentu źródłowego. Alternatywnie można wykonać przekształcenie dla otwartego dokumentu i wskazać arkusz.

Saxon

Saxon to procesor XSLT i XQuery dla Javy i .NET. Obsługuje standardy XPath 2.0, XSLT 2.0, XQuery 1.0. Udostępnia zarówno prosty interfejs command-line, jaki i API (dla Javy zgodne z JAXP 1.3), dzięki któremu z procesorów można korzystać we własnych programach.

Oprogramowanie w podstawowej wersji jest otwarte. Wersja zaawansowana (ze wsparciem dla przetwarzania schema aware) jest komercyjna.

W ścieżce klas powinien występować plik saxon9.jar. Przykłady użycia interfejsu command-line:

  • Na początku ustaw ścieżkę klas, np.: export CLASSPATH=saxon9.jar. Można też za każdym razem podawać parametr -cp.
  • java net.sf.saxon.Transform dokument.xml arkusz.xsl – Przekształcenie dokumentu dokument.xml zgodnie z arkuszem arkusz.xsl. Wynik zostanie wypisany na standardowe wyjście.
  • java net.sf.saxon.Transform -o wynik.xml dokument.xml arkusz.xsl – Jak wyżej, ale wynik trafi do pliku wynik.xml.
  • java net.sf.saxon.Transform dokument.xml arkusz.xsl param=Wartosc – Przypisanie parametrowi param wartości napisowej Wartosc. Jeśli napis zawiera spacje lub podejrzane znaki, najlepiej ująć go w apostrofy.
  • java net.sf.saxon.Transform dokument.xml arkusz.xsl '!method=text' '!encoding=iso-8859-2' – Przekazywanie parametrów serializacji. Tu wynik zostanie zapisany jako tekst w kodowaniu iso-8859-2.

Xsltproc

Xsltproc to procesor XSLT napisany w C, oparty o bibliotekę Libxml. Na ogół jest dostępne w dystrybucjach Linuksa. Obsługiwany jest standard XSLT 1.0.

Xalan

Xalan to bardzo popularny procesor XSLT napisany w Javie. Obecnie obsługuje XSLT 1.0.

Przeglądarki internetowe

Przeglądarki internetowe rozpoznają instrukcję przetwarzania xml-stylesheet w dokumencie źródłowym i wykonują wskazane przekształcenie, a następnie wyświetlają wynik.

Zadanie 1.

Pobierz pliki: studenci.xml oraz studenci.xsl.

Wykonaj przekształcenie w wybranym przez siebie narzędziu.

Arkusz XSLT

Struktura arkusza

Przykład 1.

<!-- element główny: -->
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<!-- konfiguracja arkusza, globalne deklaracje: -->
  <xsl:output method="html" encoding="iso-8859-2" />
  <xsl:import href="inny_arkusz.xsl"/>
  <xsl:param name="css"/>

<!-- szablony: -->
  <xsl:template match="/">
    <html>
      <head><link rel="styesheet" type="text/css" href="{$css}"/></head>
      <body><xsl:apply-templates/></body>
    </html>
  </xsl:template>

  <xsl:template match="akapit">
    <p><xsl:value-of select="."/></p>
  </xsl:template>
</xsl:stylesheet>

Arkusz (stylesheet) składa się z szablonów (templates). Każdy szablon opisuje jak zamieniać pewien węzeł dokumentu wejściowego na fragment dokumentu wyjściowego. Wykonanie transformacji polega na wywołaniu szablonu pasującego do elementu głównego.

Poza szablonami arkusz może zawierać elementy takie jak (między innymi):

  • output – określa sposób serializacji dokumentu,
  • include – zaimportowanie innego arkusza („wklejenie” w miejscu odwołania),
  • import – zaimportowanie szablonów z innego arkusza z niższym priorytetem, musi występować na początku arkusza,
  • param, variable – globalne parametry i zmienne.

XSLT językiem deklaratywnym

Treść szablonu (tzw. konstruktor sekwencji) jest wyrażeniem opisującym zawartość dokumentu wynikowego. Nie ma tutaj imperatywnych poleceń modyfikujących stan, dlatego XSLT można uznać za język deklaratywny.

Serializacja

Wynikiem transformacji jest dokument XML. Standard określa cztery sposoby serializacji (zapisania jako tekstu) wynikowych dokumentów:

  • xml – zapisywany jest dokument XML,
  • text – wypisanie tylko węzłów tekstowych dokumentu, bez żadnych znaczników,
  • html – jeśli wynikiem drzewo dokumentu HTML, zostaje on zapisany jako HTML (jest poprawnie interpretowany przez stare przeglądarki),
  • xhtml – dostępny w XSLT 2.0, (niemal?) identyczny z xml.

Zadanie 2.

W przykładzie o studentach zmień metodę serializacji i wykonaj ponownie.

Kilka instrukcji XSLT

Sterowanie

XSLT dostarcza konstrukcji do pisania wyrażeń warukowych (if, choose) oraz iterowania po elementach sekwencji (for-each).

Wewnątrz for-each zmienia się węzeł bieżący. Jeśli pierwszymi podelementami for-each będą sort, elementy sekwencji zostaną posortowane.

Przykład 2.

<xsl:template match="rozdział">
  <xsl:if test="@tytuł">
    <h2>Tytuł: <xsl:value-of select="@tytuł"/></h2>
  </xsl:if>
  <xsl:apply-templates />
</xsl:template>
<xsl:template match="konto">
Saldo konta jest
  <xsl:choose>
  <xsl:when test="saldo &gt; 0">dodatnie</xsl:when>
  <xsl:when test="saldo &lt; 0">ujemne</xsl:when>
  <xsl:otherwise>równe zero</xsl:otherwise>
  </xsl:choose>.
</xsl:template>
<xsl:template match="pracownicy">
  <table>
    <xsl:for-each select="pracownik">
      <tr>
      	<td><xsl:value-of select="imię"/></td>
      	<td><xsl:value-of select="nazwisko"/></td>
      </tr>
    </xsl:for-each>
  </table>
</xsl:template>

Zadanie 3.

Przykład studenci: studenci.xml, studenci.xsl.

Niech arkusz wybiera tylko studentów z drugiej grupy.

Zadanie 4.

Wyświetlaj kursywą (<i>) nazwiska studentów, których status jest równy prosba.

Zadanie 5.

Wprowadź parametr określający numer grupy, z której studentów ma wybierać arkusz. Jeśli nie zostanie podany, mają być wybierani wszyscy.

Kopiowanie oraz wyrażenia XPath w XSLT

Aby wstawić do dokumentu wynikowego wartość wyrażenia XPath, można użyć instrukcji value-of (rzutuje wynik na tekst) lub copy-of (wstawia z poddrzewem), a w XSLT 2.0 także sequence.

copy-of różni się od sequence tym, że węzły w wyniku są tu kopiami węzłów z wyrażenia w select, tzn. nie są z nimi identyczne w sensie is (dotyczy to także całego poddrzewa). W sequence wstawiane są te same węzły.

Niektóre atrybuty elementów XSLT oczekują wartości będących wyrażeniami XPath. Są to np. select, test. W pozostałych atrybutach można wstawić wartość tekstową wyrażenia XPath pisząc (podobnie jak w XQuery) {wyrażenie}.

Przykład 3.

<xsl:for-each select="student">
  <p id="st{@nr-indeksu}">
    <xsl:value-of select="naz"/> <xsl:value-of select="imi"/>
  </p>
</xsl:for-each>

<xsl:template match="fragment_html">
  <xsl:copy-of select="node()"/>
</xsl:template>

Aby utworzyć węzeł taki sam jak węzeł bieżący, można użyć instrukcji copy. Domyślnie kopiowanie jest powierzchowne, aby skopiować również atrybuty i podelementy trzeba to zrobić "ręcznie" wewnątrz copy. Węzłem bieżącym może być nie tylko element, ale też np. atrybut, węzeł tekstowy.

Przykład 4.

<xsl:template match="*|@*"
<xsl:copy> <xsl:apply-templates select="child::node() | attribute::node()"/> </xsl:copy>
</xsl:template>

Zadanie 6.

Utwórz nowy arkusz – „filtr” tworzący dokument XML o takiej samej strukturze, ale wybierający tylko studentów z danej grupy (parametr) i sortujący ich według nazwisk.

Typowe zastosowanie – prezentacja dokumentów tekstowych

Jednym z typowych zastosowań XSLT jest przekształcanie dokumentów tekstowych zawierających znaczniki strukturalne i semantyczne do HTML lub innego formatu służącego prezentacji. W takim zastosowaniu arkusz jest zbudowany z wielu szablonów, zasadniczo po jednym dla każdego typu elementu w dokumencie źródłowym, a sterowanie przekształceniem odbywa się za pomocą instrukcji apply-templates. Mamy wtedy do czynienia z przekształceniem sterowanym strukturą dokumentu źródłowego.

Przykład 5.

...
<xsl:template match="definicja">
  <div class="definicja">
    <xsl:apply-templates/>
  </div>
</xsl:template>

<xsl:template match="pracownicy">
  <ul>
    <xsl:apply-templates/>
  </ul>
</xsl:template>

<xsl:template match="pracownik">
  <li><xsl:apply-templates/></li>
</xsl:template>
...

Wywoływanie szablonów

Instrukcja <apply-templates select="ścieżka"/> powoduje:

  1. obliczenie wartości ścieżki, wynikiem powinna być sekwencja węzłów,
  2. posortowanie sekwencji, jeśli wewnątrz apply-templates znajdują się elementy sort,
  3. dla każdego węzła z sekwencji:

    1. dopasowanie szablonu najlepiej pasującego do węzła,
    2. obliczenie dopasowanego szablonu z węzłem z sekwencji jako węzłem bieżącym,
    3. wstawienie do wynikowego drzewa wyniku tego obliczenia.

Istnieje także instrukcja <call-template name="nazwa"/>, pozwalająca na wywołanie szablonów nazwanych. W tym przypadku węzeł bieżący się nie zmienia.

Węzeł bieżący i węzeł kontekstowy

Kiedy obliczany jest szablon dla danego węzła, ten węzeł staje się węzłem bieżącym. Instrukcje, które zmieniają węzeł bieżący to: apply-templates i for-each. W wyrażeniach XPath można się do niego odwołać za pomocą funkcji current(), w każdym miejscu w ścieżce XPath current() ma tę samą wartość.

Węzeł kontekstowy na samym początku obliczania wyrażenia XPath jest równy węzłowi bieżącemu, a dalej w miarę przechodzenia kolejnych kroków ścieżki XPath zmienia się. W każdym miejscu można się do niego odwołać za pomocą kropki . (lub wyrażenia self::node()).

Na przykład, gdy aktualnie przetwarzanym elementem jest element <referencja numer="5"/>, to poniższe ścieżki oznaczają:

  • //section[position() = current()/@numer] – wszystkie elementy section, o pozycji równej atrybutowi numer węzła bieżącego (czyli 5),
  • //section[position() = ./@numer] – wszystkie elementy section, o pozycji równej swojemu atrybutowi numer.

Zadanie 7. Prezentacja dokumentów tekstowych

Napisz arkusz XSLT służący do prezentacji w formacie HTML dokumentów zawierających przepisy kulinarne. Przykładowy dokument to przepisy.xml.

Szczegółowe wymagania (sugeruję po kolei rozbudowywać arkusz o kolejne punkty i testować):

  1. Wynikiem przekształcenia ma być dokument HTML.
  2. Nazwa przepisu powinna być przedstawiona jako nagłówek h2.
  3. Składniki potrzebne do wykonania potrawy należy przedstawić jako listę punktowaną.
  4. Treść przepisu jako jeden akapit (p) tekstu.
  5. Wystąpienia składników w treści powinny być wyróżnione (element strong).
  6. Uwagi umieść w akapitach o klasie uwaga (<p class=”uwaga”>).
  7. Informację o liczbie porcji zamieszczoną w atrybucie porcje przepisu, jeśli podana, należy przedstawić na początku przepisu (pod tytułem) pisząc tekst: Przepis na X porcji.
  8. Informację o kaloryczności zamieszczoną w atrybucie kalorie przepisu, jeśli podana, należy przedstawić na końcu przepisu pisząc tekst: Kaloryczność jednej porcji: X kcal.
  9. Zamieść na początku lub końcu przepisu informację o autorze: imię, nazwisko i (jeśli jest) „klikalny” e-mail.
  10. Spis wszystkich przepisów na początku dokumentu (z odnośnikami do początków poszczególnych przepisów). Sugerowane rozwiązanie: szablon generujący h2 dodaje atrybut id o unikalnej wartości, szablon generujący spis treści (może być for-each) dodaje odnośnik do #id-przepisu.

Zobacz także


Valid XHTML 1.1Valid CSS