!

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

Parametere
Saxon
4Suite
lxml
Børre Stenseth
XSL > XSLT >Parametere

Parametre

Hva
Parametere i XSL-transformasjoner, interne og eksterne. Saxon og 4Suite

XSL har et parameterbegrep. Vi kan definere parametre og bruke dem f.eks. når vi kaller en template.

Med referanse til data fra Olympiadeeksempelet, se modulen Olympiade . Dataene er slik page2/all_results.xml i en XML-vennlig nettleser.

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="html" version="1.0" encoding="UTF-8" indent="yes"/>

<xsl:param name="sted" select="'Barcelona'"/>
<xsl:param name="distanse" select="'200m'"/>

<xsl:template match="/">
<html>
<head>
      <title>Olympics</title>
      <meta HTTP-EQUIV="Content-Type"  content="text/html; charset=iso-8859-1"/>
      <link rel="STYLESHEET" href="olymp.css"/>
</head>
<body>
   <h1>Resultater sprint</h1>
   <xsl:apply-templates select="IOC/OlympicGame[@place=$sted]"/>
</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>
Resultatet http://www.it.hiof.no/~borres/dw/xsl/page2/xsl_output.html

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å to, ett Javaverktøy: Saxon og et Pythonverktøy: lxml. I modulen XSLT på klienten kan du dessuten se hvordan vi kan gjøre dette på kliente.

Saxon

Saxon [1] distribueres som en jar-fil. Saxon kan ta en parameterliste som input. Et kall på Saxon som løser vårt problem er slik:

java -jar C:\saxon8\saxon8.jar -o outputfil xmlfil xsltfil sted=Barcelona distanse=100m

Saxon er et Java-prosjekt med åpen kildekode og gir oss alt det verktøyet vi trenger for å skrive Javaprogrammer som transformerer som vi måtte ønske.

De siste versjoenen av Saxon (8 +) distribureres også som .Net -biliotek.

lxml

lxml [2] 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 rådata fra Olympiade eksempelet: page2/all_results.xml 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
#-------------------------------------------------------------
# Testing lxml, parametric xslt
# Work on fixed files: all_results.xml and olymp_x.xslt
# Parameters are:
# sted (Barcelona, Atlanta,  ) 
# distanse (100m or 200m or 400m) 
# B. Stenseth  2011
#-------------------------------------------------------------
def loadFile(fname):
    try:
        file=open(fname,'r')
        res=file.read()
        file.close()
        return res
    except:
        errorReturn('error reading: ' + fname)
def storeFile(fname,content):
    try:
        outf=open(fname,'w')
        outf.write(content)
        outf.close()
    except:
        errorReturn('error writing: ' + fname)

def errorReturn(msg):
    print """<html>
<head><title>errormsg</title></head>
<body><p>%s</p></body>
</html>"""%msg
    exit()

def produce(place,distance):
    # fixed filenames 
    xmlfile='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)
Test her http://www.it.hiof.no/~borres/dw/xsl/page2/lxmlstarter.html

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" version="1.0" encoding="UTF-8" indent="yes"/>
<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>

    </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>

Begge filene legges på cgi-bin området på tjeneren og 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
#-------------------------------------------------------------
# Testing lxml, parametric xslt
# Work on fixed files: eng0_01_02.xml and trans1.xslt
# Parameters are:
# hjemmelag (*: wildcard)
# bortelag  (*: wildcard)
# B. Stenseth  2011
#-------------------------------------------------------------
def loadFile(fname):
    try:
        file=open(fname,'r')
        res=file.read()
        file.close()
        return res
    except:
        sys.exit('gir opp...')
def storeFile(fname,content):
    try:
        outf=open(fname,'w')
        outf.write(content)
        outf.close()
    except:
        sys.exit('gir opp...')

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)
    
    # write it to file
    # storeFile(htmlfile,result)

#-----------------------------------------
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)
Test her http://www.it.hiof.no/~borres/dw/xsl/page2/soccertestlxml.html
Referanser
  1. Saxon XSLT sourceforge.net sourceforge.net/projects/saxon 14-03-2010
  1. lxml - XML and HTML with Python lxml.de/ 03-08-2011

Filer til fotball eksempelet page2/fotballfiler.zip

Filer til olympiade eksempelet page2/olympiadefiler.zip

Vedlikehold
Børre Stenseth, feb 2003.
( Velkommen ) XSL > XSLT >Parametere ( Sortering )