2005-08-31

Gebruik van XML, XSLT en XHTML binnen Bibliotheek Wageningen UR

een voorstel voor verdergaande standaardisatie en uniformiteit.


Langzamerhand is binnen de afdeling een redelijke hoeveelheid ervaring opgedaan met het gebruik van XML en daarvan afgeleide technologie. Steeds weer blijkt echter dat hergebruik niet of alleen met veel extra inspanning mogelijk is. De voorstellen in dit document zijn gericht op betere herbruikbaarheid en structurering van de verschillende documenten.

XML


De huidige en toekomstige versies van WebQuery genereren in vergelijking tot de oude beter gestandaardiseerde XML. Bij de conversie naar XML en ander onderhoud waarbij de database nog in MINISIS blijft, is het handig daar vast rekening mee te houden door via de cgiparm file de nieuwe situatie zoveel mogelijk te benaderen. Dat houdt onder meer in:

  • gebruik voor het recordsetelement altijd de naam xxxset,
    en voor de recordelementen de naam xxx (dat laatste gebeurt automatisch bij wq_sfx=XML), waarin xxx staat voor de naam van de minisis database.

  • gebruik op het recordniveau uitsluitend de elementen die in de nieuwe situatie ook gegenereerd zullen worden, en geef ze inhoud conform de nieuwe situatie. Het gaat
    om de volgende elementen:
    • error
    • query
    • queryinfo (nog niet gebruiken, wordt in de nieuwe situatie altijd gegenereerd en bevat de query in gestructureerde vorm)
    • hits
    • xxx (de echte records, zie boven)
    • next
    • debug (niet gebruiken, wordt in de nieuwe situatie gegenereerd als om debugginginformatie gevraagd wordt)
  • gebruik zo min mogelijk verschillende (database)namen voor de zelfde gegevens. In de nieuwe situatie wordt altijd de naam van de tabel zelf gebruikt, ook bij joins.

