2004-11-30

WebQuery 5.21

Op verzoek van Pauline nog wat extra informatie.

Query syntax:

nieuw: de impliciete OR werkt nu op basis van de veldnaam. Dat betekent dat het niet meer nodig is om daarvoor wq_val te gebruiken. Hiermee is de laatste noodzaak voor het gebruik van wq_fld/wq_val verdwenen. wq_fld en wq_val mogen (liever niet, natuurlijk) nog wel worden gebruikt, met dezelfde effecten als tot nu toe.
de bestaande eisen worden consequenter gecontroleerd
Dat betekent dat veldnamen ook echt moeten bestaan (wordt in mindbsrv nog niet gecontroleerd, aliassen worden in WebQuery nu wel gecontroleerd), Bij wq_fld en wq_lim komt dus nu een foutmelding als de bijbehorende aliasdefinitie (field xxx=yyy in de cgiparm file) er niet is.
Het betekent ook dat direct na een wq_rel een veldnaam moet komen (dus geen wq_rel, wq_max, etc.), en dat wq_val alleen mag volgen op wq_fld, wq_lim of een veldnaam, dus niet op wq_max, wq_rel etc.

Nog even iets over veldnamen en aliassen: WebQuery splitst de veldnaam in een naam en occurrence-informatie op basis van de underscore. Voor updates was dat al lang het geval, maar omdat in het post-minisis tijdperk de query op de zelfde manier naar de backend server gestuurd wordt als de update-gegevens gebeurt dat nu ook voor queries. Zet dus in veldnamen en aliassen nooit een underscore, dat kan later tot fouten leiden. Spaties mogen wel in aliassen, niet in veldnamen.

"field type publikatie=publikatietype" mag wel. WebQuery vervangt dan de alias "type publikatie" door de veldnaam "publikatietype" (bij minisis is dit onzin, omdat de veldnaam (de minisis mnemonic) maximaal 6 tekens lang is, bij oracle kan dit wel)
"field publikatietype=type publikatie" mag niet (spatie in de veldnaam)

Op dit moment werken aliassen alleen bij wq_fld en wq_lim.

Age Jan

2004-11-25

voorbeeld van het gebruik van zelfbedachte parameters in cgiparm file

Hopelijk ter verduidelijking van een van de minder bekende mogelijkheden van WebQuery het volgende naar aanleiding van een vraag die ik vanmiddag kreeg.

Soms is het handig om een zelfbedachte parameter te introduceren in de cgiparm file. Een voorbeeld daarvan is de situatie waarin je een aantal parameters meegeeft aan een xslt. In dat geval moet je er rekening mee houden dat alle xslt-parameters met de zelfde suffix (of zonder) samen één parameter zijn voor WebQuery. Als je een aantal xslt-parameters hebt die altijd de zelfde waarde hebben, en één die bij een aantal suffixen andere waarden heeft, moet je dus alle

xslt-parameters voor elke suffix opnemen, dus als de basisset xslt-parameters er uit ziet als:

xslt-parameter aap='aap'
xslt-parameter xslt='&&xslt;'
xslt-parameter service='&&SERVICE;'
xslt-parameter andere-service='&&SCRIPT_NAME;/andereservice'

en er in de praktijk tien verschillende mogelijkheden zijn voor de waarde van andere-service, moet je in totaal 40 xslt-parameter regels opnemen, vier voor elke mogelijke waarde van andere-service.

Niet dus... er is een andere mogelijkheid, die er maar 14 nodig heeft. Daarvoor wijzig je de laatste regel in

xslt-parameter andere-service='&&SCRIPT_NAME;/&&andereservice;'

waarmee je aangeeft dat je niet de tekst "andereservice" maar de inhoud van de cgiparm parameter "andereservice" wilt gebruiken. Vervolgens definieer je die voor elke suffix, dus bijvoorbeeld

andereservice standaard-andereservice
andereservice_een alternatieve-andereservice
andereservice_twee nog-een-andere
andereservice_drie &&SERVICE;
hetkannnogcomplexer derde-waarde

etc. Als wq_sfx=een wordt meegegeven, krijgt xs xslt-parameter "andere-service" dus de waarde 'alternatieve-andereservice' (inclusief de enkele quotes).

