Transcript Document

XSLT – en introduktion
Elektronisk publicering
[email protected]
Idag
•
•
•
•
•
•
Vad är XSLT?
Hur fungerar XSLT?
XPath och noder
XSLT:s notation
Templates, repetitioner och villkor
TEI
XSL-språk
• XSLT
– Ett språk för att transformera XMLdokument
• X-PATH
– Ett språk för att navigera i XML-dokument
• XSL-FO
– Ett språk för att formatera XML-dokument
Vad är XSLT?
• Står för eXtensible Stylesheet Language
for Transformation
• Ett programmeringsspråk för att
transformera XML-dokument
• En W3C-standard
• XSLT transforms an XML sourcetree into an XML result-tree
Den röda tråden…
DATA
LOGIK
GRÄNSSNITT
XML
XSLT
XHTML(+CSS)
XML, XSLT, XHTML och CSS
XML
XSLT
CSS
Omvandling
XHTML
Hur fungerar XSLT?
<?xml version="1.0" encoding="iso8859-1"?>
<!DOCTYPE boksamling SYSTEM
"boksamling.dtd">
<?xml-stylesheet type="text/xsl"
href="boksamling.xsl"?>
<boksamling>
<bok/>
</boksamling>
En post i XML-filen
<bok>
<forfattare>
<fNamn>Sue</fNamn>
<eNamn>Grafton</eNamn>
</forfattare>
<titel>L som i laglös</titel>
<kategori>Deckare</kategori>
<pris valuta="gbp">20</pris>
</bok>
XSLT-kod
<?xml version="1.0" encoding="ISO-8859-1" ?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns="http://www.w3.org/1999/xhtml">
<xsl:output method="html" indent="yes"/>
<xsl:template match="/">
<xsl:apply-templates select="boksamling"/>
</xsl:template>
<xsl:template match="boksamling">
<xsl:apply-templates select="bok"/>
</xsl:template>
<xsl:template match="bok">
Författare: <xsl:value-of select="forfattare/fNamn"/>
<xsl:text> </xsl:text>
<xsl:value-of select="forfattare/eNamn"/><br />
Titel: <xsl:value-of select="titel"/><br />
Kategori: <xsl:value-of select="kategori"/><hr />
</xsl:template>
</xsl:stylesheet>
XPath
• Ett språk för att navigera i XMLdokument
• En syntax för att definiera delar av ett
XML-dokument
• En W3C-standard
• XSLT använder XPath för att navigera i
XML-dokument
XPath - noder
• XML-dokument behandlas som träd
bestående av noder
• Typer av noder
– Element
– Attributes
– Text
– Namespaces
– Processing instruction
– Comment <!-- kommentar -->
– Document node (dokumentets rotelement)
XPath - noder
<?xml version="1.0" encoding="iso-8859-1"?>
<boksamling>
Dokumentnod
<bok>
(rotelement)
<forfattare>
<fNamn>Sue</fNamn>
Elementnod
<eNamn>Grafton</eNamn>
</forfattare>
<titel>L som i laglös</titel>
<kategori>Deckare</kategori>
<pris valuta="gbp">20</pris>
</bok>
</boksamling>
Attributnod
Textnod
XPath – Relationer mellan noder
• Varje element och attribut har en och endast
en förälder
• Elementnoder har noll till många barn
• Noder med samma förälder kallas syskon
– Det första syskonet är äldst, det näst första är näst
äldst och så vidare…
• En förfader är en förälders förälder
• En ättling är ett barns barn
XPath – Peka ut noder
• Nodnamn – Pekar ut samtliga barn till noden
• / - Pekar ut från rotelementet
• // - Pekar ut noder i dokumentet från den
aktuella nod som matchar utpekningen
• . – Pekar ut aktuell nod
• .. – Pekar ut föräldern till aktuell nod
• @ - Pekar ut attribut
XPath – Peka ut noder
• boksamling – Pekar ut samtliga barn till noden
boksamling
• /boksamling – Pekar ut rotelementet boksamling
• boksamling/bok – Pekar ut alla bok-element som är
barn till boksamling
• //bok – pekar ut samtliga bok-element, oavsett var de
befinner sig i hierarkin
• boksamling//titel – Pekar ut samtliga titel-element
som är ättlingar till boksamling, oavsett var de
befinner sig i hierarkin
• //@currency – Pekar ut samtliga attributnoder med
namnet currency
Ser något bekant ut?
• Jämför med relativa url:er i HTML:
– ../start.htm
– img/bild.gif
– etc…
• ../ motsvarar ett steg upp i trädet
• nodnamn1/nodnamn2/ motsvarar två
steg ner i trädet
Exempel: template-anrop
<xsl:template match="boksamling">
<xsl:apply-templates
select="bok/forfattare/eNamn"/>
</xsl:template>
• Gör att vi är säkra på att rätt eNamn hämtas,
dvs det som är barn till forfattare som i sin
tur är barn till bok
En annan variant
<xsl:template match="boksamling">
<xsl:apply-templates
select="bok//eNamn"/>
</xsl:template>
• Gör att vi är säkra på att rätt eNamn
hämtas, dvs det som är ättling till bok
En tredje variant
<xsl:template match="boksamling">
<xsl:apply-templates
select="//forfattare/eNamn"/>
</xsl:template>
• Gör att vi är säkra på att rätt eNamn
hämtas, dvs det som är barn till
forfattare
En fjärde variant
<xsl:template match="boksamling">
<xsl:apply-templates
select="//eNamn"/>
</xsl:template>
• Fungerar om eNamn finns på endast en nivå
i trädet
• Skulle eNamn finnas på flera nivåer
förväxlar tolken noderna med varandra
• I receptexemplet tidigare har vi ju noden
namn på flera nivåer
Notera skillnaden:
<xsl:template match="receptsamling">
<xsl:apply-templates select="//namn"/>
</xsl:template>
<xsl:template match="receptsamling">
<xsl:apply-templates select="//recept/namn"/>
</xsl:template>
<xsl:template match="receptsamling">
<xsl:apply-templates
select="//ingrediens/namn"/>
</xsl:template>
Exempel
Exempel: anropat template
<xsl:template match="eNamn">
<xsl:value-of select="."/>
<xsl:value-of select="../fNamn"/>
<xsl:value-of select="../../titel"/>
<xsl:value-of select="../../kategori"/>
</xsl:template>
Pekar ut
aktuell nod
(eNamn)
Pekar ut eNamns
förälders (forfattare)
barn (fNamn)
(enkelt uttryckt:
eNamns syskon)
Pekar ut eNamns
förfäders barn
Operatorer
•
•
•
•
•
•
•
A=A
(A är ekvivalent med A)
A!=B
(A är inte ekvivalent med B)
A>B
(A är större än B)
A<C
(A är mindre än C)
A>=D (A är större än eller lika med D)
A<=E
(A är mindre än eller lika med E)
Ett uttryck av detta slaget är antingen sant
(true) eller falskt (false)
Operatorer
• A=A and B!=C
– Sant om och endast om A är ekvivalent med A och
B inte är ekvivalent med C
• A=A or B=C
– Sant om A är ekvivalent med A eller om B är
ekvivalent med C
– Om första påståendet är sant kollas inte fler
påståenden
• not (A=B)
– Sant om och endast om A inte är ekvivalent med B
Aritmetiska operatorer
•
•
•
•
•
+
*
div
mod
addition
subtraktion
multiplikation
division
modulus
5+2
7-2
8*3
6 div 3
9 mod 2
XSLT
• Förändra en icke presentabel fil till en
webbsida
• Formatera ett dokument till PDF eller
liknande
• Förändra en XML-vokabulär till en
annan
• Extrahera specifik information från ett
dokument och formatera på ett annat
sätt
XSLT
• Det vi ska beskriva (receptsamlingen)
kan ses som en linjär sekvens
• Det XML-kodade innehållet är mer likt
en databas
• Flera olika outputs är möjliga
Rendering av XML-innehåll
•
•
•
•
Kopiera element
Utesluta element
Flytta element
bland annat…
En receptsamling
<!ELEMENT receptsamling (recept*)>
<!ELEMENT recept (namn, ingrediens+)>
<!ATTLIST recept id CDATA "">
<!ELEMENT namn (#PCDATA)>
<!ELEMENT ingrediens (namn, kategori, mangd)>
<!ELEMENT namn (#PCDATA)>
<!ELEMENT kategori (#PCDATA)>
<!ELEMENT mangd (#PCDATA)>
<!ATTLIST mangd enhet CDATA "st">
XML-filen
Kopiera element
• Navigationssystem
• Till exempel kan alla namn-element
som är barn till recept kopieras och
placeras i en lista i början av texten
• Listans element kan sedan länkas till
respektive namn-element
• För kopiering kan for-each användas
med fördel
Exempel: kopiera element
<xsl:template match="receptsamling">
<div>
<ul id="index">
<xsl:for-each select="//recept/namn">
<li>
<a href="#{../@id}">
<xsl:value-of select="."/>
</a>
</li>
</xsl:for-each>
</ul>
<xsl:apply-templates/>
</div>
</xsl:template>
Matchande template
<xsl:template match="recept">
<h1 id="{@id}">
<a href="#">
<xsl:apply-templates
select="namn"/>
</a>
</h1>
</xsl:template>
• Länkar varje namn-element tillbaka till
index
Exempel
Utesluta element
• Vi kanske inte vill visa all info om ett
recept?
• Eller vi kanske inte vill visa alla recept?
• Om vi utesluter ett element utesluter vi
också dess barn och ättlingar
• Vi skulle t ex kunna utesluta ett element
vars id är lika med carb
Utesluta element, exempel
<xsl:template match="X-PATH-uttryck"/>
<xsl:template match="ingrediens"/>
<xsl:template
match="ingrediens[kategori='Grönsak'"]/>
<xsl:template match="recept[@id='carb']"/>
Utesluta element, exempel
<ingrediens>
<namn>Vitlök</namn>
<kategori>Grönsak</kategori>
<mangd enhet="st">1-2
klyftor</mangd>
</ingrediens>
Exempel
Flytta element
• Template-anrop utförs i den ordning de
är skrivna i:
<xsl:apply-templates
select="mangd[@enhet]"/>
<xsl:apply-templates select="mangd"/>
<xsl:apply-templates select="kategori"/>
• Här kommer attributet enhet skrivas ut
först, sedan mangd och sist namn, t ex:
400 gram köttfärs
Sammanfattning: XSLT:s
notation
• Alla element i XSLT innehåller prefixet
xsl:
<xsl:choose>
</xsl:choose>
<xsl:sort select="name"/>
<xsl:value-of select="name"/>
Operatorer i XSLT skiljer sig
något från X-PATH
•
•
•
•
•
•
A=A
A!=B
8 &gt; 6
6 &lt; 8
A &gt;= B
B &lt;= A
A är ekvivalent med A
A är inte ekvivalent med B
8 är större än 6
6 är mindre än 8
A är större än eller lika med B
B är mindre än eller lika med A
Operatorer i XSLT
• AND, OR och AND…!
– pris &lt; 10 and kategori = 'Deckare’
– pris &lt; 10 or kategori = 'Deckare’
– pris &lt; 10 and kategori != 'Deckare’
Templates?
• Innehåller regler som appliceras vid
matchning av en specificerad nod
• Syntax:
<xsl:template name=”namn" match=”mönster"
mode=”form" priority=”siffra">
…
</xsl:template>
• Samtliga attribut är valfria, men minst ett av
attributen name och match måste återfinnas
Exempel, templates
<xsl:template match="boksamling">
<xsl:apply-templates
select="bok/forfattare/eNamn"/>
</xsl:template>
<xsl:template match="eNamn">
<xsl:value-of select="."/>
<xsl:value-of select="../fNamn"/>
<xsl:value-of select="../../titel"/>
<xsl:value-of select="../../kategori"/>
</xsl:template>
Exempel, templates med villkor
<xsl:template match="boksamling">
<xsl:apply-templates
select="bok/forfattare[eNamn='Grafton']"/>
</xsl:template>
<xsl:template match="forfattare">
<xsl:value-of select="eNamn"/>
<xsl:value-of select="fNamn"/>
<xsl:value-of select="../titel"/>
<xsl:value-of select="../kategori"/>
</xsl:template>
Repetitioner i XSLT: for-each
<xsl:for-each select=“X-PATH-uttryck”>
…kod som utförs på varje nod som
överensstämmer med X-PATHuttrycket
</xsl:for-each>
Exempel: for-each
<xsl:template match="/">
<xsl:for-each select="boksamling/bok">
<xsl:value-of
select="forfattare/eNamn"/>
<xsl:value-of
select="forfattare/fNamn"/>
<xsl:value-of select="titel"/>
<xsl:value-of select="kategori"/>
</xsl:for-each>
</xsl:template>
Exempel: for-each med villkor
<xsl:template match="/">
<xsl:for-each select
="boksamling/bok/forfattare[eNamn
='Grafton']">
<xsl:value-of select="eNamn"/>
<xsl:value-of select="fNamn"/>
<xsl:value-of select="../titel"/>
<xsl:value-of select="../kategori"/>
</xsl:for-each>
</xsl:template>
Styrstrukturer i XSLT
om (villkor a) utför a
annars om (villkor b) utför b
annars utför c
Med if
<xsl:if test=”villkor a">
…kod som utförs om villkor a är sant
</xsl:if>
<xsl:if test=”villkor b">
…kod som utförs om villkor b är sant
</xsl:if>
<xsl:if test=”villkor c">
…kod som utförs om villkor c är sant
</xsl:if>
Exempel: if
<xsl:if test="pris &lt; 10 and
kategori != 'Deckare'">
<xsl:value-of
select="forfattare/eNamn"/>:&#32;
<xsl:value-of select="titel"/>
</xsl:if>
Med choose
<xsl:choose>
<xsl:when test=”villkor a">
...kod som utförs om villkor a är sant
</xsl:when>
<xsl:when test=”villkor b">
...kod som utförs om villkor b är sant
</xsl:when>
<xsl:otherwise>
…kod som utförs om varken villkor a eller b är sant
</xsl:otherwise>
</xsl:choose>
Exempel: choose
<xsl:choose>
<xsl:when test="kategori='Deckare'">
<xsl:value-of select="titel"/>,&#32;
är en deckare
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="titel"/>,&#32;
är inte en deckare
</xsl:otherwise>
</xsl:choose>
Transformera XML-filen
<?xml version="1.0" encoding="ISO-8859-1" ?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns="http://www.w3.org/1999/xhtml">
<xsl:output method="xml" indent="yes" doctype-public="//W3C//DTD XHTML 1.0 Strict//EN" doctypesystem="http://www.w3.org/TR/xhtml1/DTD/xhtml1strict.dtd" />
<xsl:template match="/">
<html>
<head>
<title>Receptsamling</title>
</head>
<body>
<xsl:apply-templates select="receptsamling"/>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
Ett första steg…
</xsl:template>
<xsl:template
match="receptsamling">
<xsl:apply-templates
select="recept"/>
</xsl:template>
</xsl:stylesheet>
Kunde se bättre ut…
• Vi behöver fler templates!
<xsl:template match="recept">
<h2><xsl:value-of select="namn"/></h2>
<xsl:apply-templates select="ingrediens"/>
</xsl:template>
Liten förbättring…
• …men bra nog är det minsann inte!
• Fler templates!
<xsl:template match="ingrediens">
<xsl:value-of select="namn"/>&#32;
(<xsl:value-of select="kategori"/>)<br />
<xsl:value-of select="mangd"/>&#32;
<xsl:value-of select="mangd/@enhet"/><br />
</xsl:template>
Relevanta frågor för samlingen
• Ta fram alla recept som innehåller en
viss ingrediens
• Sortera alla recept i bokstavsordning
• Visa enbart receptet som heter…
• Lista alla rotfrukter i samlingen
(ok, den sista var kanske inte så himla
relevant)
Algoritm: ta fram alla recept som
innehåller ingrediensen pasta
1. Peka på rotelementet receptsamling
2. För varje recept i receptsamling
2.1 Om (ingrediens/namn=='Pasta')
2.1.1 Skriv ut namnet på receptet
2.2 annars
2.2.1 Gör ingenting
Lösning 1
<xsl:template match="receptsamling">
<xsl:apply-templates
select="recept/ingrediens[namn='Pasta']"/>
</xsl:template>
<xsl:template match="ingrediens">
<xsl:value-of select="../namn"/>
</xsl:template>
Exempel
Lösning 2
<xsl:template match="receptsamling">
<xsl:apply-templates select="recept"/>
</xsl:template>
<xsl:template match="recept">
<xsl:if test="ingrediens[namn='Pasta']">
<xsl:value-of select="namn"/>
</xsl:if>
</xsl:template>
Exempel
Algoritm: sortera alla recept i
bokstavsordning
1. Peka på rotelementet receptsamling
2. För varje recept i receptsamling
2.1 Sortera recepten i stigande
bokstavsordning
2.2 Skriv ut recepten
Lösning
<xsl:template match="receptsamling">
<xsl:apply-templates select="recept">
<xsl:sort select="namn" order="ascending"
data-type="text"/>
</xsl:apply-templates>
</xsl:template>
<xsl:template match="recept">
<xsl:value-of select="namn"/>
</xsl:template>
Exempel
Fler förslag på att transformera
XML-filen?
• …
Övningsmaterialet
• http://www.adm.hb.se/~dgu/elpub/xslt1.htm
Det där ska
föreställa en
etta