24
Tags:
xml
Skrevet af
Bruger #2086
@ 13.12.2003
Introduktion til XSLT
Hvis du har læst de to artikler jeg har skrevet om XML, burde du efterhånden have et rimeligt godt indblik i XML som dataformat.
Du har lært lidt om hvad XML er for en størrelse samt at formatere XML med CSS.
Hvis du tænker lidt tilbage på artiklen om XML og CSS
kan du måske huske at du ikke kan bestemme om en node skal med i visningen eller om den skal udelades.
Imodsætning til CSS fungere XSL på følgende måde:
Kun de XML data man selv udvælger kommer med i visningen og XSL kan
transformere en XML fil til et hvilket som helst format f.eks HTML, WML, SVG og mange flere.
Da W3.org lavede XML standarden var og er XSL en del XML specifikationen, men da det tog lidt for lang tid at lave en XSL standard valgte man at opdele XSL i to dele: XSLT der bruges til transformationer og XSLFO der bruges til at formatere XML objekter til grafiske præsentationer og til tryksager.
Der er ikke nogen forskel på syntaksen i de to "typer" af XSL, den eneste forskel er det vaglte medie man laver transformation til der afgør hvilken version XSL der skal benyttes.
I de foregående artikler har jeg brugt HTML som indgangs vinkel til at forstå XML.
I denne artikel vil det være en fordel hvis du har styr på CSS.
Selv om at XSLT er et stylesheet sprog på linje med CSS, så kan XSLT en hel masse mere end CSS.
Men det er alligevel en god baggrunds viden at have styr på adskildelse af data og præsentation hvis du vil lære XSLT.
Alle eksempelerne i denne artikel siden bliver transformeret med et ASP script, det har den fordel at også browsere der ikke understøtter XSL og XML vil kunne vise eksempelerne da det kun er resultatet af transformationen der bliver vist af browseren.
Resultatet af alle eksempelerne er ren HTML kode men kunne ligeså godt have været et hvilket som helst andet format f.eks SVG eller WAP.
Noder, forældre og børn
Inden man går i krig med XSLT er der et begreb der skal sættes på plads.
Når man arbejder med de lidt mere avancerede dele af XML som f.eks Data Islands og XSL, skal man ændre sin tænkning omkring begrebet "TAGS".
Man skal tænke på et tag som et element eller mere korrekt som en NODE.
Man skal opfatte XML elementer der indeholder ander XML elementer som en såkaldet parrent-node (forældre) til alle de XML elementer der står imellem start og slut elementet.
Alle de noder der står direkte under en parrent-node skal opfattes som child-noder (børn) til deres parrent-node.
Derud over kan en parrent/child node indeholde en elle flere attribut-noder og for at gøre forvirringen total så kan både parrent-noder, child-noder og attribut-noder indeholde en tekst-node.
Der er et par gode grunde til at man skal opfatte XML som noder:
1. Som tidligere nævnt er XML ikke begrænset Web-udvikling, men kan også bruges til andre typer af applikationer f.eks COM + programmering og her arbejder man ikke med begrebet tags.
2. Når eller hvis du kommer igang med DOM programmering bruger man følgende properties til at udvælge de noder man vil manipulere med et DOM objekt f.eks XML DOM.
I. selectNodes (noder man vil udvælge)
II. selectSingleNode (node man vil udvælge)
Det vil måske tage lidt tid at vænne sig til at tænke på et tag som en node, men det er den måde man er nødt til at tænke på hvis man vil have optimalt udbytte af XML teknologien.
Download og instalation af XML parser
Hvis du selv skal arbejde med XSLT og XML Dom, er du nødt til at have have en XML parser installeret på din maskine, jeg vil anbefale dig at benytte Microsofts XML parser (MSXML) i mindst version 3, da den efter min mening har den bedeste understøttelse af XSL og XML Dom.
Parseren kan downloades hos Microsoft på dette link
http://www.microsoft.com/downloads/details.aspx?FamilyID=3144b72b-b4f2-46da-b4b6-c5d7485f2b42&displaylang=en Linket her føre dig til en side hvor du kan downloade MSXML 4.0.
Når MSXML er downloaded skal den installeres, det eneste du skal gøre er at dobbetklikke på filen og følge instalations vejledningen.
Hvis du får problemer med at installere parseren er det fordi du ikke har rette version af Windows installer installeret på din maskine, den kan downloades på samme side som paseren og er freeware.
Extensible Stylesheet Language Transformation (XSLT)
Det grundlæggende princip i XSLT er at man kan producerer et "output dokument" på grundlag af et XML document.
En transformation kan opfattes som en tre trins raket på denne måde:
Kildedokument (xml fil) ---> Stylesheet (xsl fil) ---> output dokument (f.eks HTML eller XML).
Man kan også have flere end et stylesheet der generere hver sit output dokument,
med udgangspunkt i den samme XML fil.
Det vil sige at de samme XML data kan bruges til at generere et uendligt antal output dokumenter.
Hvis du tænker det er jo det samme som man kan med en database så er det ikke helt forkert.
Inden vi går igang med XSL er der en ting man skal være opmærksom på:
Da XSL er en del af XML specifikationen skal et XSLT stylesheet være velformet
og det skal overholde regelerne for XML f.eks at elementer ikke må overlappe hinanden osv.
Det har den betydning at:
hvis man laver et output dokument i html format skal html'en også være velformet, i praksis betyder det at man skal skrive sin html efter Xhtml standarden.
Der er to bærende elementer i XSLT "Templates og Match pattens".
En template kan betragtes på samme måde som en regel i CSS der udføres på en selector.
Med en regel mener jeg de erklæringer man laver til et tag f.eks font-size, color, border osv.
Et match patten skal opfattes som en selector i css, altså som den XML node man vil lave formatering for.
En template er derfor at betragte som en skabelon der inderholder formatering for det matchende mønster (Match patten) der er indeholdt i templaten.
Den generelle syntaks for et XSLT stylesheet er vist i kode boksen herunder alt tekst der står i kursiv og fed skrift er kun kommentarer.
[i][b]Først XML PI'en[/b][/i]
<?xml version="1.0" encoding="iso-8859-1"?>
[i][b]Namespace og start element for stylessheetet[/b][/i]
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
[i][b]Template for dokument roden[/b][/i]
<xsl:template match="/">
På dette sted i styleshettet vil der som regel stå alle
basis koderne til et HTML dokument
Samt kald af et eller flere apply-templates elementer
[i][b]Afslutning Template for dokument roden[/b][/i]
</xsl:template>
Her kommer andre templates der matcher udvalgte XML noder
[i][b]Afslutning af stylessheetet element[/b][/i]
</xsl:stylesheet>
En lille forklaring til ovenstående er nok på sin plads.
Da et XSLT stylesheet også er XML skal man ALTID starte stylesheetet med en XML erklæring.
Derefter følger rod elementet og namespacet for stylesheetet
(<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
Hvis du ikke ved hvad et namespace er så er det såmænd "bare" en URL der definere elementeres tilhørsforhold.
Når namespacet er erklæret her man adgang til et præfix en slags forkortelse der identifisere et elements tilhørsforhold i dette tildfælde xsl:.
Det næste element der skal erklæres (<xsl:template match="/">
er en template der matcher (finder) dokument roden i det XML dokument man er ved at transformere, dokument roden er repræsenteret ved match="/", denne template skal ALTID laves i et XSL stylesheet da den er udgangspunktet for hele transformationen. Tildsidst lukkes XSL elementerne i den rækkefølge de er blevet åbnet.
XSLT syntaks
I stedet for at straks kaste mig ud i en masse transformations eksempler, vil jeg i tabellen her under beskrive de forskellige XSL elementer kort.
I næste afsnit vil du kunne se hvordan XSL elementerne bruges.
Der findes flere XSL elementer end dem jeg har angivet her på siden.
De her nævnte er de mest benyttede og de kan klarer de fleste udviklings opgaver man kan komme ud for.
Jeg vil vove påstanden at hvis du får 100% styr på disse elementer så vil det vare længe før du bliver udsat for en opgave der ikke kan løses med dem der er beskrevet i tabellen ovenfor.
Introdukton til XML Path Language (XPath)
På samme måde som et database program har et sprog (SQL) til at udvælge data fra en tabel, benytter man i XML et sprog der hedder XPath (XML path language), til at udvælge de XML noder man vil udføre en transformation på.
Jeg vil ikke i denne artikel gå i dybden med syntaksen i XPath da der kan skrives tykke bøger om dette sprog, men i næste afsnit er det XPath der benyttes hver gang jeg skriver en reference til en node i en match eller select attribut og jeg vil så løbende forklarer hvad der sker.
Men her en ultrakort forklaring af XPath
Udgangspunktet for en XPath reference er en såkaldet akse, begrebet en akse dækker over den retning der skal søges i efter den eller de noder man vil udvælge.
En Xpathreference er bygget op efter en bestemt syntaks.
Den er bygget op som et såkaldet location step på denne måde.
Akse :: Node-test [Nul eller flere prædikater]
Inden du går i gang med de forskellige eksempler er der et begreb du skal have styr på, begrebet er "kontekstnoden".
Begrebet kontekstnoden er lig med den aktuelle node der behandles, kontekstnoden er den node som xslt parseren arbejder udfra, kontekstnoden er den node der er angivet i et xsl elements select, match eller name attribut.
Det er vigtigt at man giver sig tid til at forstå begrebet kontekstnoden, da man ellers ikke vil være i stand til at opbygge et stylesheet som man selv kan forstå.
I de eksempler du kan se i næste afsnit bruger jeg kun child aksen og da child aksen er default aksen, behøver man ikke at angive aksen før den bruges, så de XPath referencer der benyttes i eksemplerne vil se ud på denne måde: nodetest1/nodetest2[prædikat]
En nodetest er lig med navnet på den eller de noder der udvælges.
Et prædikat skal opfattes som en en betingelse der kan knyttes til en nodetest, det er valgfrit om man vil bruge et prædikat, men i mange tilfælde er man ude efter at begrænse udvælgelsen af noder til en eller flere noder, der opfylder den betingelse man har skrevet som et prædikat, et prædikat skal altid skrives i firkantede prarenteser f.eks.
udvalgtnode[@id = '6'] som instruerer XSL parseren om kun at behandle det eller de noder der har værdien 6 for deres id attribiut.
Man kan også knytte mere end et prædikat til en nodetest følgende er derfor helt lovligt:
udvalgtnode[@id = '6'][attributnode='test'] nu vil parseren kun udføre en transformation for det familiemedlems som har en id attribut med værdien 6 og en attribut med tekst værdien 'test'. Ikke mere om XPath i denne artikel.
Eksempel på XSL Transformation
For at kunne lave nogle forskellige eksempler på XSLT, skal jeg bruge et XML dokument der indeholder de data jeg skal bruge dokumentet som er et udsnit af mit stamtræ kan ses herunder.
Dokumentet er gemt med navnet familie.xml
<?xml version="1.0" encoding="iso-8859-1"?>
<stamtrae>
<familemedlem id="001" familiegren="hansen">
<fornavn>Susanne</fornavn>
<efternavn>Hansen</efternavn>
<roller>
<rolle>Mor til marc, </rolle>
<rolle>Claus kone, </rolle>
<rolle>Faster til Julie og Mathias, </rolle>
<rolle>Tante til Rasmus og Mads</rolle>
</roller>
<koen>Kvinde</koen>
<alder>38 år</alder>
<hoejde>167 cm</hoejde>
<vaegt>Må jeg ikke oplyse (men den er lav ;o)</vaegt>
</familemedlem>
<familemedlem id="002" familiegren="pryds">
<fornavn>Claus</fornavn>
<efternavn>Pryds</efternavn>
<roller>
<rolle>Far til Marc, </rolle>
<rolle>Susannes mand, </rolle>
<rolle>Farbror til Rasmus og Mads, </rolle>
<rolle>Onkel til Julie og Mathias</rolle>
</roller>
<koen>Mand</koen>
<alder>37 år</alder>
<hoejde>175 cm</hoejde>
<vaegt>74 kg.</vaegt>
</familemedlem>
<familemedlem id="003" familiegren="pryds">
<fornavn>Marc</fornavn>
<efternavn>Hansen</efternavn>
<roller>
<rolle>Vores søn, </rolle>
<rolle>Fætter til Rasmus, Mads, Julie og Mathias</rolle>
</roller>
<koen>Dreng</koen>
<alder>10 år</alder>
<hoejde>152 cm</hoejde>
<vaegt>41 kg</vaegt>
</familemedlem>
<familemedlem id="004" familiegren="pryds">
<fornavn>Ellen</fornavn>
<efternavn>Pryds</efternavn>
<roller>
<rolle>Mor til Claus, </rolle>
<rolle>Svigermor til Susanne, </rolle>
<rolle>Farmor til marc, </rolle>
<rolle>Mormor til Rasmus og Mads</rolle>
</roller>
<koen>Kvinde</koen>
<alder>61 år</alder>
<hoejde>158 cm</hoejde>
<vaegt>Ikke oplyst</vaegt>
</familemedlem>
<familemedlem id="005" familiegren="pryds">
<fornavn>Ib</fornavn>
<efternavn>Pryds</efternavn>
<roller>
<rolle>Far til Claus, </rolle>
<rolle>Svigerfar til Susanne, </rolle>
<rolle>Farfar til Marc, </rolle>
<rolle>Morfar til Rasmus og Mads</rolle>
</roller>
<koen>Mand</koen>
<alder>67 år</alder>
<hoejde>168 cm</hoejde>
<vaegt>67 kg</vaegt>
</familemedlem>
</stamtrae>
Dette er kun et udsnit af hele dokumentet. Hele dokumentet kan ses i sin helhed i artiklen Start på XML.
Som nævnt i afsnittet XSLT syntaks er der to bærende elementer i XSLT "Templates og Match pattens".
En template kan betragtes på samme måde som en regel i CSS der udføres på en selector.
Med en regel mener jeg de erklæringer man laver til et tag f.eks font-size, color, border osv.
Et match patten skal opfattes som en selector i css, altså som den XML node man vil lave formatering for.
En template er derfor at betragte som en skabelon der inderholder formatering for det matchende mønster (Match patten) der er indeholdt i templaten.
Dokumentet er magen til det dokument jeg har brugt i min artikel om XML og CSS, men imodsætning til det eksempel jeg lavede i den artikel vil du se, at jeg ved hjælp af et meget simpelt ASP script og XSLT er istand til, at producere lige så mange dokumenter i dette tilfælde html dokumenter som jeg vil, i alt laver jeg 5 dokumenter ud af de samme XML data. ASP scriptet der udføre transformationerne er gennemgået i sidste afsnit i denne artikel.
Eksempel 1 Template til udvælgelse af node med value-of
I dette eksempel bliver der genereret noget html kode samt indholdet i fornavn og efternavn noderne i familie.xml.
Udvælgelse af noder laves med et xsl:value-of element.
I xsl:value-of elementes select attribut skriver man en XPath (sti) til den node man vil bearbejde.
En XPath reference skrives på samme måde som når man angiver mapper i en URL.
En XPath skal skrives med udgangspunkt i den aktuelle node der er angivet i det template elements match attribut hvor value-of elementet er defineret.
Den aktuelle node i dette tilfælde er dokument roden, fordi at match attributten kun indeholder en /
Derfor er jeg nødt til at skrive hele stien til den node jeg er ude efter med følgende XPath:
stamtrae/familemedlem/fornavn = rodnode/elementNode/udvalgtNode.
[b]Først XML PI'en[/b]
<?xml version="1.0" encoding="iso-8859-1"?>
[b]Namespace og start element for stylessheetet[/b]
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
[b]Template for dokument roden[/b]
<xsl:template match="/">
[b]Indsætter html og body start tags og et stylesheet[/b]
<html>
<head>
<style type="text/css">
body{background-color:rgb(78,77,75);color:rgb(190,202,200);}
li{color:#FFBC54;}
</style>
</head>
<body>
[b]Oprettelse af to value-of elementer i li tags + XPath
i select attributter til fornavn og efternavns noder[/b]
<li><xsl:value-of select="stamtrae/familemedlem/fornavn"/></li><br/>
<li><xsl:value-of select="stamtrae/familemedlem/efternavn"/></li><br/>
[b]Indsætter html og body slut tags[/b]
</body>
</html>
[b]Afslutning Template for dokument roden[/b]
</xsl:template>
[b]Afslutning af stylessheetet element[/b]
</xsl:stylesheet>
Se eksempel her
http://cws-webservice.dk/xml/visfamilie.asp?TransformationsType=docroot_valueofSom du ser bliver der kun udført transformation for den første forkomst af fornavn og efternavn og kun for det første familemedlem's element som parseren møder.
Et value-of element virker på denne måde og det er jo ikke lige det jeg er ude efter, jeg vil udføre en transformation alle fornavn og efternavn's noder der findes direkte alle familiemedlem elementer i filen familie.xml, men vi er da kommet et stykke af vejen mod det endlige mål.
Løsningen er at indsætte et XSL element der kalder den oprettede template sålænge der er XML elementer der matcher XPathen i select attributten.
En anden egenskab ved et value-of element er: da elementet altid repræsentere tekst indeholdet i det udvalgte element vil elementet opfattes som et "tomt" element og kan derfor lukkes på den korte måde (<xsl:value-of select="fornavn" />
husk på at XSL er også XML så alle elementer skal afsluttes.
Eksempel 2 Template til udvælgelse af noder med for-each
Det ene af de to XSL elementer der kan udføre transformationen for enhver forkomst af en angivet node hedder xsl:for-each (for hver), et for-each element fungerer på følgende måde:
Når parseren behandler den template der indeholder for-each elementet kigger den først
på match attributten i templaten for at finde ud af hvilken node der er den aktuelle node
som jeg fra nu af kun vil referere til som "kontekst noden".
Derefter ser den for-each elementet og læser XPathen fra kontekst noden, i dette tilfælde ser parseren at den skal udføre en transformation for de noder der findes direkte under et familiemedlem element,
men kun for de noder der udvælges i value-of elementerne.
Hele templaten ser nu ud på denne måde.
[b]Først XML PI'en[/b]
<?xml version="1.0" encoding="iso-8859-1"?>
[b]Namespace og start element for stylessheetet[/b]
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
[b]Template for dokument roden[/b]
<xsl:template match="/">
[b]Indsætter html og body start tags og et stylesheet[/b]
<html>
<head>
<style type="text/css">
body{background-color:rgb(78,77,75);color:rgb(190,202,200);}
li{color:#FFBC54;}
</style>
</head>
<body
[b]Start for-each element og XPath til familiemedlem[/b]
<xsl:for-each select="stamtrae/familemedlem">
[b]Value-of elementer i li tags og udvælgelse af noder i select attributter[/b]
<li>Fornavn: <xsl:value-of select="fornavn"/></li><br/>
<li>Efternavn: <xsl:value-of select="efternavn"/></li><br/>
<li>Køn: <xsl:value-of select="koen"/></li><br/><br/>
[b]Slut for-each element[/b]
</xsl:for-each>
[b]Indsætter html og body slut tags[/b]
</body>
</html>
[b]Afslutning Template for dokument roden[/b]
</xsl:template>
[b]Afslutning af stylessheetet element[/b]
</xsl:stylesheet>
Se eksempel her
http://cws-webservice.dk/xml/visfamilie.asp?TransformationsType=for_eachSom du kan se har jeg nu opnået at transformationen bliver udført for alle forkomster af
noderne "fornavn" "efternavn" og "koen".
Men et for-each element kan ikke bruges til at kalde en template der er oprettet et andet sted i stylesheetet, men kan "kun" bruges i den template hvor i elementet er oprettet.
Det kan et apply-templates element derimod som bliver beskrevet i det næste eksempel.
Eksempel 3 Template til udvælgelse af noder med apply-templates
Selvom at transformationen med for-each elementet virker som den skal, er resultatet
ikke helt som jeg havde tænkt mig det skulle være.
Bl.a vil jeg gerne kunne lave en formatering for nogle familiemedlemmer
og en anden formatering for nogle andre familiemedlemmer.
Til dette formål har jeg brug for et xsl:apply-templates element, dette elements egenskab er at det kan tildele en template den formatering der er lavet i en anden template.
Principet minder lidt om funktionsorienteret programmering hvor man skriver en stump kode der så kan kaldes flere forskellige steder i et program.
[b]Først XML PI'en[/b]
<?xml version="1.0" encoding="iso-8859-1"?>
[b]Namespace og start element for stylessheetet[/b]
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
[b]Template for dokument roden[/b]
<xsl:template match="/">
[b]Indsætter html og body start tags og et stylesheet[/b]
<html>
<head>
<style type="text/css">
body{background-color:rgb(78,77,75);color:rgb(190,202,200);}
li{color:#FFBC54;}
</style>
</head>
<body>
[b]Indsætter et apply-template element og en XPath til familemedlem noder[/b]
<xsl:apply-templates select="stamtrae/familemedlem"/>
[b]Indsætter html og body slut tags[/b]
</body>
</html>
[b]Afslutning Template for dokument roden[/b]
</xsl:template>
[b]Template for familemedlem noder[/b]
<xsl:template match="familemedlem">
[b]Value-of elementer i li tags og udvælgelse af noder i select attributter[/b]
<li>Fornavn: <xsl:value-of select="fornavn"/></li><br/>
<li>Efternavn: <xsl:value-of select="efternavn"/></li><br/>
<li>Køn: <xsl:value-of select="koen"/></li><br/><br/>
[b]Afslutning Template for familemedlem noder[/b]
</xsl:template>
[b]Afslutning af stylessheetet element[/b]
</xsl:stylesheet>
Se eksempel her
http://cws-webservice.dk/xml/visfamilie.asp?TransformationsType=docroot_apply_tempSom du ser er der ingen forskel på resultatet af dette stylesheet og det foregående.
den største forskel er at jeg har to templates en for dokument-roden og en for familiemedlem noder samt at XPath referencerne er anderledes end i det foregående stylesheet.
Den største forskel på XPath referencerne er at i familiemedlem templaten angiver jeg kun en kontekst node og lader så apply-templats elementet finde alle familiemedlem elementerne ved hjælp af XPath'en stamtrae/familemedlem som er angivet i select attributten.
Forskellen på apply-templats og for-each elementerne består ikke så meget i resultatet, forskellen består i metoden og andvendelse mulighederne.
En af andvendelse mulighederne af et apply-templats element er at man kan lave templates for flere forskellige noder f.eks kan jeg lave en template for en rolle node også kalde denne template inde i familiemedlem's templaten, på denne måde opnår jeg 100% kontrol med den endlige formatering af filen familie.xml.
Eksempel 4 Template til udvælgelse af noder med choose og when
Jeg vil gerne lave mit stylesheet på en måde der gøre at jeg kan lave en forskellig formatering for et familiemedlem afhængig af hvilken gren af familien medlemet tilhører.
For at kunne gører det er jeg nødt til, at lave en test af de enkelte familiemedlemeres tilhørs forhold, til det formål har jeg følgende to muligheder:
1. Jeg kan bruge et xsl:if element der kan lave en test der udføres en transformation hvis en bestemt betingelse er opfyldt, hvis den betingelse der er angivet ikke er opfyldt udføres der ikke en transformation.
2. Jeg kan bruge et xsl:choose element som kan teste for om en af flere betingelser er opfyldt og derefter udføre en slags formatering hvis betingelse nr 1 er opfyldt og en anden slags formatering hvis betingelse nr 2 er opfyldt osv. Hvis ingen af de betingelser der angives opfyldes kan man angive et xsl:otherwise element der så udføre en anden transformation.
Strukturen bruges på samme måde som en if, else if, else struktur i programmering.
Transformationen med en xsl:if test at bruge til at udvælge en bestemt node, men hvis man gerne vil lave en formatering for alle noder der matcher et mønster og en anden formatering for alle noder der matcher et andet mønster, giver det mere mening at bruge et xsl:choose element.
Grunden til dette er at et xsl:choose element bruges til at lave en test af en type noder med et xsl:when element, som bliver grundlaget for en type formatering og et xsl:otherwise element som som bliver grundlaget for en anden type formatering.
Strukturen i en xsl:choose test har flere fordele:
1. Koden er mere læsbar når den deles op i blokke.
2. Man kan lave flere end en xsl:when test i hver blok.
3. Man kan lave en alternativ formatering hvis ingen xsl:when test er true.
Den præsentation jeg gerne vil ende med at lave er:
Jeg vil lave en gruppering af mine familiemedlemmer sorteret efter hvilken gren af familien de tilhøre, for at skille de to grene ad vil jeg lave en class der formatere hver sin familiegren.
For at løse denne opgave skal jeg identificere de to familiegrene henholdsvis Hansen og Pryds.
Derfor laver jeg en xsl:choose struktur med en xsl:when test og et xsl:otherwise element.
Du kan se det færdige stylesheet i kodeboksen herunder.
[b]Først XML PI'en[/b]
<?xml version="1.0" encoding="iso-8859-1"?>
[b]Namespace og start element for stylessheetet[/b]
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
[b]Template for dokument roden[/b]
<xsl:template match="/">
[b]Indsætter html og body start tags og et stylesheet[/b]
<html>
<head>
<style type="text/css">
body{background-color:rgb(78,77,75);color:rgb(190,202,200);font-size:12px;font-family:verdana;}
th {background-color:#CC7002;color:black;font-size:13px;}
td {padding:3px;font-size:10px;}
table{border:solid 1px #CC7002;}
.pryds{font-size:10px;background-color:#CC7002;color:#FFBC54;}
.hansen{font-size:10px;background-color:#FFBC54;color:rgb(78,77,75)}
</style>
</head>
<body>
[b]starter en table og kalder et apply-templates element[/b]
<table>
<thead>
<tr bgcolor="#FFBC54">
<th>ID og Job</th>
<th>Fornavn</th>
<th>Efternavn</th>
<th>Vægt</th>
<th>Alder</th>
<th>Køn</th>
<th>Beskrivelse</th>
</tr>
</thead>
<tbody>
<xsl:apply-templates select="stamtrae/familemedlem"/>
</tbody>
</table>
</body>
</html>
[b]Afslutning Template for dokument roden[/b]
</xsl:template>
[b]Template der matcher familemedlem[/b]
<xsl:template match="familemedlem">
[b]Indsætter et xsl:choose element[/b]
<xsl:choose>
[b]Indsætter en xsl:when test[/b]
<xsl:when test="@familiegren='pryds'">
<tr class="pryds">
<td>Familiemedlem nr: <xsl:value-of select="@id"/>
(<xsl:value-of select="job-titel"/>)</td>
<td>Fornavn: <xsl:value-of select="fornavn"/></td>
<td>Efternavn: <xsl:value-of select="efternavn"/></td>
<td>Vægt: <xsl:value-of select="vaegt"/></td>
<td>Køn: <xsl:value-of select="koen"/></td>
<td>Alder: <xsl:value-of select="alder"/></td>
<td><xsl:value-of select="beskrivelse"/></td>
</tr>
[b]Afslutning xsl:when test[/b]
</xsl:when>
[b]Indsætter et xsl:otherwise element[/b]
<xsl:otherwise>
<tr class="hansen">
<td>Familiemedlem nr: <xsl:value-of select="@id"/>
(<xsl:value-of select="job-titel"/>)</td>
<td>Fornavn: <xsl:value-of select="fornavn"/></td>
<td>Efternavn: <xsl:value-of select="efternavn"/></td>
<td>Vægt: <xsl:value-of select="vaegt"/></td>
<td>Køn: <xsl:value-of select="koen"/></td>
<td>Alder: <xsl:value-of select="alder"/></td>
<td><xsl:value-of select="beskrivelse"/></td>
</tr>
[b]Afslutning xsl:otherwise element[/b]
</xsl:otherwise>
[b]Afslutning xsl:choose element[/b]
</xsl:choose>
[b]Afslutning familiemedlems template[/b]
</xsl:template>
[b]Afslutning stylesheet[/b]
</xsl:stylesheet>
Se eksempel her
http://cws-webservice.dk/xml/visfamilie.asp?TransformationsType=chooseSom du ser har jeg opnået at hver gren af min familie er vist med hver sin CSS class.
Men jeg har ikke fået grupperet de to familiegrene, i det sidste stylesheet på denne side vil jeg vise hvordan en sådan gruppering kan laves.
Eksempel 5 Template det færdige resultat
For at lave en gruppering af de to familiegrene, har jeg valgt at lave et stylesheet der består af to templates der matcher hver sin familiegren.
Hver template bliver så kaldt i hvert sit apply-template element som indsættes i hver sin table, man kan sige at denne måde at lave et stylesheet på er mere simple end nogle af de andre eksempler jeg har vist, men det er jo også god programmeringsskik at lave sin kode så simpel som muligt.
Du kan se det færdige stylesheet i kode boksen herunder.
[b]Først XML PI'en[/b]
<?xml version="1.0" encoding="iso-8859-1"?>
[b]Namespace og start element for stylessheetet[/b]
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
[b]Template for dokument roden[/b]
<xsl:template match="/">
<html>
<head>
<style type="text/css">
body{background-color:rgb(78,77,75);color:rgb(190,202,200);font-size:12px;font-family:verdana;}
th {border:solid 1px #CC7002;background-color:rgb(78,77,75);color:#FFBC54;font-size:13px;}
td {padding:3px;font-size:10px;}
table{border:solid 1px #CC7002;}
h3 {margin-top:45px;text-align:center;color:rgb(78,77,75);background-color:#FFBC54;border:solid 1px #CC7002;padding:4px;}
.pryds{font-size:10px;background-color:#CC7002;color:rgb(78,77,75);}
.hansen{font-size:10px;background-color:#FFBC54;color:rgb(78,77,75)}
</style>
</head>
<body>
<h3>Familiegren: Pryds</h3>
[b]Starter en table for familiegrenen Pryds[/b]
<table width="100%">
<thead>
<tr bgcolor="#CC7002">
<th>Gren og Job</th>
<th>Fornavn</th>
<th>Efternavn</th>
<th>Vægt</th>
<th>Alder</th>
<th>Køn</th>
<th>Beskrivelse</th>
</tr>
</thead>
<tbody>
[b]Indsætter et xsl:apply-templates og et xsl:sort element for Pryds grenen[/b]
<xsl:apply-templates select="stamtrae/familemedlem[@familiegren='pryds']">
<xsl:sort select="stamtrae/familemedlem/@id" data-type="number"/>
</xsl:apply-templates>
</tbody>
</table><br/><br/>
[b]Table for familiegrenen Pryds slut[/b]
<h3>Familiegren: Hansen</h3>
[b]Starter en table for familiegrenen Hansen[/b]
<table width="100%">
<thead>
<tr bgcolor="#FFBC54">
<th>Gren og Job</th>
<th>Fornavn</th>
<th>Efternavn</th>
<th>Vægt</th>
<th>Alder</th>
<th>Køn</th>
<th>Beskrivelse</th>
</tr>
</thead>
<tbody>
[b]Indsætter et xsl:apply-templates og et xsl:sort element for Hansen grenen[/b]
<xsl:apply-templates select="stamtrae/familemedlem[@familiegren='hansen']">
<xsl:sort select="stamtrae/familemedlem/@id" data-type="number"/>
</xsl:apply-templates>
</tbody>
</table>
[b]Table for familiegrenen hansen slut[/b]
</body>
</html>
[b]Template for dokument roden slut[/b]
</xsl:template>
[b]Template for familiegren Pryds[/b]
<xsl:template match="familemedlem[@familiegren='pryds']">
<tr class="pryds">
<td>Familiegren <xsl:value-of select="@familiegren"/><br/>
(<xsl:value-of select="job-titel"/>) </td>
<td>Fornavn:<br/> <xsl:value-of select="fornavn"/></td>
<td>Efternavn:<br/> <xsl:value-of select="efternavn"/></td>
<td>Vægt:<br/> <xsl:value-of select="vaegt"/></td>
<td>Køn:<br/> <xsl:value-of select="koen"/></td>
<td>Alder:<br/> <xsl:value-of select="alder"/></td>
<td><xsl:value-of select="beskrivelse"/></td>
</tr>
[b]Template for familiegren Pryds slut[/b]
</xsl:template>
[b]Template for familiegren Hansen[/b]
<xsl:template match="familemedlem[@familiegren='hansen']">
<tr class="hansen"> <td>Familiegren <xsl:value-of select="@familiegren"/><br/>
(<xsl:value-of select="job-titel"/>) </td>
<td>Fornavn:<br/> <xsl:value-of select="fornavn"/></td>
<td>Efternavn:<br/> <xsl:value-of select="efternavn"/></td>
<td>Vægt:<br/> <xsl:value-of select="vaegt"/></td>
<td>Køn:<br/> <xsl:value-of select="koen"/></td>
<td>Alder:<br/> <xsl:value-of select="alder"/></td>
<td><xsl:value-of select="beskrivelse"/></td>
</tr>
[b]Template for familiegren Hansen slut[/b]
</xsl:template>
</xsl:stylesheet>
Se eksempel her
http://cws-webservice.dk/xml/visfamilie.aspSom du ser har jeg opnået det jeg ville, hver gren af min familie er grupperet og vist med hver sin formatering.
Derud over er der også lavet en sortering i faldende rækkefølge med et xsl:sort element sorteringen er lavet med udgangspunkt i mine id attributers værdi.
Det var så slut på det sidste eksempel, hvis du kopiere et eksempel for, at teste på din egen maskine så husk, at fjerne alt tekst i eksemplerne der står med fed skrift de er kun kommentarer.
ASP script til udførelse af transformation
Som jeg har nævnt bruger jeg et ASP script til at udføre transformationerne, det har den store fordel at også de browsere der ikke understøtter XML, vil være i stand til at vise resultatet (den genereret HTML) af transformationen, fordi at transformationen sker på en server.
Man kan også vælge at lade IE udføre transformationen, det gøres ved at indsætte denne stylesheet erklæring i sit XML dokument.
<?xml-stylesheet type="text/xsl" href="navn-på-stylesheet.css"?>
Her efter vil IE kunne udføre transformationen men kun IE fra version 5
og at begrænse sin bruger gruppe til dette er ikke optimalt.
Du kan se ASP scriptet i kode boksen her under.
<SCRIPT LANGUAGE="JSCRIPT" RUNAT="SERVER">
// *************************************************************************
// Detect hvilken type præsentation, XML-dokumentet skal transformeres til.
// Med en switch case struktur der vælger et stylesheet med udgangspunkt
// i den overførte Querystring "TransformationsType"
// *************************************************************************
var strStyleFile;
switch (Request("TransformationsType") + "")
{
case "docroot_valueof" :
strStyleFile = "docrod_valueof.xsl";
break;
case "for_each" :
strStyleFile = "for_each.xsl";
break;
case "docroot_apply_temp" :
strStyleFile = "docrod_temp_apply.xsl";
break;
case "choose" :
strStyleFile = "choose.xsl";
break;
default :
strStyleFile = "visfamilie.xsl";
}
// ******************************************************
// 2. Finder placering af XML-dokument og XSLT-stylesheet.
// ******************************************************
var strSourceFile = Server.MapPath("familie.xml");
var strStyleFile = Server.MapPath(strStyleFile);
// ******************************************************
// 3. Indlæs XML-dokument i et DOM object.
// ******************************************************
var oSource = Server.CreateObject("MSXML2.DOMDocument.4.0");
oSource.async = false;
oSource.load(strSourceFile);
// ******************************************************
// 4. Indlæs XSLT-stylesheet i et DOM object.
// ******************************************************
var oStylesheet = Server.CreateObject("MSXML2.DOMDocument.4.0");
oStylesheet.async = false;
oStylesheet.load(strStyleFile);
// ******************************************************
// 5. Send transformeret HTML til client.
// ******************************************************
oSource.transformNodeToObject (oStylesheet, Response);
</SCRIPT>
Hvis du ikke kender så meget til ASP forstår du sikkert ikke så meget af scriptet.
Det vil være for omfattende at gå i dybden med scriptet men det grundlæggende er.
Scriptet får overfør en Querystring parameter fra et almindeligt link f.eks:
<a href="visfamilie.asp?TransformationsType=docrod_valueof">
Querystringen er den del af linket der står efter ? tegnet, i dette tilfælde aflæser scriptet TransformationsTypen som er lig docrod_valueof, som så finder det rette stylesheet i switch case strukturen.
På grundlag af denne parameter vælger scriptet dette stylesheet docrod_valueof.xsl.
På denne måde kan jeg udføre mange forskellige transformationer af det samme XML dokument ved at kalde scriptet med en forskellig TransformationsType parameter.
Det var alt i denne omgang om XSLT håber, at du får lidt ud af artiklen. Prøv selv at lege lidt med de muligheder XSLT tilbyder og du vil opdage, at mulighederne er næsten uden grænser.
MVH
Claus Pryds
Hvad synes du om denne artikel? Giv din mening til kende ved at stemme via pilene til venstre og/eller lægge en kommentar herunder.
Del også gerne artiklen med dine Facebook venner:
Kommentarer (7)
Ok artikel, meget god. Men synes at kunne forstå at du skærer XSL og XSLT over een kam, det er nu engang ikke det samme, og der er forskel på de muligheder der er i henhold til Transformationer. Men udemærket artikel.
Nej det gør jeg ikke.
XSL består som jeg starter artiklen med, at beskrive af 2 dele XSLT og XSLFO hverken mere eller mindre.Som jeg læser din kommentar forstår jeg at du mener, at der findes mere end de nævnte del satndarder af XSL og det gør der ikke.
Med hensyn til at du skriver citat: "synes at kunne forstå at du skærer XSL og XSLT over een kam, det er nu engang ikke det samme"
kan jeg kun sige at hvad du forstår eller fortolker ud fra hvad der står i artiklen må stå for din egen regning.
Eftersom at du skriver XSL og XSLT nu engang ikke det samme (hvilket du næsten har ret i) er det så ikke dig har forstået at XSLT er en del af XSL standarden ?
Selv om at jeg på ingen måder er sur eller noget andet over din kommentar, så har jeg svært ved, at opfatte din kommentar som andet kritik for kritikens skyld ;o)
og ikke som konstruktiv kritik
Fin artikel - det er de nu alle 3. God til folk der skal igang med XML. Dejligt også at eksemplet går igen i alle 3 - det gør der nemmere at følge.
jeg ved ikke om det er mig der har misforstået noget... men du beskriver det som om det var serverside teknologi...
jeg tror ikke min næste hp bliver med xml for hvis browseren alligevel bare får html er forskælden lig 0.....
jeg må indrømme at jeg kun troede w3c lavede client teknologier...
når... jeg kan vel lave det hele med html , dhtml og asp/php...
Hej jop
Du skriver følgende
"jeg ved ikke om det er mig der har misforstået noget... men du beskriver det som om det var serverside teknologi..."
Jeg har skrevet at transformationen af de XML data jeg bruger udføres med et ASP script i dette tilfælde.
Men man kan sagtens bruge XSLT og XML på klienten.
Den eneste grund til at jeg bruger ASP er for at få alle de forskellige browsere med.
Det er nemlig ikke alle browsere der kan fortolke XML og XSLT.
Du vil også sagtens kunne bruge et javacsript til at udføre transformationer på klienten.
MVH
Claus Pryds
Serdeles fed artikkel.. Du er for min skyld meget velkommen til at lave en mere udbyggende artikkel med de typer som du siger du bevidst ikke har taget med..
Jeg må sige det er en af de bedste på dansk jeg har læst og jeg har ledt en del på google udne at finde noget så dybdegående
..
Til dem der ikke lige har lagt mærke til det så er det faktisk også XSLT der bliver brugt til at formatere de logs som messenger laver.. hvis du redigere i xml filerne er de jo helt ulæselige men hvis man åbner dem med IE er de jo fint overskuelige og med pæne farver
De fleste eksempler vil i praksis fucke.
Og der mangler bestemt en beskrivelse af <xsl:output>..
Artiklen bærer præg af skribent ikke har benyttet xsl i praktisk, kun sat sig ind i.
Men ellers en dybegående artikel, men intet nyt sammenlignet med w3c's lette guide.
Venligst.
Du skal være
logget ind for at skrive en kommentar.