XSLT


  • Genereer zo mogelijk XML of XHTML.
  • Valideer de gegenereerde uitvoer (als dat kan).
  • Structureer de XSLT's zoveel mogelijk. Dat betekent onder meer:

    • maak voor elke waarde van wq_sfx een aparte xslt. Weersta de verleiding om
      xslt's te combineren omdat er zoveel op de zelfde manier moet. Maak in dat geval
      eventueel een aparte xslt voor de gemeenschappellijke delen. Vaak is dat niet
      nodig; zet dan de gemeenschapplijke templates in de xslt met het kleinste aantal
      “eigen” templates of in de meestgebruikte, en importeer die in de andere xslt's.

    • maak templates zo klein mogelijk, zodat ze één element of attribuut behandelen.
      Gebruik voor de onderliggende elementen/attributen waar mogelijk “applytemplates”.
      Door die in de ogen van sommigen “extreme” uitsplitsing maak je niet
      alleen hergebruik eenvoudiger, maar je templates worden simpeler, omdat je veel
      minder conditionele statements nodig hebt (realiseer je dat een template alleen
      wordt gebruikt als het betreffende element voorkomt. De constructie waarbij een
      template wordt aangeroepen na een test op aanwezigheid van het betreffende
      element is principieel fout. Testen op afwezigheid (en dan iets met een ander
      element doen) kan wel zinvol zijn, maar is vaak niet nodig (bv. als altijd exact één
      van de twee aanwezig moet zijn).

    • kleine templates zijn beter leesbaar voor anderen dan grote. Fouten zijn daardoor
      eenvoudige op te sporen.

    • als je in een template de functionaliteit nodig hebt van een reeds bestaand
      template, maak daar dan zo mogelijk geen kopie van, maar gebruik het origineel
      als subtemplate:

      1. roep het aan via applyimports select=”.”

      2. geef het nieuwe template een andere mode mee, en roep het oude aan via
        applytemplates select=”.” (zonodig inclusief mode)

      3. doe het NIET met calltemplate als het ook met applytemplates kan.

    • maak gebruik van de importhiërarchie. Geïmporteerde templates, maar ook
      geïmporteerde globale parameters en variabelen hebben per definitie een lagere
      prioriteit dan die in de xslt waaarin ze geïmporteerd worden. Je kunt dus
      bijvoorbeeld in een algemeen bruikbare xslt (zie default.xslt) standaardwaarden
      zetten en die in een andere xslt overschrijven waar dat nodig is (zie bv.
      wwwtest.xslt en wwwtestupdate.xslt, die heel simpel zijn omdat ze voor vrijwel
      alles de functionaliteit van default.xslt gebruiken)

    • importeren van xslt's is meestal een betere manier van hergebruik dan kopieren
      en aanpassen.

    • maak voor de volgende pagina en andere links naar de zelfde tabel gebruik van
      de standaardparameter
      “service”, die vanaf WebQuery 5.28 altijd automatisch
      wordt meegegeven aan de xslt.

    • probeer zoveel mogelijk te generaliseren en via de cgiparm file te parametriseren.

    • gebruik zo min mogelijk parameters. Dat klinkt tegenstrijdig met het vorige punt,
      maar is het niet. Waar het om gaat is dat je nagaat of het nodig of zinvol kan zijn
      om iets variabel te maken, en hoe dat dan zou moeten. Soms is het beter een
      template voor een andere situatie te herschrijven in een andere xslt. Door goed
      structureren (imports) kan je ervoor zorgen dat de onderliggende templates weer
      wel uit de originele xslt gebruikt worden.

  • documenteer de templates door er boven te zetten waar ze voor bedoeld zijn. Niet
    door te zeggen wat ze doen (dat vertelt de code beter), maar door te zeggen wat
    daarvoor de reden is. Geef ook aan waar eventuele parameters voor gebruikt worden. Beperk de documentatie binnen de template tot het absolute minimum; het maakt het template per definitie minder leesbaar. Als het zou leiden tot betere leesbaarheid is het template te complex.

  • Denk na over de naamgeving, zowel van de templates als van de xsltfiles.
    Begin de naam van een xsltfile met de naam van de service waarvoor hij bedoeld is. Dat is in de nieuwe situatie altijd de enkelvoudvorm van een nederlandstalig zelfstandig
    naamwoord. Zet daarachter de elementengroep of de WebQuery suffix waarvoor het
    ding bedoeld (of beide: eerst de groep en dan de suffix, bv. titelbeschrijvingauteurkort.
    xslt). Combineer algemeen bruikbare templates (en algemeen bruikbaar
    betekent onder meer: onafhankelijk van de gebruikte service) tot zinvolle groepen en
    geef die een zinvolle naam, die in één taal aangeeft waarvoor ze bedoeld zijn. Dus
    niet “libraryauteur.xslt” maar “auteurkort.xslt” of “auteur.xslt”. Zo'n algemene naam
    kan NIET gebruikt worden voor templates die alleen voor auteurs uit de titelbeschrijvingservices gebruikt kunnen worden. In dat geval is “titelbeschrijvingauteur.
    xslt” een betere keuze. Voor de meeste templateverzamelingen zal iets dergelijks gelden, echt universeel bruikbare templates zijn helaas zeldzaam.

XHTML


XHTML wijkt op een aantal punten af van zijn voorganger, HTML 4.0. Omdat het xml is, wordt een aantal dingen strenger gecontroleerd. Daarom, en ter bevordering van de modulariteit, de volgende eisen en wensen:
  • geef in de XSLT aan dat de output XML is en geen HTML. De versie daarvan is dan ook 1.0 en niet 4.0.

  • schrijf elementen attribuutnamen altijd in kleine letters (voor xhtml is dat verplicht).

  • regel alle style attributen via een extern css style sheet waarnaar je in de html
    header verwijst. Gebruik ook voor de stylenamen uitsluitend kleine letters (sommige
    browsers maken wel, andere geen onderscheid tussen kleine letters en hoffdletters).

  • maak voor scripting gebruik van een externe scriptfile waarnaar je in de html header verwijst. Zet in event handlers (onclick etc.) geen complete scripts, maar alleen een aanroep van een functie.

    Een voorbeeld


    Voorbeelden hebben het nadeel dat ze vaak zonder nadenken gekopieerd en vervolgens aangepast worden totdat het resultaat werkt. Dat is hier uitdrukkelijk niet de bedoeling. Het onderstaande voorbeeld is op dit moment in gebruik voor de services
    wwwtest en titel, en daarmee voor allerlei verschillende testsituaties met verschillende
    databasetabellen. Het is voor een nieuwe service eenvoudig te gebruiken als
    generieke invoeren controleapplicatie, en als basis voor andere applicaties.
    Ongetwijfeld valt er nog het een en ander aan te verbeteren; het gaat echter om de
    algemene bruikbaarheid en de modulaire uitwerking van de functionaliteit.
    Het bestaat uit de volgende bestanden (zie bijlagen)

    • cgiparm files: wwwtest.WebQuery, titel.WebQuery

    • hulpbestand: recorddefinitions.
      xml

    • xslt files: default.xslt, defaultupdate.
      xslt, wwwtest.xslt


    Bijlage 1: wwwtest.WebQuery



    security on
    service wwwtest
    server db1.library.wur.nl
    xslt xslt/wwwtest.xslt
    xslt_html -
    #
    xslt_debug xslt/debug.xslt
    xslt_result xslt/wwwtest-result.xslt
    xslt_update xslt/wwwtest-update.xslt
    #
    xslt-parameter css='/css/WebQuery.css'
    xslt-parameter title='&&extra;'
    xslt-parameter script='no-script-just-testing'
    xslt-parameter browser='&&HTTP_USER_AGENT;'
    extra xslt: &&xslt;
    extra_test andere tekst bij suffix test

    Opmerkingen bij de bovenstaande regels:

    • WebQuery genereert zelf de xsltparameters “service” en “user”. Daarom mogen die
      niet in de cgiparmfile staan.

    • De “extra” regels worden in het voorbeeld niet volledig gebruikt; ze zijn een voorbeeld van een al langer bestaande maar relatief onbekende methode om de parameters slechts éénmaal te hoeven definiëren en toch bij de suffix “test” een
      andere titel te krijgen. In dat geval wordt bij het uitwerken van de xsltparameter
      “title” de regel “extra_test” gebruikt in plaats van de regel “extra”.


    Bijlage 2: titel.WebQuery



    server db1.library.wur.nl
    service titel
    security update
    xslt_pauline xslt/titelplus.xslt
    xslt xslt/debug.xslt
    hit-limit 500,10
    xslt_short xslt/cms_demo_short.xslt
    xslt_full xslt/cms_demo_full.xslt
    xslt_boolean xslt/boolean.xslt
    field ti=titel
    field au=auteur
    field dt=documenttype
    xslt-parameter css='/css/WebQuery.css'
    xslt-parameter title='&&extra;'
    xslt_wwwtest xslt/wwwtest.xslt
    xslt_update xslt/default-update.xslt
    extra titelbeschrijving
    extra_update titelbeschrijving update

Opmerkingen bij de inhoud van dit bestand (zie ook bijlage 1):


  • Gebruik de suffix “wwwtest” om te testen met de “default” xslt's.

  • De “extra” regels worden hier gebruikt om de titel bij update aan te passen.


Bijlage 3: recorddefinitions.xml


Dit bestand bevat de voor het update template benodigde informatie uit de xsd's,
aangevuld met opmaakgegevens. Per tabel is er een recorddefinition element.
Hieronder volgt een deel van het bestand (“...” staat voor een aantal weggelaten
regels):


<?xml version="1.0" encoding="ISO-8859-1"?>

<recorddefinition-set>
...
<recorddefinition name="titelbeschrijving">
<field name="documenttype" type="text" size="10"/>
<group name="artikel">
<group name="titel">
<group name="origineel" repeat="yes">
<field name="begintekst" type="text" size="50"/>
<field name="tekst" type="text" size="3000"/>
<field name="auteursvermelding" type="text" size="200"/>
</group>
<field name="engels" type="text"/>
</group>
<group name="auteur">
<group name="persoon" repeat="yes">
<field name="achternaam" type="text" size="50"/>
<field name="voorletters" type="text" size="30"/>
<field name="voorvoegsels" type="text" size="30"/>
<field name="functie" type="text" size="10"/>
<field name="titulatuur" type="text" size="20"/>
</group>
<group name="corporatie" repeat="yes">
<field name="naam" type="text" size="150"/>
<field name="plaats" type="text" size="36"/>
<field name="land" type="text" size="2"/>
<field name="code" type="text" size="6"/>
<field name="afdeling" type="text" size="100"/>
</group>
<group name="affiliatie">
<field name="naam" type="text" size="150"/>
<field name="plaats" type="text" size="36"/>
<field name="land" type="text" size="2"/>
<field name="code" type="text" size="6"/>
<field name="afdeling" type="text" size="100"/>
</group>
</group>
<group name="collatie">
<field name="paginering" type="text" size="40"/>
<field name="illustraties" type="text" size="60"/>
<field name="formaat" type="text" size="20"/>
<field name="begeleidend" type="text" size="40"/>
</group>
<field name="jaar" type="text" size="40"/>
<field name="deel" type="text" size="40"/>
<field name="nummer" type="text" size="40"/>
</group>
<group name="monografie">
...
</group>
...
</recorddefinition>
<recorddefinition name="wwwtest">
<field name="elem" type="textarea" rows="3" cols="100"/>
<field name="repeat" type="textarea" rows="5" cols="100" repeat="yes"/>
<group name="veld3">
<field name="sub1" type="text" size="50"/>
<field name="sub2" type="text" size="50"/>
<field name="sub3" type="text" size="50"/>
</group>
<group name="repsub" repeat="yes">
<field name="rsub1" type="text" size="50"/>
<field name="file01" type="file" size="50" boxtext="(check to remove this
occurrence)"/>
<field name="rsub3" type="text" size="50"/>
</group>
</recorddefinition>
</recorddefinition-set>



