!

Dette materialet blir ikke lenger vedlikeholdt. Du vil finne oppdatert materiale på siden: http://borres.hiof.no/wep/

template
Børre Stenseth
XSL > XSLT >Basis

Basis

Hva
Den grunnleggende anatomien i en XSL-transformasjon, stilsett, template

Alle transformasdjonene i denne modulen er fra XML til HTML. Transformasjonene gjøres "on-the-fly" når XML-fila lastes opp i nettleseren med en referanse til transformasjonen.

I modulene Olympiade finner du eksempler på transformasjoner fra XML til XML og fra XML til tekst i ulike formater.

Vi trenger noe råmateriale å arbeide med. Gjennomgangseksempelet i denne modulen vil være en bokliste som er bygget opp slik:

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE booklist SYSTEM "bokdok.dtd">
<?xml-stylesheet type="text/xsl" href="boktrans.xslt"?>
<booklist>
    <book isbn="" pages="">
        <title/>
        <course/>
        <category/>
        <author/>
        <publisher/>
        <year/>
        <comment/>
    </book>
    <!-- more books -->
</booklist>

I de tre første linjene angir vi:

  • at dette er en XML-fil og hvordan den er kodet
  • at fila er av en bestemt type. Vi har laget en DTD-fil og kan validere den. Dette er strengt tatt ikke nødvendig for de transformasjonsøvelsene vi skal gjøre.
  • at vi skal kople til en XSL-transformasjon. Navnet på XSL-fila vil endre seg etterhvert som vi skal gjøre ulike typer transformasjoner i det følgende.

Selve innholdet er en liste med bøker. Her kan du se et eksempel på en fil med litt innhold: page1/bok1.xml.

For enkelhets skyld skal vi holde oss til transformasjoner fra XML til HTML. Du vil finne mange eksempler på andre typer transformasjoner i dette materialet, blandt annet i eksempelet Olympiade . Vi transformerer til HTML for at vi kan inspisere resultatet direkte i en nettleser som kan transformere automatisk. Sørg for at du bruker en slik nettleser når du arbeider med disse eksemplene. Alternativt må du bruke en av verktøyene som er beskrevet i modulen Verktøy, f.eks. XMLSpy, og transformere før du ser på resultatet i en hvilken som helst nettleser som kan tolke den HTML-koden din transformasjon leverer.

Enkel liste

Vi skriver en minimal transformasjon som bare skriver ut en liste over alle boktitlene, uten noen form for formattering:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="html" 
   omit-xml-declaration="yes"
   indent="yes" 
   doctype-public="-//W3C//DTD XHTML 1.0 Strict//EN" 
   doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd" 
   encoding="utf-8"/>
  <xsl:template match="/">
    <html>
      <head>
        <title>liste</title>
      </head>
      <body>
        <h1>List of books</h1>
        <xsl:for-each select="booklist/book">
          <p>
            <xsl:value-of select="title"/>
          </p>
        </xsl:for-each>
      </body>
    </html>
  </xsl:template>
</xsl:stylesheet>

Boklista transformert med denne transformasjonen direkte i en nettleser:

page1/bok2.xml http://www.it.hiof.no/~borres/dw/xsl/page1/bok2.xml

Eller se det transformerte resultatet direkte:

page1/book_out2.html http://www.it.hiof.no/~borres/dw/xsl/page1/book_out2.html

Vi merker oss følgende:

  • XSL-fila er en XML-fil. Det vil si at XSL er et språk i XML-familien.
  • Vi definerer et namespace for XSLT, med kortnavnet xsl. Vi kan bruker xsl som prefix når vi skal angi elementer som er XSL-elementer.
  • Vi angir hva slags output vi ønsker, og hvordan den skal kodes.
  • Vi angir en template som skal knyttes til det øverste nivået i den xml-fila vi skal transformere. / angir rota i treet. Vi kan ha flere templates.

Inne i templaten gjenkjenner vi HTML-kode. Denne teksten genereres slik som den er i resultatet av transformasjonen. Det eneste vi bruker fra den XML-fila vi jobber på finner vi ved kodesegmentet

    
<xsl:for-each select="booklist/book">
      <p>
        <xsl:value-of select="title"/>
      </p>
</xsl:for-each>
	

Vi befinner oss i en template som er koplet til rota i XML-strukturen og vi angir at vi vil ha en løkke over de nodene som heter book og som er barn av booklist. Når vi så har kommet inn i selve løkka, kan vi etterpå si at vi skal ha tak i verdien, innholdt, i elementet title Dette rører ved noe av det som er sentralt i XSLT. Vi ser at uttrykket boolist/book minner om måten vi skriver deler av en filpath på. I XSL-terminologi har vi oppgitt en XPath. Du vil trolig oppleve at det som skaper mest hodebry i XSL er å finne riktige slike path-uttrykk for å "peke på" elementer som er barn, søsken eller foreldre til andre elementer. Vi må hele tid finne den pathen i forhold til det stedet vi befinner oss, konteksten eller contekst node.

