» direct naar zoek en menu

Tijdschrift voor webwerkers » Artikel #56

Introductie tot XSL-T - Het transformeren van XML

XSL (eXtensible Stylesheet Language) is de verzamelnaam voor een aantal specificaties van het W3C (World Wide Web Consortium). Allemaal hebben ze te maken hebben met het omzetten en visueel weergeven van XML documenten:

  1. XSL Transformations (XSL-T)
    Een taal om XML documenten te transformeren naar een ander XML formaat. Van XML naar XHTML bijvoorbeeld. XSL-T is het hoofdonderwerp van dit artikel. Een voorbeeld van zo’n transformatie zou kunnen zijn dat je een RSS feed neemt en die in een layout gooit.

  2. XML Path Language (XPath)
    XPath is een syntax die je kunt gebruiken om delen van een XML document aan te spreken. XSL-T gebruikt deze expressies om te beslissen welk stukje inhoud als volgende getoond moet worden.

  3. XSL Formatting Objects (XSL-FO)
    Wil je van XML naar een PDF document (Portable Data Format), dan kun je dat doen door je XML eerst om te zetten naar een ander XML document met zogenaamde formatting objects. Daarna kun je via een tool als FOP (Formatting Objects Processor) een PDF document genereren.

Waarom

Eerst en vooral: Waarom zou iemand nu een XML document willen transformeren? Hebben we niet genoeg aan CSS (Cascading Style Sheets)? Even vergelijken:

CSS is op zich heel simpel. Het enige dat je kunt doen is een tag aanduiden en er enkele eigenschappen van aanpassen.

.example {
	display: block;
	color: #000;
	background-color: #eee;
	padding: 5px;
	border: 2px solid #bbb;
}

XSL-T daarentegen biedt heel wat meer mogelijkheden:

Net als CSS kun je de presentatievorm wijzigen, zonder het originele XML-document te moeten aanpassen. Daarnaast kun je nog met de volgorde van de informatie spelen, bepaalde informatie volledig verbergen of meerdere keren weergeven. Je kunt zelfs nieuwe inhoud toevoegen.

Enkele voorbeelden van mogelijk gebruik:

  1. Een nieuwssite bewaart z’n artikels in XML formaat (of het CMS spuwt ze op die manier uit), en gebruikt per medium een XSL-T transformatie: eentje om een webversie te genereren, eentje voor een PDA-versie en eentje om een papieren versie te genereren.
  2. De uitvoer van een bepaalde webapplicatie moet dienen als invoer voor een andere, maar deze laatste verwacht een net–iets–anders XML formaat. Geen probleem met een XSL-T transformatie.

Genoeg theorie, tijd voor het echte werk nu...

Ons XML document

In dit artikel gebruiken we een eenvoudig XML-document om de basiswerking van XSL-T te illustreren. Laten we er van uitgaan dat Naar Voren beschikt over een XML-databank met informatie over alle reeds verschenen artikels. Een extract vind je hier: (bekijk volledig bestand)

<website>
  <titel>Naar Voren</titel>

   <inhoud>
     <artikel id="1">
       <titel>De eerste 9 seconden</titel>
       <auteur>Robert Jan Verkade</auteur>
       <abstract>Angst voor de onuitwisbare eerste 
         indruk? [...]</abstract>

     </artikel>
     <artikel id="2">
       <titel>We gaan van linkestein</titel>
       <auteur>Remco Sikkema</auteur>
       <abstract>Als je een beetje verder kijkt 
         dan je neus lang is,[...]</abstract>

     </artikel>
   </inhoud>
  <url>http://www.naarvoren.nl/</url>
</website>

Het belangrijkste wat je moet begrijpen bij het verstaan van XSL-T, is dat elk XML-document gezien kan worden als een boom. XSL-T zet de bronboom om in een doelboom. De bronboom die bij ons voorbeeld hoort zou er dan als volgt uitzien:

Invoerboom

Laten we vanuit onze XML databank de Naar Voren archiefpagina proberen na te bouwen. We willen dus een HTML document met ergens een tabel, die voor elk artikel een rij bevat. Een simplistische weergave van deze uitvoerboom hieronder:

Uitvoerboom (gedeeltelijk)

De transformatie