Bijlage 4: default.xslt



<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xml:space="default">

<!--default xslt voor gebruik met WebQuery-->
<xsl:output method="xml" version="1.0" encoding="ISO-8859-1" indent="yes" doctype-public="-//W3C//DTD XHTML 1.0
Strict//EN" doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd" omit-xml-declaration="no"/>
<!--Dit stylesheet is bedoeld als basis voor alle andere stylesheets. Het bevat defaults voor alle door WebQuery en wqoracle gegenereerde elementen, en voor de "standaard" door wqstub/mindbsrv gegenereerde elementen. Om de match-regels overzichtelijk te houden en overrides in andere templates te vereenvoudigen zijn verschillende modes gebruikt voor recordset, record en velden:
recordset: mode="recordset"
record: mode="record"
velden: default mode
De vormgeving van de html-elementen is geregeld via class attributen, zodat ze via een css kunnen worden aangepast.
Ten behoeve van het testen hebben alle templates een naam, die in de output als xml-commentaar wordt weergegeven. De templates worden nooit via deze naam (met call-template) aangeroepen, maar altijd via de match parameter (met apply-templates of apply-imports). De enige uitzondering op deze regel is het script-ref template, omdat daarin geen xml element maar een variabele verwerkt wordt.
Gebruikte xslt-parameters:
service = de gebruikte WebQuery service. Wordt standaard door WebQuery (5.28+) meegegeven
title = de te gebruiken titel. Kan in de cgiparm file worden meegegeven. Indien niet
meegegeven, wordt 'WebQuery' als titel weergegeven.
css = de te gebruiken cascasding style sheet. Kan in de cgiparm file worden meegegeven.
Indien niet meegegeven, wordt '/css/WebQuery.css' gebruikt.
script = de te gebruiken (java)script-file. Kan in de cgiparm file worden meegegeven.
Indien niet meegegeven, wordt geen scriptfile gebruikt.
-->

