Project

Profile

Help

Bug #6131 » day-of-week.xslt

Johan Gheys, 2023-07-19 08:44

 
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:dow="urn:dow-functions"
xmlns:map="http://www.w3.org/2005/xpath-functions/map"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="2.0">

<xsl:function name="dow:day-of-week" as="xs:integer">
<xsl:param name="date" as="xs:string"/>
<xsl:sequence select="xs:integer(format-date(xs:date($date), '[F1]', (), 'ISO', ()))"/>
</xsl:function>

<xsl:function name="dow:day-to-string" as="xs:string">
<xsl:param name="R" as="xs:integer*"/>
<xsl:param name="F" as="xs:integer*"/>
<xsl:param name="N" as="xs:integer*"/>
<xsl:value-of>
<xsl:if test="exists($R)">
<xsl:sequence select="'R', $R"/>
</xsl:if>
<xsl:if test="exists($F)">
<xsl:sequence select="'F', $F"/>
</xsl:if>
<xsl:if test="exists($N)">
<xsl:sequence select="'N', $N"/>
</xsl:if>
</xsl:value-of>
</xsl:function>

<xsl:function name="dow:merge-valday" as="map(*)*">
<xsl:param name="valday" as="map(*)*"/>
<xsl:param name="feastday" as="xs:string*"/>
<xsl:iterate select="$valday">
<xsl:param name="previous-valday" select="()" as="map(*)?"/>
<xsl:variable name="index" select="position()"/>
<xsl:variable name="current-valday" select="($previous-valday, .)[1]"/>
<xsl:variable name="next-valday" select="$valday[$index + 1]"/>
<xsl:variable name="merged-R" select="sort(distinct-values(($current-valday?R, $next-valday?R)))"/>
<xsl:variable name="merged-F" select="sort(distinct-values(($current-valday?F, $next-valday?F)))"/>
<xsl:variable name="hole-validFromDate" select="dow:next-day($current-valday?validToDate)"/>
<xsl:variable name="hole-validToDate" select="dow:previous-day($next-valday?validFromDate)"/>
<xsl:variable name="hole-val" select="map{'validFromDate': $hole-validFromDate, 'validToDate': $hole-validToDate}"/>
<xsl:variable name="hole-valday" select="dow:val-to-continuous-valday($hole-val, $feastday)[exists($next-valday)]"/>
<xsl:variable name="merged-N" select="sort(distinct-values(($current-valday?N, $next-valday?N, $hole-valday?R)))"/>
<xsl:variable name="add-now" select="empty($next-valday) or exists(($merged-R[. = ($merged-F, $hole-valday?R)], $merged-F[. = $hole-valday?R], $merged-N[. = ($merged-R, $merged-F)]))"/>
<xsl:if test="$add-now">
<xsl:sequence select="$current-valday"/>
</xsl:if>
<xsl:variable name="merged-valday" as="map(*)?">
<xsl:if test="not($add-now)">
<xsl:map>
<xsl:map-entry key="'validFromDate'" select="$current-valday?validFromDate"/>
<xsl:map-entry key="'validToDate'" select="$next-valday?validToDate"/>
<xsl:map-entry key="'R'" select="$merged-R"/>
<xsl:map-entry key="'F'" select="$merged-F"/>
<xsl:map-entry key="'N'" select="$merged-N"/>
</xsl:map>
</xsl:if>
</xsl:variable>
<xsl:next-iteration>
<xsl:with-param name="previous-valday" select="$merged-valday"/>
</xsl:next-iteration>
</xsl:iterate>
</xsl:function>

<xsl:function name="dow:next-day" as="xs:string">
<xsl:param name="date" as="xs:string"/>
<xsl:sequence select="dow:shift-day($date, 1)"/>
</xsl:function>

<xsl:function name="dow:previous-day" as="xs:string">
<xsl:param name="date" as="xs:string"/>
<xsl:sequence select="dow:shift-day($date, -1)"/>
</xsl:function>

<xsl:function name="dow:shift-day" as="xs:string">
<xsl:param name="date" as="xs:string"/>
<xsl:param name="nbOfDays" as="xs:integer"/>
<xsl:choose>
<xsl:when test="$nbOfDays gt 0">
<!-- Add abs to avoid compilation warning -->
<xsl:value-of select="xs:date($date) + xs:dayTimeDuration(concat('P', abs($nbOfDays), 'D'))"/>
</xsl:when>
<xsl:when test="$nbOfDays lt 0">
<xsl:value-of select="xs:date($date) - xs:dayTimeDuration(concat('P', abs($nbOfDays), 'D'))"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$date"/>
</xsl:otherwise>
</xsl:choose>
</xsl:function>

<xsl:function name="dow:val-to-continuous-valday" as="map(*)*">
<xsl:param name="val" as="map(*)*"/>
<xsl:param name="feastday" as="xs:string*"/>
<xsl:for-each select="$val">
<xsl:variable name="date" select="dow:val-to-date(.)"/>
<xsl:variable name="day" select="for $d in $date return if ($d = $feastday) then 7 else dow:day-of-week($d)"/>
<xsl:variable name="R" select="sort(distinct-values($day))"/>
<xsl:sequence select="map:merge((map:entry('R', $R), .))"/>
</xsl:for-each>
</xsl:function>

<xsl:function name="dow:val-to-date" as="xs:string*">
<xsl:param name="val" as="map(*)*"/>
<xsl:for-each select="$val">
<xsl:variable name="validFromDate" select="?validFromDate"/>
<xsl:variable name="validToDate" select="?validToDate"/>
<xsl:variable name="nb-of-days" select="xs:integer((xs:date($validToDate) - xs:date($validFromDate)) div xs:dayTimeDuration('P1D'))"/>
<xsl:for-each select="0 to $nb-of-days">
<xsl:sequence select="dow:shift-day($validFromDate, .)"/>
</xsl:for-each>
</xsl:for-each>
</xsl:function>

<xsl:function name="dow:val-to-valday" as="map(*)*">
<xsl:param name="val" as="map(*)*"/>
<xsl:param name="feastday" as="xs:string*"/>
<xsl:variable name="continuous-valday" select="dow:val-to-continuous-valday($val, $feastday)"/>
<xsl:sequence select="dow:merge-valday($continuous-valday, $feastday)"/>
</xsl:function>

<xsl:function name="dow:valday-to-string" as="xs:string*">
<xsl:param name="valday" as="map(*)*"/>
<xsl:for-each select="$valday">
<xsl:sequence select="concat('val=[', ?validFromDate, ',', ?validToDate, '] day=', dow:day-to-string(?R, ?F, ?N))"/>
</xsl:for-each>
</xsl:function>

</xsl:stylesheet>
(2-2/3)