Allereerst geven we de volledige XSL-T transformatie die we zullen gebruiken (althans, het stuk waar XSL aan te pas komt). De XSL-elementen worden vet weergegeven. (bekijk volledige bestand)

<?xml version="1.0" encoding="iso-8859-1"?>
<xsl:stylesheet version="1.1" 
  XMLns:xsl="http://www.w3.org/1999/XSL/Transform" 
>

<xsl:template match="/website">
  <html>
  <head>
    <title><xsl:value-of select="titel" />

    archief</title>
    ...
  </head>
  <body>
    ...

    <table cellspacing="0" id="archief">

    <tr>

    <th id="kop1">nr.</th>
    <th id="kop2">titel & auteur</th>
    <th id="kop3">het gaat over...</th>

    </tr>
	
    <xsl:for-each select="inhoud/artikel">
    <xsl:sort order="descending"
    select="number(@id)" data-type="number" />
      <tr>
        <td headers="kop1">
          <strong><xsl:value-of
          select="@id" /></strong>

        </td>
        <td headers="kop2">
          <xsl:element name="a">
            <xsl:attribute name="href">
              /artikel/<xsl:value-of select="@id" />
            </xsl:attribute>

            <xsl:value-of select="titel" />
          </xsl:element>
          <br />
          <xsl:value-of select="auteur" />
        </td>
        <td headers="kop3">

          <xsl:value-of select="abstract" />
        </td>
      </tr>
    </xsl:for-each>

    </table>

    ...
  </body>

  </html>
</xsl:template>

</xsl:stylesheet>

Als je goed kijkt, merk je dat dit als het ware een skelet is voor de archiefpagina die we willen bereiken.

Namespaces

Bekijken we eerst het root-element van de transformatie:

<xsl:stylesheet version="1.1" 
  XMLns:xsl="http://www.w3.org/1999/XSL/Transform" 
>

De xmlns:xsl namespace declaratie is uiterst belangrijk. Het komt er op neer dat binnen het stylesheet document alle elementen waarvan de naam begint met de xsl: prefix gelinkt worden aan de URL http://www.w3.org/1999/XSL/Transform. De meeste XSL-T verwerkers weigeren actie als hier een andere URL wordt vermeld.

Het xsl:stylesheet element bevat de volledige logica van de stylesheet, net zoals een html element een volledige webpagina bevat.

Templates

Zo’n XSL stylesheet bestaat uit één of meerdere templates. Een template komt overeen met een deel van de invoerboom als het match attribuut voldoet.

<xsl:template match="/website">
...
</xsl:template>

Het match attribuut is in feite een XPath expressie. Via zo’n expressie kan je een of meer elementen aanduiden in een XML-boom. De syntax is zoals die van bestandssystemen: een slash (/) duidt een lager niveau aan. Enkele voorbeelden van expressies vind je hieronder:

XPath expressies kunnen dus heel krachtig zijn als het moet. Binnen XSL-T worden ze her en der gebruikt, zoals we verder zullen merken.

Terug naar het template nu. Wanneer XSL-T een document omzet, kiest het eerst de root-knoop van de bronboom, en gaat op zoek naar een geschikt template om het te behandelen. Tijdens het behandelen van een template kunnen andere templates opgeroepen worden (via xsl:apply-templates). De huidige knoop wordt dan de basis voor het kiezen van nieuwe templates. In ons voorbeeld zullen we het echter bij één template houden.

Wanneer een template wordt uitgevoerd, wordt z’n inhoud naar de uitvoer gekopieerd. Tenzij er xsl: elementen voorkomen, want dan komt XSLT terug in actie. In ons voorbeeld wordt de uitvoer een HTML pagina.

Invoegen van waarden uit XML

Invoegen van waarden uit het XML document gebeurt via <xsl:value-of select="..." />. Het select-attribuut is alweer een XPath expressie, en vertelt de XSL-T processor wat precies moet worden ingevoegd. Zo voegt het volgende voorbeeld de website-titel toe wanneer uitgevoerd in de context van het website element, of de titel van een artikel wanneer de context een artikel element is.

<xsl:value-of select="titel" />

Iteratie

Voor onze archieflijst moeten we itereren over alle artikels, en voor elk artikel een tabelrij uitvoeren. Voor de iteratie heeft XSL-T het xsl:for-each element klaar. We willen ook een andere volgorde dan in de XML versie (we willen het nieuwste artikel — met hoogste id — eerst zien). Hiervoor kunnen we xsl:sort gebruiken.

