2004-02-11
Het gebruik van exslt
Naar aanleiding van een vraag van Peter gistermiddag heb ik gisteravond een voorbeeld uitgewerkt van het gebruik van een van de belangrijkste xslt extensies. De essentie van de vraag was of het mogelijk is om een transformatie in twee (of meer) stappen uit te voeren binnen 1 xslt. Het antwoord daarop is in principe ja, maar er is een functie voor nodig die pas in xslt 2.0 standaard wordt. Veel xslt processoren hebben hem echter wel, of ze hebben er een workaround voor.Omdat de vraag voortkwam uit een discussie met Irene of er met een xslt een index op de rubriekendatabase gemaakt kon worden op basis van twee velden is het voorbeeld een xslt die een complete rubriekenlijst geeft, gevolgd door een engelstalige en een nederlandstalige index. De benodigde functionaliteit voor het aanroepen van de xslt extensies zit nog niet in WebQuery, en dat was meteen een aanleiding om te laten zien hoe je zoiets vanaf de linux command line kunt regelen. Voor degenen die meteen resultaten willen zien:xsltproc /DATA/www/WebQuery/xslt/rubriekenlijst-met-index.xslt "http://library.wur.nl/WebQuery/rubrik?wq_qry=isn%201%2f100&wq_fmt=xml&wq_sfx=XML"De xslt is voorzien van (hopelijk voldoende) commentaar. Toch wil ik er nog een aantal dingen aan toevoegen.Allereerst een motivatie voor het gebruik van de command line zoals hierboven. Op die manier kan je een dergelijke lijst ook heel eenvoudig automatisch elke dag/week/maand laten genereren als html file, door de output te redirecten en het geheel via een van de standaard schedulers (mijn voorkeur gaat uit naar cron, daar kom ik maandag op terug) op vaste momenten te laten uitvoeren. Vergelijkbaar met een job op de hp3000. Voor de hele rubrieken database duurt de query nu ongeveer 35 seconden, misschien net te lang om hem elke keer dat iemand hem nodig heeft uit te laten voeren. (het gaat hier uiteindelijk om een vervanging van een papieren versie; het zou me niet verbazen als hij meteen geprint wordt en dan pas een half jaar later weer eens opnieuw gevraagd wordt.Waarom niet cachen, zoals nu bij diverse toepassingen gebeurt? In de eerste plaats omdat ik vind dat dat een onjuist mechanisme is. Zoiets zou, als het al nodig is, binnen WebQuery, of nog beter, binnen Apache geregeld moeten worden, en niet binnen de toepassing. Daarnaast wordt steeds het zelfde wiel enigszins gewijzigd opnieuw uitgevonden, bewijst de huidige praktijk dat het (nog) niet probleemloos werkt, en de plaatsing van cache files op min of meer willekeurige plaatsen binnnen de website leidt tot security problemen.Dan nog een paar kanttekeningen bij de xslt. Ik heb geprobeerd daarin duidelijk te maken hoe je zo'n probleem (een basislijst met index(en)) kunt aanpakken, niet hoe je er een mooie lijst van maakt (de layout is zo simpel mogelijk).De basislijst maakt gebruik van het feit dat er in de database-uitvoer alleen tekst voorkomt binnen gewone velden en subvelden. Daardoor kan de volledige uitvoer ervan geregeld worden met het text() template. Dat drukt de naam van zijn parent node af, en zijn eigen inhoud. Zou er wel tekst (denk aan alleen maar een linefeed) op andere plaatsen kunnen voorkomen, dan wordt de uitvoer onleesbaar. "linefeed off" in de cgiparm file is dus een must voor deze oplossing.Nadat de basislijst gemaakt is komt de belangrijkste "truc". De variabele "index" wordt opgebouwd als result tree fragment. De templates die aangeroepen worden met mode="index" zorgen dus niet voor uitvoer in het eindresultaat, maar alleen voor het "vullen" van deze variabele.Ik heb gekozen voor een enkel template dat voor elke rubrieksnaam een keer wordt aangeroepen, met de taal en de code als parameters. Dat is m.i. de duidelijkste en meest declaratieve manier. Inplaats van de namen van alle velden had het match attribute ook "*" kunnen zijn, maar dit leek me duidelijker. Bij de aanroep is de taal als constante (dus als " ' e n ' " resp. " ' n l ' ") opgegeven, omdat die niet in de database voorkomt, maar afgeleid is uit de veldnaam.In het root template zou je na het aanmaken van de index deze kunnen controleren door de regeltoe te voegen. Daarmee zet je de volledige index als nodeset in de uitvoer. Dat komt dus (bijna) op het zelfde neer als wanneer de apply-templates die nu binnen de variabele-definitie staat daar buiten had gestaan.Helaas is dat ongeveer het enige dat je in xslt 1.0 met een result tree fragment, want dat is deze variable nu, kunt doen. Er is echter een extensie-functie die hem kan omzetten naar een node-set. Die gebruik ik in de rest van het root template tweemaal, een keer voor elke index. Omdat de attributen van het rubriek-element in de index-variabele alle gegevens bevat is de template die de uiteindelijk uitvoer ervan verzorgt nu heel eenvoudig.Ik hoop dat het bovenstaande weer wat vragen wegneemt. Het zal ongetwijfeld nieuwe oproepen, die hoor ik dan maandag wel. We zullen het dan, wat mij betreft, hebben over de manier waarop je regelmatig terugkerende zaken in unix kan regelen.Groeten,Age Jan
Subscribe to:
Post Comments (Atom)
No comments:
Post a Comment