Her er det slik at vi endrer contekst i for-løkka og kan derfor angi title direkte, uten noen kvalifiserende path.

Templates

Vi tar for oss det samme problemet som ovenfor, å skrive ut en liste av boktitler. Denne gangen formulerer vi oss litt annerledes. Vi lager en egen template for bokutskrift. Vi får altså en template i tillegg:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="html" 
     omit-xml-declaration="yes"
     indent="yes" 
     doctype-public="-//W3C//DTD XHTML 1.0 Strict//EN" 
     doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd" 
     encoding="utf-8"/>
      
<xsl:template match="/">
<html>
<head>
   <title>liste</title>
</head>
<body>
<h1>Booklist</h1>
<xsl:for-each select="booklist/book">
   <xsl:apply-templates select="self::node()"/>
</xsl:for-each>
</body>
</html>
</xsl:template>
 
<xsl:template match="book">
<p>
   <xsl:value-of select="title"/>
</p>
</xsl:template>
</xsl:stylesheet>

Boklista transformert med denne transformasjonen direkte i en nettleser:

page1/bok3.xml http://www.it.hiof.no/~borres/dw/xsl/page1/bok3.xml

Eller se det transformerte resultatet direkte:

page1/book_out3.html http://www.it.hiof.no/~borres/dw/xsl/page1/book_out3.html

Den nye templaten er laget for /booklist/book. Når vi går i løkka ber vi om å få anvendt templates som passer til den konteksten vi er i, self::node(). Vi kan erstatte self::node() med ., punktum, som kortform.

Se på alternativet nedenfor:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" 
     omit-xml-declaration="yes"
     indent="yes" 
     doctype-public="-//W3C//DTD XHTML 1.0 Strict//EN" 
     doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd" 
     encoding="utf-8"/>
      
<xsl:template match="/">
<html>
<head>
   <title>minimum</title>
</head>
<body>
   <xsl:apply-templates select="booklist/book"/>
</body>
</html>
</xsl:template>
 
<xsl:template match="//book">
   <p>
   <xsl:value-of select="title"/>
   </p>
</xsl:template>
</xsl:stylesheet>

Vi har droppet for-løkka og bestilt en template for booklist/book. Vi får en automatisk gjennomgang av alle bøker. Vi kan lese select="booklist/book" slik: "hent alle book-noder under booklist".

Vi har dessuten generalisert den andre templaten slik at den matcher bok. Det vil si alle boknoder uansett hvem de er barn av. I dette tilfellet gjør det ingen forskjell sidan vår struktur bare har en type bokelement.

Litt stil

Vi ser av eksemplene ovenfor at vi kan generere HTML etter ønske, i hvert fall så langt. Den HTML-koden vi lager gir ikke noe spesielt pent resultat og HTML-sidene er av ubestemt art. Vi ønsker å lage HTML 4 transitional og vi ønsker å kople til et stilsett. Vi gjør dette ved å endre transformasjonsfila slik at prologen i HTML-fila blir slik vi ønsker:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="html" 
     omit-xml-declaration="no"
     indent="yes" 
     doctype-public="-//W3C//DTD XHTML 1.0 Strict//EN" 
     doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd" 
     encoding="utf-8"/>
 
  <xsl:template match="/">
    <html>
      <head>
        <!-- link to stylesheet -->
        <link rel="STYLESHEET" href="bokstil.css"/>
        <title>bokliste</title>
      </head>
      <body>
        <h1>Liste over alle bøker</h1>
        <ul>
          <xsl:apply-templates select="booklist/book"/>
        </ul>
      </body>
    </html>
  </xsl:template>
    
  <xsl:template match="book">
    <li class="enkel_liste">
      <xsl:value-of select="title"/>
    </li>
  </xsl:template>
</xsl:stylesheet>

Boklista transformert med denne transformasjonen direkte i en nettleser:

page1/bok4.xml http://www.it.hiof.no/~borres/dw/xsl/page1/bok4.xml

Eller se det transformerte resultatet direkte:

page1/book_out4.html http://www.it.hiof.no/~borres/dw/xsl/page1/book_out4.html

Vi ser dessuten at vi har skrevet om slik at vi får en overskrift og en liste med en egen stil, enkel_liste.

Bedre liste