<xsl:for-each select="inhoud/artikel">
<xsl:sort order="descending" select="number(@id)"
data-type="number" />
  <tr>
    <td headers="kop1">
      <strong><xsl:value-of select="@id" /></strong>
    </td>

    <td headers="kop2">
      <xsl:element name="a">
        <xsl:attribute name="href">
          /artikel/<xsl:value-of select="@id" />
        </xsl:attribute>
        <xsl:value-of select="titel" />

      </xsl:element>
      <br />
      <xsl:value-of select="auteur" />
    </td>
    <td headers="kop3">
      <xsl:value-of select="abstract" />

    </td>
  </tr>
</xsl:for-each>

Het select attribuut bij het for-each element is opnieuw een XPath expressie. Ze geeft aan dat we over alle artikels willen itereren. Omdat de huidige knoop /website is, zullen we dus alle /website/inhoud/artikel elementen overlopen. Het lichaam van het for-each element wordt herhaald voor elk zo’n element.

De xsl:sort instructie komt binnen de for-each terecht. We willen aflopend (descending) sorteren op het id-attribuut (@id) van de artikels. Het is ook noodzakelijk om number te vermelden als data-type, omdat anders alfabetisch gesorteerd wordt en ‘19’ voor ‘9’ zou komen.

Voor elk artikel plaatsen we een tabelrij met id, titel, auteur en abstract. Rond de titel plaatsen we een link. Dit gaat echter niet zo eenvoudig in XSL-T: volgend voorbeeld zou immers een XML parse error geven:

<a href="/artikel/<xsl:value-of select="@id">"></a>

Daarom moeten we werken via de xsl:element en xsl:attribute elementen.

Transformatie Toepassen

We hebben nu een XML document en een transformatie. Nu rest ons alleen nog de transformatie uit te voeren.

  1. Een eerste mogelijkheid is de transformatie door de webbrowser te laten uitvoeren. Moderne browsers zoals Mozilla-varianten en Internet Explorer hebben immers een XSL-T processor aan boord. Je hoeft enkel een regel toe te voegen bovenaan het XML document:

    <?xml-stylesheet type="text/xsl"
    href="archief.xsl" ?>

    Nadelig aan deze methode is dat je slechts één stylesheet aan een XML document kan koppelen, en dat de client de ruwe inhoud van het XML document kan bekijken.

    Ons voorbeeld van hierboven, met zo’n instructie: naarvoren-browser.xml

  2. Manueel omzetten kan met Instant Saxon van Michael Kay. Vanuit de command line kan je als volgt transformeren:

    saxon -o artikel/ naarvoren.xml archief.xsl
  3. Vanuit een programmeertaal is het al helemaal geen probleem. Er zijn tal van libraries beschikbaar en heel wat talen komen tegenwoordig met ingebouwde XSL-T ondersteuning. Voor Java is er bijvoorbeeld de Xalan processor, en PHP beschikt over een stel xslt_ functies

Resultaat

Het resultaat van de transformatie uit ons voorbeeld kan je zien op deze pagina (naarvoren.xml + archief.xsl).
let op: de in het voorbeeld gebruikte links leiden niet naar de juiste pagina, ze dienen slechts als voorbeeld.

Dit voorbeeld illustreerde slechts enkele van de mogelijkheden van XSL-T. Er is echter meer mogelijk. Veel meer. Voor de lezer die wat meer wil is er een alternatieve stylesheet beschikbaar die de artikels groepeert per auteur. Resultaat daarvan vind je hier.

Meer lezen?

Referenties

Auteur

Wouter Demuynck

is in het dagelijkse leven software-ontwikkelaar. Sinds begin 2000 houdt hij het weblog Karma Universe bij.

Verder ontwikkelt hij in z’n vrije tijd ook nog Nucleus

Publicatiedatum: 03 september 2003

Let op

Naar Voren is op 18 juli 2010 gestopt met publiceren. De artikelen staan als een soort archief online. Het kan dus zijn dat de informatie verouderd is en dat er inmiddels veel betere of makkelijkere manieren zijn om je doel te bereiken.

Copyright © 2002-heden » NAAR VOREN en de auteurs