Toon posts:

[XSLT/XML] Hoe krijg ik de eerst volgende datum na vandaag?

Pagina: 1
Acties:
  • 211 views sinds 30-01-2008
  • Reageer

Verwijderd

Topicstarter
Dit lijkt eenvoudig, maar dat is het volgens mij niet...

Stel, ik heb een stukkie XML:

<?xml version="1.0" encoding="UTF-8"?>
<?xml:stylesheet type="text/xsl" href="list.xsl"?>
<xml>
<startdate>2003-01-01</startdate>
<startdate>2003-11-10</startdate>
<startdate>2004-01-01</startdate>
<startdate>2005-01-01</startdate>
</xml>

Nu wil ik alleen de eerstvolgende datum tonen na vandaag. Hier nog een stukje XSLT:

<?xml version="1.0" encoding="UTF-8" ?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:param name="today" select="'2003-10-23'"/>
<xsl:template match="xml">
<xsl:value-of select="startdate[. >= $today]"/>
</xsl:template>
</xsl:stylesheet>

Maar dit werkt dus niet, omdat je strings binnen xslt niet kan vergelijken met >
Iemand enig idee hoe dit op te lossen?

  • mbravenboer
  • Registratie: Januari 2000
  • Laatst online: 06-11-2025
Welke XSLT processor gebruik je? Als je XSLT processor namelijk EXSLT ondersteunt kan je de date en time functies van EXSLT gebruiken.

EXSLT wordt al aardig ondersteunt, bijvoorbeeld door Xalan (gebruikt in Java), libxslt (gebruikt door xsltproc), Saxon, MSXSL en .NET. Soms werkt EXSLT wel pas via een extra download/toevoeging.

Blog, Stratego/XT: Program Transformation, SDF: Syntax Definition, Nix: Software Deployment


  • tomato
  • Registratie: November 1999
  • Niet online
Je kunt natuurlijk gewoon het jaar, de maand en de dag uit de jaar-string halen en deze concateneren zodat je een string krijgt met daarin alleen cijfers waarop je kunt vergelijken:

code:
1
2
3
4
<xsl:value-of select="dates/date[
    concat(substring(.,1,4),substring(.,6,2),substring(.,9,2))
    >= concat(substring($today,1,4),substring($today,6,2),substring($today,9,2))
    ]" />


Als je de EXSLT dates&times functies kunt gebruiken kan het inderdaad iets mooier, je kunt dan ook $today met een functie vullen:

code:
1
2
3
4
5
6
<xsl:param name="today" select="date:date()" />

<xsl:value-of select="dates/date[
    concat(date:year(.),date:month-in-year(.),date:day-in-month(.))
    >= concat(date:year($today),date:month-in-year($today),date:day-in-month($today))
    ]" />


En je bent dan ook voorbereid op andere datum formaten (die de EXSLT functies aankunnen).

Deze gebruikte functies zijn in Xalan geimplementeerd, wil je het bijvoorbeeld aanpakken met de date:difference() functie dan moet je de implementatie daarvan ergens anders vandaan halen, want die is niet geimplementeerd in de huidige versie van Xalan.

Om de dates&times functies van EXSLT te kunnen gebruiken in je transformatie voeg je de volgende namespace toe (en heb je natuurlijk een processor nodig die deze functies geimplementeerd heeft):

code:
1
xmlns:date="http://exslt.org/dates-and-times"


Volgens mij hoor je ook
code:
1
extension-element-prefixes="date"

toe te voegen binnen je xsl:tranform (:stylesheet) element, maar of ik begrijp dat niet helemaal, of dat is niet bij alle processors noodzakelijk...

[ Voor 4% gewijzigd door tomato op 23-10-2003 19:28 ]


  • tomato
  • Registratie: November 1999
  • Niet online
Merk overigens op dat deze oplossingen alleen werken omdat we een representatie met alleen getallen van datums kunnen maken waarmee we kunnen vergelijken.

Wil je hetzelfde met bijvoorbeeld woorden, dan moet je het heel anders gaan aanpakken.

Zie bijvoorbeeld dit antwoord van Jeni Tennison op een soorgelijke vraag. Een aardige van de geboden oplossingen (met het grootste nadeel gelijk genoemd):

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
If you were allowing XSLT 1.1, then you could use xsl:sort to list the
terms, including the input term, and select the one you're after:

<xsl:template match="longman">
   <!-- create a list of terms that includes the input term -->
   <xsl:variable name="terms">
     <input><xsl:value-of select="$input" /></input>
     <xsl:copy-of select="term" />
   </xsl:variable>
   <xsl:for-each select="$terms">
     <!-- sort the terms (including the input term) alphabetically -->
     <xsl:sort select="." />
     <!-- select the term that immediately following the input term
          within the list -->
     <xsl:apply-templates select="input/following-sibling::term" />
   </xsl:for-each>
</xsl:template>

(term is bij ons date en $input is bij ons $today)

Misschien wel aardig om ook even te zien ;)

  • tomato
  • Registratie: November 1999
  • Niet online
Als overigens de datum van vandaag ook altijd voor komt in je input, kun je het nog eenvoudiger voor elkaar krijgen.

Ik heb dit net nog even gebruikt om bij een bepaald nieuwsbericht een link naar het volgende nieuwsbericht te tonen. In dat geval wordt $today de datum van het huidige nieuwsbericht en kun je er dus vanuit gaan dat deze datum ook voor komt in de index van alle nieuwsberichten.

Je kunt dan eenvoudig het volgende bericht selecteren (indien het bestaat):
code:
1
2
3
<xsl:apply-templates select="news.index')/index/item[
        date=$today
        ]/following-sibling::item[1]" />

In dit geval gaat het natuurlijk wel om het krijgen van de volgende, ik weet niet zeker of dat in jouw vraag ook de bedoeling was (je stelde je vraag wel zo, maar in je code gebruikte je een >=).

Als je eigenlijk een > bedoelde zou je deze aanpak kunnen toepassen, maar je moet dan ook ervan uit kunnen gaan dat $today voor komt in je lijst met data. Ik neem aan dat dat bij jou wat lastiger ligt, net als bij de post die ik hierboven quote. Daar wordt in de template tijdelijk een nieuwe lijst gemaakt waar '$today' ook in voor komt, helaas werkt dit niet in XSLT1.0.

Verwijderd

Topicstarter
Bedankt mensen, 't werkt nu! Ik hou van puur xsl, dus heb de optie gekozen waar je binnen de [] alles concat en substringt. Ik heb ook nog geprobeerd om die nodes in de variabele $term te stoppen, maar dan krijg ik een foutmelding dat $term geen nodelist is als ik een for-each erop los laat. Maar 't werkt nu, en daar ben ik heel blij mee.

[ Voor 3% gewijzigd door Verwijderd op 24-10-2003 12:26 ]


  • tomato
  • Registratie: November 1999
  • Niet online
Verwijderd schreef op 24 oktober 2003 @ 12:25:
Ik heb ook nog geprobeerd om die nodes in de variabele $term te stoppen, maar dan krijg ik een foutmelding dat $term geen nodelist is als ik een for-each erop los laat.
Inderdaad, als ik het goed begrijp is dat dus een gebrek van XSLT1.0, maar het fijne weet ik er ook niet van.
Pagina: 1