<xsl:param name="service" select="'/WebQuery'"/>
<xsl:param name="title" select="'WebQuery'"/>
<xsl:param name="css" select="'/css/WebQuery.css'"/>
<xsl:param name="script"/>
<!--
template voor het root element
Dit template bevat de basis html (header en body tags). De header kan via xslt-parameters in de
cgiparm file worden aangepast. Voor niet meegegeven parameters worden de volgende defaults gebruikt:
xslt-parameter title='WebQuery'
xslt-parameter css='/css/WebQuery.css'
Voor script is de default dat er geen script wordt gebruikt.
-->
<xsl:template match="/" name="default-root">
<xsl:comment>default-root</xsl:comment>
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<link rel="stylesheet" type="text/css" href="{$css}"/>
<title>
<xsl:value-of select="$title"/>
</title>
<xsl:call-template name="script-ref">
<xsl:with-param name="script" select="$script"/>
</xsl:call-template>
</head>
<body class="page">
<xsl:apply-templates mode="recordset"/>
</body>
</html>
</xsl:template>
<!--
template voor de recordset
Dit template maakt een tabel waarin de records worden getoond, en de eerste regel van die tabel,
met de naam van de recordset.
-->
<xsl:template match="*" mode="recordset" name="default-recordset">
<xsl:comment>default-recordset; node='<xsl:value-of select="name()"/>'</xsl:comment>
<table class="status">
<tr class="page">
<td class="label">
<xsl:value-of select="name()"/>
</td>
</tr>
<xsl:apply-templates mode="record"/>
</table>
</xsl:template>
<!--
record level templates
Dit zijn templates voor alle elementen op het record niveau: error, hits, next, debug, query,
queryinfo en (als default) het record zelf.
error toont de onderliggende structuur (attributen en elementen) in tabelvorm.
hits toont een tabelregel met het aantal gevonden records. Omdat dit nooit nul kan zijn
(in dat geval wordt een error element gegenereerd) wordt alleen gecontroleerd of er
exact 1 record is, en dan de meervouds-s weggelaten.
next onderscheidt de twee mogelijke vormen: de oude (minisis) vorm iwordt herkend aan het
bestaan van het isn attribuut.
debug wordt genegeeerd, evenals
query en
queryinfo
* (de echte records) worden weergegeven als nieuwe tabel in een regel van de bovenliggende.
-->
<xsl:template match="error" mode="record" name="default-error">
<xsl:comment>default-error></xsl:comment>
<tr class="error">
<td>
<xsl:apply-templates select="@*"/>
<xsl:apply-templates/>
</td>
</tr>
</xsl:template>
<!--
-->
<xsl:template match="hits" mode="record" name="default-hits">
<xsl:comment>default-hits</xsl:comment>
<tr class="hits">
<td class="label">
</td>
<td>
<xsl:value-of select="."/>
<xsl:text> record</xsl:text>
<xsl:if test=". != '1'">
<xsl:text>s</xsl:text>
</xsl:if>
<xsl:text> found</xsl:text>
</td>
</tr>
</xsl:template>
<!--
-->
<xsl:template match="next" mode="record" name="default-next">
<xsl:comment>default-next</xsl:comment>
<tr class="next">
<td class="label">
</td>
<td>
<xsl:choose>
<xsl:when test="@isn">
<a href="{@service}/{@isn}?{.}">more...</a>
</xsl:when>
<xsl:otherwise>
<a href="{$service}?wq_qry={../query}&wq_ofs={./@wq_ofs}&wq_max={./@wq_max}">more...</a>
</xsl:otherwise>
</xsl:choose>
</td>
</tr>
</xsl:template>
<!--
-->
<xsl:template match="debugqueryqueryinfo" mode="record" name="default-special">
<xsl:comment>default-special></xsl:comment>
<!-- just ignore these elements -->
</xsl:template>
<!--
-->
<xsl:template match="*" mode="record" name="default-record">
<xsl:comment>default-record; node='<xsl:value-of select="name()"/>'</xsl:comment>
<tr>
<xsl:attribute name="class"><xsl:choose><xsl:when test="position() mod 2 =
1">rowodd</xsl:when><xsl:otherwise>roweven</xsl:otherwise></xsl:choose></xsl:attribute>
<td class="label">
<xsl:value-of select="name(.)"/>
</td>
<td>
<table class="status">
<xsl:apply-templates select="@*"/>
<xsl:apply-templates/>
</table>
</td>
</tr>
</xsl:template>
<!--
-->
<!--
field level templates
* is identiek aan het template voor een record, afgezien van de mode.
@* toont het attribuut in een tabelregel
-->
<xsl:template match="*" name="default-all-elements">
<xsl:comment>default-all-elements; node='<xsl:value-of select="name()"/>'</xsl:comment>
<tr>
<xsl:attribute name="class"><xsl:choose><xsl:when test="position() mod 2 =
1">rowodd</xsl:when><xsl:otherwise>roweven</xsl:otherwise></xsl:choose></xsl:attribute>
<td class="label">
<xsl:value-of select="name(.)"/>
</td>
<td>
<table class="status">
<xsl:apply-templates select="@*"/>
<xsl:apply-templates/>
</table>
</td>
</tr>
</xsl:template>
<!--
-->
<xsl:template match="@*" name="default-all-attributes">
<xsl:comment>default-all-attributes; node='<xsl:value-of select="name()"/>'</xsl:comment>
<tr class="attribute">
<td class="label">
<xsl:value-of select="name(.)"/>
</td>
<td class="data">
<!-- xsl:apply-templates/ here generates a loop in libxslt; WHY ?? -->
<xsl:value-of select="."/>
</td>
</tr>
</xsl:template>
<!--
template voor het refereren naar een script
Deze code had ook rechtstreeks in het root template kunnen staan. Er is hier toch gekozen voor
een eigen template om in een aanroepend template eenvoudig iets anders te kunnen doen, bijvoorbeeld
als er van een andere scripttaal gebruik gemaakt wordt.
-->
<xsl:template name="script-ref">
<xsl:param name="script"/>
<xsl:comment>default-script-ref; script='<xsl:value-of select="$script"/>'</xsl:comment>
<!--
-->
<xsl:if test="$script">
<!--
volgens de html4.0 standaard moet de browser een eventuele inhoud van de script tag negeren
als het src attribute aanwezig is. Het is dus zinloos om daar iets in te zetten (bv.
"script niet gevonden"), omdat de browser dat NOOIT zal mogen laten zien.
-->
<script type="text/javascript" src="{$script}"/>
</xsl:if>
</xsl:template>
<!--
-->
</xsl:stylesheet>
Bijlage 5: defaultupdate.
xslt
<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xml:space="default">
<!--
default xslt voor updates met WebQuery
-->
<xsl:import href="default.xslt"/>
<!--
-->
<xsl:output method="html" version="4.0" encoding="ISO-8859-1" indent="yes" doctype-public="-//W3C//DTD XHTML 1.0
Strict//EN" doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd" omit-xml-declaration="no"/>
<!--
Gebruikte parameters:
service = de gebruikte WebQuery service. Wordt standaard door WebQuery (5.28+) meegegeven
title = de te gebruiken titel. Kan in de cgiparm file worden meegegeven. Indien niet
meegegeven, wordt 'WebQuery' als titel weergegeven.
css = de te gebruiken cascasding style sheet. Kan in de cgiparm file worden meegegeven.
Indien niet meegegeven, wordt '/css/WebQuery.css' gebruikt.
script = de te gebruiken (java)script-file. Kan in de cgiparm file worden meegegeven.
Indien niet meegegeven, wordt geen scriptfile gebruikt.
Dit stylesheet verwacht een record definitie in het document 'record-definitions.xml' in deze directory
-->
<xsl:variable name="record-definition" select="document('record-definitions.xml')/recorddefinition-set"/>
<!--
record level templates
De op recordniveau mogelijke standaardelementen worden verwerkt door de default templates.
Omdat er in deze file ook een * template bestaat moet hier expliciet een apply-imports worden
uitgevoerd (of geprutst worden met prioriteiten, maar dat vond ik minder duidelijk).
-->
<xsl:template match="debugerrorhitsnextqueryqueryinfo" mode="record" name="special-record-update">
<xsl:apply-imports select="." mode="record"/>
<!-- use defaults -->
</xsl:template>
<!--
Het basisidee achter de overige templates in dit stylesheet is dat afwisselend de record-definitie
en het werkelijke record bekeken worden. Daartoe wordt het huidige record in een variabele gezet,
die als parameter aan het processing template wordt meeegegeven. Om alles goed te kunnen onderscheiden
worden de modes update en update-def gebruikt.
Het record-template geeft de besturing door aan het processing template. Dat bekijkt voor elk
gedefinieerd veld of het voorkomt. Zo ja, dan krijgt dat de besturing, en anders wordt een leeg
formulierveld gemaakt. Voor herhaalbare processing template altijd een leeg formulierveld aan.
Op groepsniveau werkt het om een soortgelijke manier.
-->
<xsl:template match="*" mode="record" name="default-record-update">
<xsl:comment>default-record-update; node='<xsl:value-of select="name()"/>'</xsl:comment>
<xsl:variable name="database-record" select="current()"/>
<tr>
<xsl:attribute name="class"><xsl:choose><xsl:when test="position() mod 2 =
1">rowodd</xsl:when><xsl:otherwise>roweven</xsl:otherwise></xsl:choose></xsl:attribute>
<td>
<form action="{$service}/update/{@isn}" method="post" accept-charset="UTF-8" enctype="multipart/form-data">
<table class="status">
<tr class="attribute">
<td class="label">
<xsl:value-of select="name($database-record)"/>
</td>
<td class="label">
<xsl:apply-templates select="@*" mode="update"/>
</td>
</tr>
<xsl:for-each select="$record-definition/recorddefinition[@name=name($database-record)]">
<xsl:apply-templates mode="update-def">
<xsl:with-param name="database-record" select="$database-record"/>
</xsl:apply-templates>
</xsl:for-each>
<tr>
</tr>
<tr>
<td class="label">
</td>
<td>
<input name="wq_crc" type="hidden" value="{@crc}"/>
<input name="wq_sfx" type="hidden" value="XML"/>
<input name="wq_dbg" type="hidden" value=":all"/>
<input type="submit" value="wijzig record"/>
<input type="reset" value="origineel scherm"/>
</td>
</tr>
</table>
</form>
</td>
</tr>
</xsl:template>
<!--
attribute templates
-->
<xsl:template match="@*" mode="update" name="update-all-attributes">
<xsl:comment>update-all-attributes; node='<xsl:value-of select="name()"/>'</xsl:comment>
<xsl:value-of select="name()"/>
<xsl:text>=</xsl:text>
<xsl:apply-templates/>
<xsl:text> </xsl:text>
</xsl:template>
<!--
field level template
-->
<xsl:template match="*" mode="update" name="default-field-update">
<xsl:comment>default-field-update; node='<xsl:value-of select="name()"/>'</xsl:comment>
<xsl:param name="definition" select="/.."/>
<xsl:variable name="database-record" select="current()"/>
<xsl:variable name="name">
<xsl:value-of select="name()"/>
<xsl:text>_</xsl:text>
<xsl:value-of select="position()"/>
</xsl:variable>
<tr valign="top">
<xsl:attribute name="class"><xsl:choose><xsl:when test="position() mod 2 =
1">rowodd</xsl:when><xsl:otherwise>roweven</xsl:otherwise></xsl:choose></xsl:attribute>
<td class="label">
<xsl:value-of select="$name"/>
<xsl:apply-templates select="@occ" mode="update"/>
</td>
<td>
<xsl:choose>
<xsl:when test="name($definition) = 'group'">
<input type="hidden" name="{$name}"/>
<table class="status" width="100%">
<xsl:apply-templates select="$definition/*" mode="update-def">
<xsl:with-param name="database-record" select="$database-record"/>
</xsl:apply-templates>
</table>
</xsl:when>
<xsl:when test="$definition/@readonly = 'yes'">
<xsl:apply-templates mode="update"/>
</xsl:when>
<xsl:when test="$definition/@type = 'file'">
<xsl:apply-templates mode="update"/>
<input name="{$name}" type="checkbox" value="&&delete;"/>
<xsl:value-of select="$definition/@boxtext"/>
</xsl:when>
<xsl:when test="$definition/@type = 'textarea'">
<textarea name="{$name}" rows="{$definition/@rows}" cols="{$definition/@cols}" wrap="virtual">
<xsl:apply-templates mode="update"/>
</textarea>
</xsl:when>
<xsl:otherwise>
<input name="{$name}" type="{$definition/@type}">
<xsl:attribute name="size">
<xsl:choose>
<xsl:when test="$definition/@size > 60">
<xsl:text>55</xsl:text>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$definition/@size"/>
</xsl:otherwise>
</xsl:choose>
</xsl:attribute>
<xsl:attribute name="value"><xsl:apply-templates mode="update"/></xsl:attribute>
</input>
<xsl:if test="$definition/@size > 60">
<xsl:text> ... [</xsl:text>
<xsl:value-of select="$definition/@size"/>
<xsl:text>]</xsl:text>
</xsl:if>
</xsl:otherwise>
</xsl:choose>
</td>
</tr>
</xsl:template>
<!--
processing template
-->
<xsl:template match="fieldgroup" mode="update-def" name="update-field-or-group">
<xsl:param name="database-record" select="/.."/>
<xsl:variable name="definition" select="current()"/>
<xsl:variable name="occurrences" select="count($database-record/*[name()=$definition/@name])"/>
<xsl:comment>update-field-or-group; <xsl:value-of select="name()"/>='<xsl:value-of select="@name"/>', database node='<xsl:valueof
select="name($database-record)"/>'</xsl:comment>
<tr>
<td>
<xsl:apply-templates select="$database-record/*[name()=$definition/@name]" mode="update">
<xsl:with-param name="definition" select="$definition"/>
</xsl:apply-templates>
</td>
</tr>
<xsl:if test="@repeat='yes' or $occurrences=0">
<xsl:variable name="name">
<xsl:value-of select="@name"/>
<xsl:text>_</xsl:text>
<xsl:value-of select="$occurrences + 1"/>
</xsl:variable>
<tr valign="top">
<td class="label">
<xsl:value-of select="$name"/>
<xsl:text> [nieuw]</xsl:text>
</td>
<td>
<xsl:choose>
<xsl:when test="name() = 'group'">
<input type="hidden" name="{$name}"/>
<table class="status" width="100%">
<xsl:apply-templates select="$definition/*" mode="update-def">
<xsl:with-param name="database-record" select="/.."/>
</xsl:apply-templates>
</table>
</xsl:when>
<xsl:when test="@readonly = 'yes'">
<xsl:apply-templates mode="update-def"/>
</xsl:when>
<xsl:when test="@type = 'textarea'">
<textarea name="{$name}" rows="{@rows}" cols="{@cols}" wrap="virtual">
<xsl:apply-templates mode="update-def"/>
</textarea>
</xsl:when>
<xsl:otherwise>
<input name="{$name}" type="{@type}">
<xsl:attribute name="size">
<xsl:choose>
<xsl:when test="@size > 60">
<xsl:text>55</xsl:text>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="@size"/>
</xsl:otherwise>
</xsl:choose>
</xsl:attribute>
<xsl:attribute name="value"><xsl:apply-templates mode="update"/></xsl:attribute>
</input>
<xsl:if test="@size > 60">
<xsl:text> ... [</xsl:text>
<xsl:value-of select="@size"/>
<xsl:text>]</xsl:text>
</xsl:if>
</xsl:otherwise>
</xsl:choose>
</td>
</tr>
</xsl:if>
</xsl:template>
<!--
-->
</xsl:stylesheet>
<\pre>