Parametere
Med referanse til data fra Olympiadeeksempelet, se modulen Olympiade .
Fila i sin helhet
Vi kan lage konstruksjoner av følgende type:
... <xsl:apply-templates select="IOC/OlympicGame" > <xsl:with-param name="sted" select="'Barcelona'"/> </xsl:apply-templates> ... <xsl:template match="OlympicGame"> <xsl:param name="sted"/> <xsl:if test="$sted=@place"> ... do something ... </xsl:if> </xsl:template> ...
Slike konstruksjoner er parallelle til måten vi bruker parametre på ved prosedyre-kall i andre programmeringsspråk. Parameterstyring av templates er interessant i seg selv, men det løser ikke det problemet vi stadig møter når vi skal planlegge XSLT-transformasjoner. Hvordan skal vi kunne parameterstyre hele transformasjonen ?
Hvis vi f.eks. ønsker å ekstrahere resultatene fra 200m i Barcelona fra vår lange XML-fil med flere olymiader og flere øvelser, har vi et problem. Det virker litt tungvindt å skrive en transformasjon for alle mulige kombinasjoner av sted og øvelse. Vi kan nærme oss problemet ved å se på en konstruksjon der vi innfører to "globale parametere":
<xsl:param name="sted" select="'Barcelona'"/> <xsl:param name="distanse" select="'200m'"/>
Når vi kaller dem globale så innebærer det at de er definert utenfor alle templates i stilsettet og de er tilgjengelig i hele fila, alle templates. Transformasjonsfila er i sin helhet slik:
<?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" version="1.0" omit-xml-declaration="yes" indent="yes"/>--> <xsl:output method="html" doctype-system="about:legacy-compat" encoding="UTF-8" /> <xsl:param name="sted" select="'Barcelona'"/> <xsl:param name="distanse" select="'200m'"/> <xsl:template match="/"> <html> <head> <title>Olympics</title> <link rel="STYLESHEET" href="olymp.css"/> </head> <body> <h1>Resultater sprint</h1> <xsl:apply-templates select="IOC/OlympicGame[@place=$sted]"/> <a href="javascript:history.back()">tilbake</a> </body> </html> </xsl:template> <xsl:template match="OlympicGame"> <h2> <xsl:value-of select="@place"/> - <xsl:value-of select="@year"/> </h2> <xsl:apply-templates select="event[@dist=$distanse]"/> </xsl:template> <xsl:template match="event"> <h3><xsl:value-of select="@track"/></h3> <xsl:apply-templates select="athlet"> <xsl:sort select="result" order="ascending"/> </xsl:apply-templates> </xsl:template> <xsl:template match="athlet"> <p> <xsl:value-of select="result"/> : <xsl:value-of select="name"/> </p> </xsl:template> </xsl:stylesheet>
Det virker rimelig å ønske seg et transformasjonsverktøy som kan ta en liste av parametre som input, tolke disse som globale parametre og så foreta transformasjonen. Og heldigvis, slike finnes. Vi skal se på et Pythonverktøy: lxml. I modulen På klienten kan du dessuten se hvordan vi kan gjøre dette på kliente.
lxml
lxml [1] synes å være det biblioteket som gir best og enklest funksjonalitet når det gjelder XSLT og XPath i Python.
Eksempel Olympiade
Vi tar utgangspunkt i samme xml-darta som ovenfor rådata og bruker den samme transformasjonen som er sitert ovenfor, med to globale parametre.
Vi bruker et Pythonprogram som cgi-script for å utføre transformasjonen basert på de ønskene (sted og øvelse) vi sender inn fra vår HTML-side.
#! /usr/bin/python import sys,cgi from lxml import etree #import cgitb; cgitb.enable() #------------------------------------------------------------- # Testing lxml, parametric xslt # B. Stenseth 2014 #------------------------------------------------------------- def produce(place,distance): # fixed filenames xmlfile='../ol/all_results.xml' xsltfile='olymp_x.xslt' htmlfile='result.html' xmlTree=etree.parse(xmlfile) xsltTree=etree.parse(xsltfile) transform=etree.XSLT(xsltTree) d=etree.XSLT.strparam(distance) p=etree.XSLT.strparam(place) resultTree=transform(xmlTree,sted=p,distanse=d) print str(resultTree) #----------------------------------------- print 'Content-type: text/html\n' form=cgi.FieldStorage() # what was thew question again ? place='' distance='' try: place=form['1'].value except: place='Barcelona' try: distance=form['2'].value except: distance='400m' produce(place,distance)
Eksempel Fotball
Vi tar utgangspunkt i en XML-fil som inneholder resultatene fra Engelsk Premier League sesongen 2001/2002. Fila er bygd opp slik:
<?xml version="1.0" encoding="utf-8"?> <liga> <land>England</land> <serie>Premier League</serie> <sesong>2001/2002</sesong> <kamp> <dato>18.08.2001</dato> <hlag>Charlton</hlag> <hmal>1</hmal> <blag>Everton</blag> <bmal>2</bmal> </kamp> <kamp> <dato>18.08.2001</dato> <hlag>Derby</hlag> <hmal>2</hmal> <blag>Blackburn</blag> <bmal>1</bmal> </kamp> ... </liga>
Fila i sin helhet
Vi skriver en transformasjon som ekstraherer resultater avhengig av angitt hjemmelag og bortelag:
<?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" doctype-system="about:legacy-compat" encoding="UTF-8" /> <xsl:param name="hjemmelag" select="'Chelsea'"/> <xsl:param name="bortelag" select="'Arsenal'"/> <xsl:template match="/"> <html> <head> <title>Fotball</title> </head> <body> <h1><xsl:value-of select="liga/land"/></h1> <h2> <xsl:value-of select="liga/serie"/> - <xsl:value-of select="liga/sesong"/> </h2> <xsl:for-each select="liga/kamp"> <xsl:if test="($hjemmelag='*' and $bortelag='*' ) or (hlag=$hjemmelag and $bortelag='*') or ($hjemmelag='*' and blag=$bortelag) or (hlag=$hjemmelag and blag=$bortelag)"> <xsl:apply-templates select="self::node()"/> </xsl:if> </xsl:for-each> <a href="javascript:history.back()">tilbake</a> </body> </html> </xsl:template> <xsl:template match="kamp"> <div> <xsl:value-of select="dato"/>: <xsl:value-of select="hlag"/>-<xsl:value-of select="blag"/> : <xsl:value-of select="hmal"/>-<xsl:value-of select="bmal"/> </div> </xsl:template> </xsl:stylesheet>
Vi bruker et Python-script, for å utføre transformasjonen basert på de ønskene vi sender inn.
#! /usr/bin/python import sys,cgi from lxml import etree #import cgitb; cgitb.enable() #------------------------------------------------------------- # Testing lxml, parametric xslt # Parameters are: # hjemmelag (*: wildcard) # bortelag (*: wildcard) # B. Stenseth 2014 #------------------------------------------------------------- def produce(hjemme,borte): # fixed filenames xmlfile='eng0_01_02.xml' xsltfile='trans1.xslt' htmlfile='result.html' xmlTree=etree.parse(xmlfile) xsltTree=etree.parse(xsltfile) transform=etree.XSLT(xsltTree) h=etree.XSLT.strparam(hjemme) b=etree.XSLT.strparam(borte) resultTree=transform(xmlTree,hjemmelag=h,bortelag=b) print str(resultTree) #----------------------------------------- print "Content-type: text/html\n" form=cgi.FieldStorage() # what was the question again ? hjemme='' borte='' try: hjemme=form['hjemmelag'].value except: hjemme='*' try: borte=form['bortelag'].value except: borte='*' produce(hjemme,borte)