Vi beholder i hovedsak strukturen i den transformasjonen vi brukte over, men vi vil endre templaten for å skrive ut en bok slik at vi får ut mer informasjon om hver bok. Vi vil dessuten skrive ut mer informasjon i toppen av siden.

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="html" 
     omit-xml-declaration="yes"
     indent="yes" 
     doctype-public="-//W3C//DTD XHTML 1.0 Strict//EN" 
     doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd" 
     encoding="utf-8"/>
 
<xsl:template match="/">
<html>
<head>
<!-- link to stylesheet -->
<link rel="STYLESHEET" href="bokstil.css" />
<title>bokliste</title>
</head>
<body>
<h1>Liste over alle bøker</h1>
<xsl:apply-templates select="booklist/book"/>
</body>
</html>
</xsl:template>
 
<xsl:template match="book">
   <div class="booktitle"><xsl:value-of select="title"/></div>
   <div><xsl:value-of select="author"/></div>
   <div><xsl:value-of select="publisher"/>, 
   <xsl:value-of select="year"/></div>
   <div>Isbn: <xsl:value-of select="@isbn"/></div>
   <div class="kommentar"><xsl:value-of select="comment"/></div>
</xsl:template>
</xsl:stylesheet>

Boklista transformert med denne transformasjonen direkte i en nettleser:

page1/bok5.xml http://www.it.hiof.no/~borres/dw/xsl/page1/bok5.xml

Eller se det transformerte resultatet direkte:

page1/book_out5.html http://www.it.hiof.no/~borres/dw/xsl/page1/book_out5.html

Utvalgt liste

Vi ønsker å endre transformasjonen slik at vi bare får ut bøker som har kategori XML. Foruten at vi endrer overskriften, så endrer vi løkka som går gjennom bøkene slik:

   <xsl:apply-templates select="booklist/book[category='XML']"/>

Boklista transformert med denne transformasjonen direkte i en nettleser:

page1/bok6.xml http://www.it.hiof.no/~borres/dw/xsl/page1/bok6.xml

Eller se det transformerte resultatet direkte:

page1/book_out6.html http://www.it.hiof.no/~borres/dw/xsl/page1/book_out6.html

Her ser vi at vi har et litt mer komplisert XPath-uttrykk. Vi har lagt til [category='XML'] som spesifiserer et utvalg basert på de aktuelle nodenes verdier.

HTML 5

I alle eksemplene ovenfor finner du i XSLT-filene en setning som ser slik ut:

 
	<xsl:output method="html" 
	 omit-xml-declaration="yes"
	 indent="yes" 
	 doctype-public="-//W3C//DTD XHTML 1.0 Strict//EN" 
	 doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd" 
	 encoding="utf-8"/>
	 ...
	 
 

Det vi angir her er altså at vi skal lage HTML, og vi angir dokumenhttype og encoding. Vi sier dessuten at vi skal droppe XML-headeren. Dette er en grei måt å lage kontrollert HTML strict.

Dersom vi ønsker å lage HTML5, kan vi løse dette etter følgende mønster:

 
<xsl:stylesheet version="1.0" 
	xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" 
			omit-xml-declaration="yes" 
			indent="yes" />
<xsl:template match="/">
<xsl:text disable-output-escaping='yes'>&lt;!DOCTYPE html></xsl:text>
    <html>
	<head>	</head>
	<body>	</body>
	</html>
</xsl:template>

</xsl:stylesheet>

 

Vi gjentar det siste eksempelet overfor med følgende transformasjon:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" 
            omit-xml-declaration="yes" 
            indent="yes" />
<xsl:template match="/">
<xsl:text disable-output-escaping="yes">&lt;!DOCTYPE html></xsl:text>
 <html>
<head>
   <meta charset="UTF-8"/>    
    <link rel="STYLESHEET" href="bokstil.css" />
    <title>bokliste</title>
</head>
<body>
<h1>Liste over alle XML-bøker</h1>
<xsl:apply-templates select="booklist/book[category='XML']"/>
</body>
 </html>
</xsl:template>

<xsl:template match="book">
<div class="booktitle"><xsl:value-of select="title"/></div>
<div><xsl:value-of select="author"/></div>
<div><xsl:value-of select="publisher"/>, 
<xsl:value-of select="year"/></div>
<div>Isbn: <xsl:value-of select="@isbn"/></div>
<div class="kommentar"><xsl:value-of select="comment"/></div>
</xsl:template>
</xsl:stylesheet>

Boklista transformert med denne transformasjonen:

page1/book_out_html5.html http://www.it.hiof.no/~borres/dw/xsl/page1/book_out_html5.html
Referanser

Alle filene er referert i modulen

Vedlikehold
Børre Stenseth, oppdatert 2011.
( Velkommen ) XSL > XSLT >Basis ( XSLT på klienten )