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 > 6 6 < 8 A >= B B <= 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 < 10 and kategori = 'Deckare’ – pris < 10 or kategori = 'Deckare’ – pris < 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 < 10 and kategori != 'Deckare'"> <xsl:value-of select="forfattare/eNamn"/>:  <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"/>,  är en deckare </xsl:when> <xsl:otherwise> <xsl:value-of select="titel"/>,  ä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"/>  (<xsl:value-of select="kategori"/>)<br /> <xsl:value-of select="mangd"/>  <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