Zoals je ziet, kan je ook de waarde van de meeste andere cgiparm parameters, zoals de naam van de gebruikte xslt ook meegeven als xslt-parameter.

Age Jan

2004-11-15

Overbodige variabelen in xslt's

Bij het beantwoorden van een vraag van Marc viel mijn oog (in dit geval in sfx-button.xslt) op een sutiatie die ik de laatste tijd vaker tegenkwam, waarin eerst een variabel wordt gevuld, die dan vervolgens wordt afgedrukt, zoals in het volgende fragment:
<xsl:when test="artikel/auteur/corporatie/naam and artikel/auteur/corporatie/naam!=''"><xsl:variable name="must-urlencode-it">
<xsl:call-template name="urlencode">
<xsl:with-param select="artikel/auteur/corporatie/naam" name="string">
</xsl:call-template>
</xsl:variable>
<xsl:text>&aulast=</xsl:text>
<xsl:value-of select="$must-urlencode-it">
</xsl:when<>/xsl:value-of></xsl:with-param>
Dit fragment doet precies het zelfde als het volgende:
<xsl:when test="artikel/auteur/corporatie/naam and artikel/auteur/corporatie/naam!=''">
<xsl:text>&aulast=</xsl:text>
<xsl:call-template name="urlencode">
<\xsl:with-param select="artikel/auteur/corporatie/naam" name="string">
</xsl:call-template>
</xsl:when></xsl:with-param>
en omdat lege velden niet in de database mogen voorkomen kan het nog eenvoudiger:
<xsl:when test="artikel/auteur/corporatie/naam">
<xsl:text>&aulast=</xsl:text>
<\xsl:call-template name="urlencode">
<xsl:with-param select="artikel/auteur/corporatie/naam" name="string">
</xsl:call-template>
</xsl:when></xsl:with-param>
Vooral omdat het in dit geval gaat om de inhoud van een attribuut, waardoor xmlspy tientallen van dit soort constructies op één regel zet, zou ik iedereen willen vragen niet alleen te zoeken naar een constructie die werkt, maar ook even na te denken over de vraag of het niet eenvoudiger kan. Hier scheelt het m.i. behoorlijk in de leesbaarheid, en dus in de onderhoudbaarheid.
Age Jan

2004-09-28

WebQuery batch interface

Op verzoek van Peter heb ik, op basis van de scripts die ik op de HP3000 gebruikte voor het testen van WebQuery, een script gemaakt waarmee je WebQuery redelijk eenvoudig in een shellscript kunt aanroepen. Het staat in /usr/local/bin op de lx1 en is dus zonder enige aanpassing voor iedereen bruikbaar.
De aanroep is: WebQueryGet <webqueryservice><query>Of : WebQueryPost <webqueryservice><query>
(inderdaad, twee namen voor één script, de eerste voor een GET, de tweede voor een POST)
In beide gevallen zijn de zelfde twee parameters nodig:
Met <webqueryservice>bedoel ik de naam die in de websituatie gebruikt wordt na /WebQuery/ . De query moet op dezelfde manier gegeven worden als in een normale GET.
Cookies worden vastgehouden in een tijdelijk bestand waarvan de naam is afgeleid van de het procesnummer van de shell van waaruit je het script aanroept. Dat betekent dat je die kunt terugvinden via die shell. Vanuit die shell is die file bereikbaar is met de naam "/tmp/WQ$$.cookie". Het script gebruikt uit die file het WebQueryDatabase cookie, zodat je ook secured databases kunt benaderen via een username. Geef daarvoor de volgende twee opdrachten binnen dezelfde shell:
1) WebQueryPost "" "@=login&A=<denaamvandegebruiker>&B=<zijnofhaarpassword>"
Waarbij de < > en wat er tussen staat vervangen worden door resp. gebruikersnaam en password.
2) de WebQueryPost of WebQueryGet waarmee je de database raadpleegt of wijzigt.

De uitvoer van het script verschijnt in stdout, eventuele foutmeldingen in stderr. Het is dus verstandig om die met redirects en/of een pipe verder te verwerken.
Een voorbeeld dat het resultaat neerzet in de file resultaat en fouten meldt in de file foutmeldingen is:
WebQueryGet "clcwww" "ti=water&ti=oil" >resultaat 2>foutmeldingen

Age Jan

2004-08-23

eenvoudiger minisis conversie xslt

Op verzoek van Peter heb ik een mogelijkheid in WebQuery ingebouwd om de minisis-conversie te vereenvoudigen. Geen gedoe meer met aanroepen van de minisis-conversie template in je eigen templates. Als in een cgiparm-file een sterretje vóór de servernaam hp3000.library.wur.nl gezet wordt, doet WebQuery een automagische conversie, dat wil zeggen dat de conversie uitgevoerd wordt zonder dat je er verder iets voor hoeft te doen resp mag doen. Je xslt krijgt dan ALTIJD een geconverteerd bestand aangeboden. Zelfs met wq_sfx=XML wordt de conversie uitgevoerd.
Als voorbeeld heb ik de ejournals.xslt uit de testomgeving gekopieerd naar xxxejournals.xslt, en de wwwsrc.WebQuery cgiparm file naar wwwsrcc.WebQuery. Die kopieen werken op de nieuwe manier, als je tenminste ook nog de testversie (5.19) van WebQuery (dus bijvoorbeeld
http://test.library.wur.nl/test/WebQuery/wwwsrcc?ti=science&wq_max=10&wq_fmt=xml ) gebruikt.

Age Jan

2004-08-17

WebQuery Request cookie problemen

Vanmorgen bleek bij het uietzoeken van een support call dat het WebQueryRequest cookie, dat gezet wordt als iemand een database probeert te benaderen zonder op de juiste manier te zijn ingelogd, soms ongewenste bij-effecten heeft.
Het werkt als volgt: als een niet-toegankelijke pagina wordt benaderd wordt het WebQueryRequest cookie meegegeven, waarin staat wat er niet lukte. Meestal wordt dan een login pagina getoond. Na het inloggen wordt dan de mogelijkheid gegeven om de oorspronkelijke pagina opnieuw op te roepen, of wordt dat automatisch gedaan.
Het probleem is, dat als, zoals op de desktop, geen login pagina getoond wordt (maar de "my library" login knop), het WebQueryRequest cookie nog een tijd blijft bestaan. Wordt binnen die tijd een (niet aan de vorige pagina gerelateerde) login pagina getoond, bijvoorbeeld die van wurpubrd, dan zal, omdat het cookie voorrang heeft boven de eventueel in die pagina aanwezige C- en D velden, gecontroleerd worden of de voorgaande pagina (in het vorbeeldgeval een profielu pagina) nu wel toegankelijk is. Als dit niet het geval is verschijnt een foutmelding, die aangeeft dat een voor de gebruiker nu niet relevante pagina niet toegankelijk is.
Omdat WebQuery niet kan weten of het WebQueryRequest cookie door zo'n constructie zinloos geworden is, is op dit moment de enige oplossing om eerst expliciet uit te loggen en dan opnieuw in te loggen (uitloggen verwijdert het cookie). Een betere oplossing is m.i. om in de desktop op een andere manier te controleren of iemand is ingelogd. Daarvoor zou het in 5.17 geintroduceerde WebQueryUser cookie gebruikt kunnen worden, of een ander soort who-am-i uitvoer.
Wat is jullie mening hierover?
, Age Jan

WebQuery 5.18

Zojuist heb ik WebQuery 5.18 geactiveerd. Deze versie bevat twee langverwachte nieuwe query-parameters: wq_inf en wq_par.
De waarde die aan wq_inf wordt meegegeven wordt door WebQuery wel als query-element gezien, maar er wordt NIETS mee gedaan. Hij wordt dus ook niet doorgegeven aan de database-server. Maar omdat je in de cgiparm file nu ook alle query-elementen kunt benaderen kan je hem bijvoorbeeld wel doorgeven aan een xslt als xslt-parameterwaarde. Het voorbeeld:
xslt-parameter css='rsc/stijl/&&wq_inf1;_01.css'
Zorgt ervoor dat je via een dropdown box de kleur van de toegepaste standaardstijl kunt wijzigen. Dat geeft gelijk aan dat je eigenlijk verplicht bent om in de xslt te controleren of een op die manier doorgegeven variabele een geldige waarde heeft, want de eindgebruiker kan er in principe ALLES in zetten. Door volgnummers te gebruiken kan je meer dan één wq_inf waarde gebruiken. Het oneigenlijk gebruik van de gewone query-elementen om iets aan een xslt door te geven kan dus weggewerkt worden.
De waarde die aan wq_par wordt meegegeven moet er één zijn uit het volgende rijtje: "open", "(", "close", ")". Hiermee kan je prioriteiten aangeven binnen de query. Deze functionaliteit vervangt die van wq_lim. Voorlopig blijft wq_lim als invoer nog wel ondersteund; intern wordt het omgezet naar wq_par's.
Als gevolg van deze twee wijzigingen kan ik geen enkele reden meer bedenken om wq_qry nog te gebruiken, afgezien van de drie redenen waarom die mogelijkheid bestaat, namelijk het HANDMATIG geven van een complete query DOOR DE EINDGEBRUIKER, het weergeven van de query op het scherm en (voorlopig nog) het via een hidden field doorgeven van de "previous query" aan de volgende WebQuery call. Omdat de inhoud van het wq_qry element afhankelijk is van de achterliggende database-server zal elk ander gebruik van wq_qry op enig moment zonder nadere aankondiging tot problemen leiden.
Het probleem dat de impliciete OR (een veld gevolgd door eeen of meer "losse" wq_val elementen) niet van haakjes voorzien werd is eveneens opgelost.
De controle van de meegegeven query-elementen is iets aangepast, waardoor verkeerd geplaatste variabelen een betere foutmelding geven.
De debug-info wordt nu in xml gegeven (uiteraard alleen in debug-mode). Debug-mode is nu ook onafhankelijk van je ip-adres in te stellen met "wq_dbg=on" (zet dat svp NOOIT in een productie-pagina, want dan krijgt iedereen het te zien)
Met vriendelijke groet,
Age Jan Kuperus

2004-02-17

browsers en character sets

De bekende "browsers" gaan verwarrend en inconsequent om met charactersets. Als gevolg daarvan krijgt WebQuery problemen bij het invoeren van gegevens via formulieren. De theoretische oplossing is toevoeging van het attribuut accept-charset="iso-8859-1" aan alle formulierdefinities. Bij Mozilla en wellicht ook bij alle andere echte webbrowsers lost dit in één klap het probleem op. Bij de Internet Exploder van Microschoft natuurlijk niet, want die trekt zich van standaards nooit wat aan. Als het formulier op een html pagina staat (daarbij geeft Apache altijd aan dat het iso-8859-1 is), wordt ook iets dergelijks teruggegeven (zoals bekend met een paar niet-standaard tekens in de reeks 0x80-0x9f). Als het formulier op een pagina staat die door WebQuery of php in utf-8 gemaakt wordt, wordt echter utf-8 teruggestuurd, ongeacht of er accept-charset="iso-8859-1" in de fom tag staat of niet.
We hebben een aantal mogelijkheden om dit probleem aan te pakken:
  1. IE uitbannen. Dit heeft mijn voorkeur maar is helaas niet realistisch in onze omgeving.
  2. Idem, maar alleen voor het invoeren en wijzigen. Onhandig voor de gebruiker.
  3. Altijd iso-8859-1 genereren in WebQuery en php scripts. Voor mij is dit de tweede keus, maar ik weet niet hoeveel extra werk dat oplevert.
  4. Een hidden field met een vaste naam en inhoud opnemen in elk formulier, waarmee we kunnen testen wat er teruggegeven wordt, en op basis waarvan we dan een extra vertaalslag inbouwen van utf-8 naar iso-8859-

1. Technisch haalbaar, maar niet-standaard, niet 100% zeker, en levert extra werk op. Wat mij betreft hooguit als noodoplossing.
Verwachten jullie problemen bij oplossing 3, of hebben jullie zelf een ander voorkeur? , Age Jan

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