Project

Profile

Help

Support #4934 » shared-functions.xslt

Johan Gheys, 2021-03-12 11:02

 
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:map="http://www.w3.org/2005/xpath-functions/map"
xmlns:math="http://www.w3.org/2005/xpath-functions/math"
xmlns:file="http://expath.org/ns/file"
xmlns:arch="http://expath.org/ns/archive"
xmlns:saxon="http://saxon.sf.net/"
xmlns:ext="http://www.infrabel.be/saxon/extension"
xmlns:thread="java:java.lang.Thread"
xmlns:shared="urn:shared-functions"
extension-element-prefixes="saxon"
version="2.0">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" saxon:indent-spaces="0" saxon:line-length="100000" saxon:attribute-order="*"/>
<xsl:import href="/shared/extension-function-api.xslt"/>
<xsl:variable name="apos" as="xs:string">'</xsl:variable>
<xsl:variable name="quot" as="xs:string">"</xsl:variable>
<xsl:variable name="pipe" select="'|'"/>
<xsl:variable name="separator" select="'-'"/>
<xsl:variable name="EOL" select="'&#10;'"/>
<xsl:variable name="TAB" select="'&#x9;'"/>
<xsl:variable name="TNO" select="'2078-12-31'"/>
<xsl:variable name="output-parameters" select="shared:output-parameters()"/>
<xsl:key name="by-id" match="*" use="@id"/>
<xsl:key name="by-key" match="*" use="@key"/>
<!-- *********************************************************************************************************** -->
<xsl:function name="shared:acosd" as="xs:double?">
<xsl:param name="cos" as="xs:double?"/>
<xsl:sequence select="if (exists($cos)) then shared:radians-to-degrees(math:acos($cos)) else ()"/>
</xsl:function>
<!-- *********************************************************************************************************** -->
<xsl:function name="shared:add-digest" as="element()*">
<xsl:param name="element" as="element()*"/>
<xsl:for-each select="$element">
<xsl:sequence select="shared:add-or-update-attributes(., 'digest', shared:get-digest(.))"/>
</xsl:for-each>
</xsl:function>
<!-- *********************************************************************************************************** -->
<xsl:function name="shared:add-digest-for-element-without-validity" as="element()*">
<xsl:param name="element" as="element()*"/>
<xsl:for-each select="$element">
<xsl:sequence select="shared:add-or-update-attributes(., 'digest', shared:get-digest(shared:get-element-without-validity(.)))"/>
</xsl:for-each>
</xsl:function>
<!-- *********************************************************************************************************** -->
<xsl:function name="shared:add-or-update-attributes">
<xsl:param name="elements"/>
<xsl:param name="attrNames"/>
<xsl:param name="attrValues"/>
<xsl:for-each select="$elements">
<xsl:copy>
<xsl:sequence select="@*[not(name(.) = $attrNames)]"/>
<xsl:for-each select="$attrNames">
<xsl:variable name="seq" select="position()"/>
<xsl:attribute name="{.}" select="$attrValues[$seq]"/>
</xsl:for-each>
<xsl:sequence select="node()"/>
</xsl:copy>
</xsl:for-each>
</xsl:function>
<!-- *********************************************************************************************************** -->
<xsl:function name="shared:always-false" as="xs:boolean">
<xsl:sequence select="current-date() lt xs:date('2000-01-01')"/>
</xsl:function>
<!-- *********************************************************************************************************** -->
<xsl:function name="shared:asind" as="xs:double?">
<xsl:param name="sin" as="xs:double?"/>
<xsl:sequence select="if (exists($sin)) then shared:radians-to-degrees(math:asin($sin)) else ()"/>
</xsl:function>
<!-- *********************************************************************************************************** -->
<xsl:function name="shared:atand" as="xs:double?">
<xsl:param name="tan" as="xs:double?"/>
<xsl:sequence select="if (exists($tan)) then shared:radians-to-degrees(math:atan($tan)) else ()"/>
</xsl:function>
<!-- *********************************************************************************************************** -->
<xsl:function name="shared:camel-case" as="xs:string">
<xsl:param name="arg" as="xs:string?"/>
<xsl:variable name="camelCaseWords" as="xs:string*">
<xsl:for-each select="tokenize($arg,'\s+|_|-')">
<xsl:sequence select="if (position() eq 1) then lower-case(.) else concat(upper-case(substring(., 1, 1)), lower-case(substring(., 2)))"/>
</xsl:for-each>
</xsl:variable>
<xsl:sequence select="string-join($camelCaseWords,'')"/>
</xsl:function>
<!-- *********************************************************************************************************** -->
<xsl:function name="shared:chars" as="xs:string*">
<!-- Same as functx:chars -->
<xsl:param name="arg" as="xs:string?"/>
<xsl:sequence select="for $ch in string-to-codepoints($arg) return codepoints-to-string($ch)"/>
</xsl:function>
<!-- *********************************************************************************************************** -->
<xsl:function name="shared:clone" as="element()*">
<xsl:param name="pItem" as="element()*"/>
<xsl:for-each select="$pItem">
<!-- Delete unwanted namespace nodes like xmlns="" by adding namespace-uri() (e.g. when drawing a graphicalLevelCrossing)
See http://lenzconsulting.com/namespaces-in-xslt -->
<xsl:element name="{local-name()}" namespace="{namespace-uri()}">
<xsl:sequence select="@*"/>
<xsl:for-each select="*">
<xsl:sequence select="shared:clone(.)"/>
</xsl:for-each>
</xsl:element>
</xsl:for-each>
</xsl:function>
<!-- *********************************************************************************************************** -->
<xsl:function name="shared:clone" as="element()*">
<xsl:param name="pItem" as="element()*"/>
<xsl:param name="pValidFromDate" as="xs:string?"/>
<xsl:param name="pValidToDate" as="xs:string?"/>
<xsl:for-each select="$pItem">
<xsl:element name="{name()}" namespace="{namespace-uri()}">
<xsl:sequence select="@* except (@validFromDate, @validToDate)"/>
<xsl:if test="exists(@validFromDate) and exists($pValidFromDate)">
<xsl:attribute name="validFromDate" select="shared:max(($pValidFromDate, @validFromDate))"/>
</xsl:if>
<xsl:if test="exists(@validToDate) and exists($pValidToDate)">
<xsl:attribute name="validToDate" select="shared:min(($pValidToDate, @validToDate))"/>
</xsl:if>
<xsl:for-each select="*">
<xsl:sequence select="shared:clone(., $pValidFromDate, $pValidToDate)"/>
</xsl:for-each>
</xsl:element>
</xsl:for-each>
</xsl:function>
<!-- *********************************************************************************************************** -->
<xsl:template name="shared:compile-stylesheet">
<xsl:param name="options" as="map(*)"/>
<xsl:variable name="startTime" select="saxon:timestamp()"/>
<xsl:sequence select="$startTime[shared:always-false()]"/>
<xsl:sequence select="shared:compile-stylesheet($options)"/>
<xsl:sequence select="shared:log-execution-time($startTime)"/>
</xsl:template>
<!-- *********************************************************************************************************** -->
<xsl:function name="shared:compile-stylesheet">
<xsl:param name="options" as="map(*)"/>
<xsl:sequence select="shared:log('DEBUG', concat('Compiling ', $options?stylesheet, ' to ', $options?sef))"/>
<xsl:variable name="executable" select="shared:find-java()"/>
<xsl:variable name="arguments" as="xs:string*">
<xsl:sequence select="'-cp'"/>
<xsl:sequence select="shared:find-classpath()"/>
<xsl:sequence select="'net.sf.saxon.Transform'"/>
<xsl:sequence select="'-target:JS'"/>
<xsl:sequence select="'-nogo'"/>
<xsl:sequence select="'-relocate:on'"/>
<xsl:sequence select="'-ns:##html5'"/>
<xsl:sequence select="concat('-xsl:', $options?stylesheet)"/>
<xsl:sequence select="concat('-export:', $options?sef)"/>
</xsl:variable>
<saxon:do action="ext:exec-external($executable, $arguments)"/>
</xsl:function>
<!-- *********************************************************************************************************** -->
<xsl:function name="shared:copy">
<xsl:param name="source" as="xs:string"/>
<xsl:param name="target" as="xs:string"/>
<xsl:if test="file:exists($source)">
<xsl:sequence select="shared:log('DEBUG', concat('Copying ', $source, ' to ', $target))"/>
<xsl:sequence select="file:copy($source, $target)"/>
</xsl:if>
</xsl:function>
<!-- *********************************************************************************************************** -->
<xsl:function name="shared:copy-children">
<xsl:param name="source" as="xs:string"/>
<xsl:param name="target" as="xs:string"/>
<xsl:if test="file:is-dir($source) and file:is-dir($target)">
<xsl:for-each select="shared:list($source)">
<xsl:sequence select="shared:copy(concat($source, .), $target)"/>
</xsl:for-each>
</xsl:if>
</xsl:function>
<!-- *********************************************************************************************************** -->
<xsl:function name="shared:copy-files">
<xsl:param name="source" as="xs:string"/>
<xsl:param name="target" as="xs:string"/>
<xsl:if test="file:is-dir($source) and file:is-dir($target)">
<xsl:for-each select="shared:list-files($source)">
<xsl:sequence select="shared:copy(concat($source, .), $target)"/>
</xsl:for-each>
</xsl:if>
</xsl:function>
<!-- *********************************************************************************************************** -->
<xsl:function name="shared:cosd" as="xs:double?">
<xsl:param name="angleInDegrees" as="xs:double?"/>
<xsl:sequence select="if (exists($angleInDegrees)) then math:cos(shared:degrees-to-radians($angleInDegrees)) else ()"/>
</xsl:function>
<!-- *********************************************************************************************************** -->
<xsl:function name="shared:create-dir">
<xsl:param name="dir" as="xs:string"/>
<xsl:sequence select="shared:log('DEBUG', concat('Creating ', $dir))"/>
<xsl:sequence select="file:create-dir($dir)"/>
</xsl:function>
<!-- *********************************************************************************************************** -->
<xsl:function name="shared:cumulative-sum" as="item()*">
<xsl:param name="items" as="item()*"/>
<xsl:sequence select="shared:cumulative-sum-impl($items, 1, 0, ())"/>
</xsl:function>
<!-- *********************************************************************************************************** -->
<xsl:function name="shared:cumulative-sum-impl" as="item()*">
<xsl:param name="items" as="item()*"/>
<xsl:param name="index" as="xs:integer"/>
<xsl:param name="sum" as="item()"/>
<xsl:param name="result" as="item()*"/>
<xsl:variable name="item" as="item()?" select="$items[$index]"/>
<xsl:choose>
<xsl:when test="empty($item)">
<xsl:sequence select="$result"/>
</xsl:when>
<xsl:otherwise>
<xsl:variable name="value" select="$item + $sum"/>
<xsl:variable name="next" select="$result, $value"/>
<xsl:sequence select="shared:cumulative-sum-impl($items, $index + 1, $value, $next)"/>
</xsl:otherwise>
</xsl:choose>
</xsl:function>
<!-- *********************************************************************************************************** -->
<xsl:function name="shared:dates-between" as="xs:string*">
<xsl:param name="from-date" as="xs:string"/>
<xsl:param name="to-date" as="xs:string"/>
<xsl:variable name="nb-of-midnights" select="xs:integer((xs:date($to-date) - xs:date($from-date)) div xs:dayTimeDuration('P1D'))"/>
<xsl:for-each select="0 to $nb-of-midnights">
<xsl:sequence select="shared:shift-day($from-date, .)"/>
</xsl:for-each>
</xsl:function>
<!-- *********************************************************************************************************** -->
<xsl:function name="shared: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="shared:degrees-to-radians" as="xs:double">
<xsl:param name="angleInDegrees" as="xs:double"/>
<xsl:sequence select="$angleInDegrees div 180 * math:pi()"/>
</xsl:function>
<!-- *********************************************************************************************************** -->
<xsl:function name="shared:delete">
<xsl:param name="path" as="xs:string"/>
<xsl:sequence select="shared:delete($path, true())"/>
</xsl:function>
<!-- *********************************************************************************************************** -->
<xsl:function name="shared:delete">
<xsl:param name="path" as="xs:string"/>
<xsl:param name="recursive" as="xs:boolean"/>
<xsl:if test="file:exists($path)">
<xsl:sequence select="shared:log('DEBUG', concat('Deleting ', $path))"/>
<xsl:sequence select="file:delete($path, $recursive)"/>
</xsl:if>
</xsl:function>
<!-- *********************************************************************************************************** -->
<xsl:function name="shared:delete-files">
<xsl:param name="path" as="xs:string"/>
<xsl:if test="file:is-dir($path)">
<xsl:for-each select="shared:list-files($path)">
<xsl:sequence select="shared:delete(concat($path, .))"/>
</xsl:for-each>
</xsl:if>
</xsl:function>
<!-- *********************************************************************************************************** -->
<xsl:function name="shared:digits-from-string" as="xs:string?">
<xsl:param name="string" as="xs:string?"/>
<!-- Double Translate Method first proposed by Michael Kay -->
<xsl:for-each select="$string">
<xsl:sequence select="translate(., translate(., '0123456789', ''), '')"/>
</xsl:for-each>
</xsl:function>
<!-- *********************************************************************************************************** -->
<xsl:function name="shared:distinct-sorted-values" as="xs:anyAtomicType*">
<xsl:param name="sequence" as="xs:anyAtomicType*"/>
<xsl:param name="data-type" as="xs:string"/>
<xsl:for-each-group select="$sequence" group-by=".">
<xsl:sort select="current-grouping-key()" data-type="{$data-type}"/>
<xsl:sequence select="current-group()[1]"/>
</xsl:for-each-group>
</xsl:function>
<!-- *********************************************************************************************************** -->
<xsl:function name="shared:doc" as="document-node()?">
<xsl:param name="uri" as="xs:string"/>
<xsl:choose>
<xsl:when test="doc-available($uri)">
<xsl:sequence select="saxon:discard-document(doc($uri))"/>
</xsl:when>
<xsl:otherwise>
<xsl:sequence select="shared:log('DEBUG', concat('*** MISSING ', $uri))"/>
</xsl:otherwise>
</xsl:choose>
</xsl:function>
<!-- *********************************************************************************************************** -->
<xsl:function name="shared:download">
<xsl:param name="remoteSource" as="xs:string"/>
<xsl:param name="localTarget" as="xs:string"/>
<xsl:param name="hostname" as="xs:string"/>
<xsl:param name="username" as="xs:string"/>
<xsl:param name="password" as="xs:string?"/>
<xsl:sequence select="shared:log('DEBUG', concat('Downloading ', $remoteSource, ' from ', $hostname, ' to ', $localTarget))"/>
<xsl:sequence select="ext:download($remoteSource, $localTarget, $hostname, $username, $password)"/>
</xsl:function>
<!-- *********************************************************************************************************** -->
<xsl:function name="shared:dummy-doc" as="document-node()">
<xsl:document>
<dummy/>
</xsl:document>
</xsl:function>
<!-- *********************************************************************************************************** -->
<xsl:function name="shared:escape">
<xsl:param name="text" as="xs:string"/>
<xsl:sequence select="replace(replace(replace($text, '\|', '-pipe-'), '/', '-slash-'), '\\', '-backslash-')"/>
</xsl:function>
<!-- *********************************************************************************************************** -->
<xsl:function name="shared:extract-resource">
<xsl:param name="source" as="xs:string"/>
<xsl:param name="target" as="xs:string"/>
<xsl:sequence select="shared:log('DEBUG', concat('Extracting resource ', $source, ' to ', $target))"/>
<xsl:variable name="jar-uri" select="substring-before(static-base-uri(), '/')"/>
<xsl:variable name="source-uri" select="concat($jar-uri, $source)"/>
<xsl:sequence select="file:write-binary($target, saxon:read-binary-resource($source-uri))"/>
</xsl:function>
<!-- *********************************************************************************************************** -->
<xsl:function name="shared:extract-valid-from-dates" as="xs:string*">
<xsl:param name="entityVersions" as="element()*"/>
<xsl:variable name="validFromDates" as="xs:string*" select="distinct-values($entityVersions/@validFromDate)"/>
<xsl:variable name="validToDates" as="xs:string*" select="distinct-values($entityVersions/@validToDate[. != $TNO])"/>
<xsl:variable name="shiftedValidToDates" as="xs:string*" select="for $date in $validToDates return (shared:next-day($date))"/>
<xsl:variable name="mergedDates" select="$validFromDates, $shiftedValidToDates"/>
<xsl:for-each select="distinct-values($mergedDates)">
<xsl:sort select="."/>
<xsl:sequence select="."/>
</xsl:for-each>
</xsl:function>
<!-- *********************************************************************************************************** -->
<xsl:function name="shared:extract-validities" as="element()*">
<xsl:param name="entityVersions" as="element()*"/>
<xsl:variable name="minValidFromDate" select="shared:min($entityVersions/@validFromDate)"/>
<xsl:variable name="maxValidToDate" select="shared:max($entityVersions/@validToDate)"/>
<xsl:sequence select="shared:extract-validities($entityVersions, $minValidFromDate, $maxValidToDate)"/>
</xsl:function>
<!-- *********************************************************************************************************** -->
<xsl:function name="shared:extract-validities" as="element()*">
<xsl:param name="entityVersions" as="element()*"/>
<xsl:param name="pRefValidFromDate" as="xs:string"/>
<xsl:param name="pRefValidToDate" as="xs:string"/>
<xsl:variable name="validFromDates" as="xs:string*"
select="if (exists($entityVersions)) then distinct-values($entityVersions/@validFromDate[. gt $pRefValidFromDate and . lt $pRefValidToDate]) else ()"/>
<xsl:variable name="validToDates" as="xs:string*"
select="if (exists($entityVersions)) then distinct-values($entityVersions/@validToDate[. gt $pRefValidFromDate and . lt $pRefValidToDate]) else ()"/>
<xsl:variable name="shiftedValidFromDates" as="xs:string*" select="for $date in $validFromDates return (shared:previous-day($date))"/>
<xsl:variable name="shiftedValidToDates" as="xs:string*" select="for $date in $validToDates return (shared:next-day($date))"/>
<xsl:variable name="mergedValidFromDates" as="xs:string*" select="distinct-values(($pRefValidFromDate, $validFromDates, $shiftedValidToDates))"/>
<xsl:variable name="mergedValidToDates" as="xs:string*" select="distinct-values(($validToDates, $shiftedValidFromDates, $pRefValidToDate))"/>
<xsl:variable name="dates" as="xs:string*">
<xsl:for-each select="$mergedValidFromDates, $mergedValidToDates">
<xsl:sort select="."/>
<xsl:sequence select="."/>
</xsl:for-each>
</xsl:variable>
<xsl:for-each select="$dates">
<xsl:variable name="index" select="position()"/>
<xsl:if test="($index mod 2) = 1">
<xsl:element name="shared:validity">
<xsl:attribute name="validFromDate" select="."/>
<xsl:attribute name="validToDate" select="$dates[$index + 1]"/>
</xsl:element>
</xsl:if>
</xsl:for-each>
</xsl:function>
<!-- *********************************************************************************************************** -->
<xsl:function name="shared:file-extension" as="xs:string">
<xsl:param name="uri" as="xs:string"/>
<xsl:choose>
<xsl:when test="contains($uri, '/')">
<xsl:sequence select="shared:file-extension(substring-after($uri, '/'))"/>
</xsl:when>
<xsl:when test="contains($uri, '.')">
<xsl:sequence select="shared:file-extension(substring-after($uri, '.'))"/>
</xsl:when>
<xsl:otherwise>
<xsl:sequence select="$uri"/>
</xsl:otherwise>
</xsl:choose>
</xsl:function>
<!-- *********************************************************************************************************** -->
<xsl:function name="shared:find-classpath" as="xs:string">
<xsl:sequence select="system-property('java.class.path')"/>
</xsl:function>
<!-- *********************************************************************************************************** -->
<xsl:function name="shared:find-java" as="xs:string">
<xsl:sequence select="string-join((system-property('java.home'), 'bin', 'java'), system-property('file.separator'))"/>
</xsl:function>
<!-- *********************************************************************************************************** -->
<xsl:function name="shared:fo-to-pdf">
<xsl:param name="foFileName" as="xs:string"/>
<xsl:param name="pdfFileName" as="xs:string"/>
<xsl:sequence select="shared:log('DEBUG', concat('Transforming ', $foFileName, ' to ', $pdfFileName))"/>
<xsl:sequence select="ext:fo-to-pdf($foFileName, $pdfFileName)"/>
</xsl:function>
<!-- *********************************************************************************************************** -->
<xsl:function name="shared:get-angle-from-points" as="xs:double">
<xsl:param name="points" as="xs:double*"/>
<xsl:variable name="x1" select="$points[1]"/>
<xsl:variable name="y1" select="$points[2]"/>
<xsl:variable name="x2" select="$points[3]"/>
<xsl:variable name="y2" select="$points[4]"/>
<xsl:choose>
<xsl:when test="$x1 eq $x2 and $y1 eq $y2">
<xsl:sequence select="0"/>
</xsl:when>
<xsl:when test="$x1 eq $x2 and $y1 ne $y2">
<xsl:sequence select="-90"/>
</xsl:when>
<xsl:otherwise>
<xsl:variable name="tan" select="($y2 - $y1) div ($x2 - $x1)"/>
<xsl:sequence select="shared:atand($tan)"/>
</xsl:otherwise>
</xsl:choose>
</xsl:function>
<!-- *********************************************************************************************************** -->
<xsl:function name="shared:get-attribute">
<xsl:param name="element"/>
<xsl:param name="attrName"/>
<xsl:for-each select="$element">
<xsl:sequence select="@*[name(.) = $attrName]"/>
</xsl:for-each>
</xsl:function>
<!-- *********************************************************************************************************** -->
<xsl:function name="shared:get-digest" as="xs:string">
<xsl:param name="element" as="item()"/>
<xsl:sequence select="shared:UUID($element)"/>
</xsl:function>
<!-- *********************************************************************************************************** -->
<xsl:function name="shared:get-element-without-validity">
<xsl:param name="pElement"/>
<xsl:for-each select="$pElement">
<xsl:sequence select="shared:remove-attributes(., ('validFromDate', 'validToDate'))"/>
</xsl:for-each>
</xsl:function>
<!-- *********************************************************************************************************** -->
<xsl:function name="shared:get-header" as="element()*">
<xsl:param name="pElement" as="element()*"/>
<xsl:for-each select="$pElement">
<xsl:copy>
<xsl:sequence select="@*"/>
</xsl:copy>
</xsl:for-each>
</xsl:function>
<!-- *********************************************************************************************************** -->
<xsl:function name="shared:get-signature">
<xsl:param name="entity"/>
<xsl:variable name="attributesSortedByTagName" as="item()*">
<xsl:for-each select="$entity/@* except ($entity/@validFromDate, $entity/@validToDate)">
<xsl:sort select="local-name(.)"/>
<xsl:sequence select="."/>
</xsl:for-each>
</xsl:variable>
<xsl:variable name="childrenSignaturesSortedAlphabetically" as="item()*">
<xsl:for-each select="$entity/node()[namespace::int or namespace::svg]">
<xsl:sort select="shared:get-signature(.)"/>
<xsl:sequence select="shared:get-signature(.)"/>
</xsl:for-each>
</xsl:variable>
<xsl:variable name="list" select="(local-name($entity), $attributesSortedByTagName, $childrenSignaturesSortedAlphabetically)"/>
<xsl:sequence select="string-join($list, $separator)"/>
</xsl:function>
<!-- *********************************************************************************************************** -->
<xsl:function name="shared:get-validities" as="element()*">
<xsl:param name="element" as="element()"/>
<xsl:param name="entityVersions" as="element()*"/>
<xsl:for-each select="$element">
<xsl:sequence select="shared:extract-validities($entityVersions, @validFromDate, @validToDate)"/>
</xsl:for-each>
</xsl:function>
<!-- *********************************************************************************************************** -->
<xsl:function name="shared:get-validities" as="element()*">
<xsl:param name="element" as="element()"/>
<xsl:param name="entityVersions" as="element()*"/>
<xsl:param name="purgeDate" as="xs:string"/>
<xsl:sequence select="shared:get-validities($element, $entityVersions)[@validToDate ge $purgeDate]"/>
</xsl:function>
<!-- *********************************************************************************************************** -->
<xsl:function name="shared:get-vector-bit" as="xs:integer">
<xsl:param name="vector" as="element()*"/>
<xsl:param name="layer" as="xs:string"/>
<xsl:param name="date" as="xs:string"/>
<xsl:variable name="vectorBit" as="xs:string?">
<xsl:for-each select="$vector">
<xsl:variable name="refVector" select="@*[local-name() eq concat($layer, 'Vector')]"/>
<xsl:if test="exists($refVector)">
<xsl:variable name="dateTo" select="shared:shift-day(@dateFrom, string-length($refVector) - 1)"/>
<xsl:if test="$date ge @dateFrom and $date le $dateTo">
<xsl:variable name="index" select="days-from-duration(xs:date($date) - xs:date(@dateFrom)) + 1"/>
<xsl:sequence select="substring($refVector, $index, 1)"/>
</xsl:if>
</xsl:if>
</xsl:for-each>
</xsl:variable>
<xsl:sequence select="xs:integer(($vectorBit, '0')[1])"/>
</xsl:function>
<!-- *********************************************************************************************************** -->
<xsl:function name="shared:get-vector-dates" as="xs:string*">
<xsl:param name="vector" as="element()*"/>
<xsl:param name="layer" as="xs:string"/>
<xsl:for-each select="$vector">
<xsl:variable name="refVector" select="@*[local-name() eq concat($layer, 'Vector')]"/>
<xsl:if test="exists($refVector)">
<xsl:variable name="dateFrom" select="@dateFrom"/>
<xsl:variable name="vectorBit" select="shared:chars($refVector)"/>
<xsl:for-each select="$vectorBit">
<xsl:sequence select="if (. ne '0') then shared:shift-day($dateFrom, position() - 1) else ()"/>
</xsl:for-each>
</xsl:if>
</xsl:for-each>
</xsl:function>
<!-- *********************************************************************************************************** -->
<xsl:function name="shared:get-vector-dates-for-layerVPK" as="xs:string*">
<xsl:param name="layerVPK" as="element()"/>
<xsl:param name="layer" as="xs:string"/>
<xsl:variable name="refVector" select="$layerVPK/*[local-name() eq concat($layer, 'Layer')]/*:vector"/>
<xsl:for-each select="$refVector">
<xsl:variable name="dateFrom" select="@dateFrom"/>
<xsl:variable name="vectorBit" select="shared:chars(@bitValue)"/>
<xsl:for-each select="$vectorBit">
<xsl:sequence select="if (. ne '0') then shared:shift-day($dateFrom, position() - 1) else ()"/>
</xsl:for-each>
</xsl:for-each>
</xsl:function>
<!-- *********************************************************************************************************** -->
<xsl:function name="shared:group-dates-by-week" as="element(week)*">
<xsl:param name="date" as="xs:string*"/>
<xsl:for-each-group select="$date" group-adjacent="shared:week-of-year(.)">
<xsl:element name="week">
<xsl:attribute name="id" select="current-grouping-key()"/>
<xsl:value-of select="current-group()"/>
</xsl:element>
</xsl:for-each-group>
</xsl:function>
<!-- *********************************************************************************************************** -->
<xsl:function name="shared:has-result-vector-running-days" as="xs:boolean">
<xsl:param name="vector" as="element()"/>
<xsl:sequence select="string-length(translate($vector/@resultVector, '0', '')) gt 0"/>
</xsl:function>
<!-- *********************************************************************************************************** -->
<xsl:function name="shared:in-filter" as="xs:boolean">
<xsl:param name="vector" as="element()*"/>
<xsl:param name="layer" as="xs:string"/>
<xsl:param name="date" as="xs:string"/>
<xsl:variable name="resultBit" select="shared:get-vector-bit($vector, $layer, $date)"/>
<xsl:sequence select="$resultBit ne 0"/>
</xsl:function>
<!-- *********************************************************************************************************** -->
<xsl:function name="shared:is-absolute-uri" as="xs:boolean">
<xsl:param name="uri" as="xs:string?"/>
<xsl:sequence select="matches($uri,'^[a-z]+:')"/>
</xsl:function>
<!-- *********************************************************************************************************** -->
<xsl:function name="shared:is-valid" as="xs:boolean">
<xsl:param name="entity" as="element()"/>
<xsl:param name="validityDate" as="xs:string"/>
<xsl:sequence select="$validityDate ge $entity/@validFromDate and $validityDate le $entity/@validToDate"/>
</xsl:function>
<!-- *********************************************************************************************************** -->
<xsl:template name="shared:json-to-xml">
<xsl:param name="options" as="map(*)"/>
<xsl:variable name="startTime" select="saxon:timestamp()"/>
<xsl:sequence select="$startTime[shared:always-false()]"/>
<xsl:call-template name="shared:write">
<xsl:with-param name="output" select="shared:json-to-xml($options)"/>
</xsl:call-template>
<xsl:sequence select="shared:log-execution-time($startTime)"/>
</xsl:template>
<!-- *********************************************************************************************************** -->
<xsl:function name="shared:json-to-xml" as="map(*)">
<xsl:param name="options" as="map(*)"/>
<xsl:sequence select="shared:log('DEBUG', concat('Transforming ', $options?source, ' to ', $options?target))"/>
<xsl:map-entry key="$options?target">
<xsl:document>
<xsl:sequence select="json-to-xml(unparsed-text($options?source))"/>
</xsl:document>
</xsl:map-entry>
</xsl:function>
<!-- *********************************************************************************************************** -->
<xsl:function name="shared:list" as="xs:string*">
<xsl:param name="dir" as="xs:string"/>
<xsl:sequence select="shared:list($dir, false(), '*')"/>
</xsl:function>
<!-- *********************************************************************************************************** -->
<xsl:function name="shared:list" as="xs:string*">
<xsl:param name="dir" as="xs:string"/>
<xsl:param name="recursive" as="xs:boolean"/>
<xsl:sequence select="shared:list($dir, $recursive, '*')"/>
</xsl:function>
<!-- *********************************************************************************************************** -->
<xsl:function name="shared:list" as="xs:string*">
<xsl:param name="dir" as="xs:string"/>
<xsl:param name="recursive" as="xs:boolean"/>
<xsl:param name="pattern" as="xs:string"/>
<xsl:if test="file:exists($dir)">
<xsl:for-each select="file:list($dir, $recursive, $pattern)">
<xsl:sort select="."/>
<xsl:sequence select="translate(., '\', '/')"/>
</xsl:for-each>
</xsl:if>
</xsl:function>
<!-- *********************************************************************************************************** -->
<xsl:function name="shared:list-files" as="xs:string*">
<xsl:param name="dir" as="xs:string"/>
<xsl:sequence select="shared:list-files($dir, false(), '*')"/>
</xsl:function>
<!-- *********************************************************************************************************** -->
<xsl:function name="shared:list-files" as="xs:string*">
<xsl:param name="dir" as="xs:string"/>
<xsl:param name="recursive" as="xs:boolean"/>
<xsl:sequence select="shared:list-files($dir, $recursive, '*')"/>
</xsl:function>
<!-- *********************************************************************************************************** -->
<xsl:function name="shared:list-files" as="xs:string*">
<xsl:param name="dir" as="xs:string"/>
<xsl:param name="recursive" as="xs:boolean"/>
<xsl:param name="pattern" as="xs:string"/>
<xsl:sequence select="shared:list($dir, $recursive, $pattern)[file:is-file(concat($dir, .))]"/>
</xsl:function>
<!-- *********************************************************************************************************** -->
<xsl:function name="shared:list-folders" as="xs:string*">
<xsl:param name="dir" as="xs:string"/>
<xsl:sequence select="shared:list-folders($dir, false(), '*')"/>
</xsl:function>
<!-- *********************************************************************************************************** -->
<xsl:function name="shared:list-folders" as="xs:string*">
<xsl:param name="dir" as="xs:string"/>
<xsl:param name="recursive" as="xs:boolean"/>
<xsl:sequence select="shared:list-folders($dir, $recursive, '*')"/>
</xsl:function>
<!-- *********************************************************************************************************** -->
<xsl:function name="shared:list-folders" as="xs:string*">
<xsl:param name="dir" as="xs:string"/>
<xsl:param name="recursive" as="xs:boolean"/>
<xsl:param name="pattern" as="xs:string"/>
<xsl:sequence select="shared:list($dir, $recursive, $pattern)[file:is-dir(concat($dir, .))]"/>
</xsl:function>
<!-- *********************************************************************************************************** -->
<xsl:function name="shared:log">
<xsl:param name="level" as="xs:string"/>
<xsl:param name="message" as="item()*"/>
<xsl:sequence select="ext:log($level, serialize($message))"/>
</xsl:function>
<!-- *********************************************************************************************************** -->
<xsl:function name="shared:log-error">
<xsl:param name="description" as="xs:string"/>
<xsl:param name="module" as="xs:string"/>
<xsl:param name="line-number" as="xs:integer"/>
<xsl:sequence select="shared:log('ERROR', concat('description: ', $description))"/>
<xsl:sequence select="shared:log('ERROR', concat('module: ', $module))"/>
<xsl:sequence select="shared:log('ERROR', concat('line-number: ', $line-number))"/>
</xsl:function>
<!-- *********************************************************************************************************** -->
<xsl:function name="shared:log-execution-time">
<xsl:param name="startTime" as="xs:dateTime"/>
<!-- Use xs:dayTimeDuration instead of xs:duration as said in Saxon's documentation -->
<xsl:sequence select="shared:log('DEBUG', concat('Execution time: ', (saxon:timestamp() - $startTime) div xs:dayTimeDuration('PT1S'), 's'))"/>
</xsl:function>
<!-- *********************************************************************************************************** -->
<xsl:function name="shared:log-transform-options">
<xsl:param name="options" as="map(*)"/>
<xsl:variable name="source-location" select="map:get($options, 'source-location')"/>
<xsl:variable name="base-output-uri" select="map:get($options, 'base-output-uri')"/>
<xsl:variable name="stylesheet-location" select="map:get($options, 'stylesheet-location')"/>
<xsl:variable name="stylesheet-params" select="map:get($options, 'stylesheet-params')"/>
<xsl:choose>
<xsl:when test="exists($source-location) and exists($base-output-uri)">
<xsl:sequence select="shared:log('INFO', concat('Transforming ',$source-location))"/>
<xsl:sequence select="shared:log('INFO', concat($TAB,'into ',$base-output-uri))"/>
<xsl:sequence select="shared:log('INFO', concat($TAB,'using ',$stylesheet-location))"/>
</xsl:when>
<xsl:when test="exists($source-location) and empty($base-output-uri)">
<xsl:sequence select="shared:log('INFO', concat('Transforming ',$source-location))"/>
<xsl:sequence select="shared:log('INFO', concat($TAB,'using ',$stylesheet-location))"/>
</xsl:when>
<xsl:when test="empty($source-location) and exists($base-output-uri)">
<xsl:sequence select="shared:log('INFO', concat('Generating ',$base-output-uri))"/>
<xsl:sequence select="shared:log('INFO', concat($TAB,'using ',$stylesheet-location))"/>
</xsl:when>
<xsl:otherwise>
<xsl:sequence select="shared:log('INFO', concat('Launching ',$stylesheet-location))"/>
</xsl:otherwise>
</xsl:choose>
<xsl:if test="exists($stylesheet-params)">
<xsl:for-each select="map:keys($stylesheet-params)">
<xsl:sort select="string(.)"/>
<xsl:variable name="value" select="map:get($stylesheet-params, .)"/>
<xsl:variable name="parameter-value"
select="
if ($value instance of node()) then (document-uri($value), path($value))[1] else
if (contains(lower-case(string(.)), 'password')) then replace($value, '.', '*') else
string-join($value, ' ')"/>
<xsl:sequence select="shared:log('INFO', concat($TAB,'parameter ',.,'=',$parameter-value))"/>
</xsl:for-each>
</xsl:if>
</xsl:function>
<!-- *********************************************************************************************************** -->
<xsl:function name="shared:max" as="item()?">
<xsl:param name="pItems" as="item()*"/>
<xsl:for-each select="$pItems">
<xsl:sort select="." order="descending"/>
<xsl:if test="position() eq 1">
<xsl:sequence select="."/>
</xsl:if>
</xsl:for-each>
</xsl:function>
<!-- *********************************************************************************************************** -->
<xsl:function name="shared:merge-versions">
<xsl:param name="pVersions"/>
<xsl:variable name="versionsXML">
<xsl:sequence select="$pVersions"/>
</xsl:variable>
<xsl:for-each-group select="$versionsXML/*" group-starting-with="*[not(preceding-sibling::*[1]/@digest = @digest and shared:next-day(preceding-sibling::*[1]/@validToDate) = @validFromDate)]">
<xsl:choose>
<xsl:when test="count(current-group()) = 1">
<xsl:sequence select="current-group()"/>
</xsl:when>
<xsl:otherwise>
<xsl:variable name="newValidFromDate" select="current-group()[1]/@validFromDate"/>
<xsl:variable name="newValidToDate" select="current-group()[last()]/@validToDate"/>
<xsl:sequence select="shared:add-or-update-attributes(current-group()[1], ('validFromDate', 'validToDate'), ($newValidFromDate, $newValidToDate))"/>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each-group>
</xsl:function>
<!-- *********************************************************************************************************** -->
<xsl:function name="shared:merge-versions-without-digest" as="element()*">
<xsl:param name="versions" as="element()*"/>
<xsl:variable name="versionsWithDigest" select="shared:add-digest-for-element-without-validity($versions)"/>
<xsl:variable name="mergedVersions" select="shared:merge-versions($versionsWithDigest)"/>
<xsl:sequence select="shared:remove-digest($mergedVersions)"/>
</xsl:function>
<!-- *********************************************************************************************************** -->
<xsl:function name="shared:min" as="item()?">
<xsl:param name="pItems" as="item()*"/>
<xsl:for-each select="$pItems">
<xsl:sort select="." order="ascending"/>
<xsl:if test="position() eq 1">
<xsl:sequence select="."/>
</xsl:if>
</xsl:for-each>
</xsl:function>
<!-- *********************************************************************************************************** -->
<xsl:function name="shared:month-of-year" as="xs:string">
<xsl:param name="date" as="xs:string"/>
<xsl:sequence select="format-date(xs:date($date), '[Y]-[M,2]')"/>
</xsl:function>
<!-- *********************************************************************************************************** -->
<xsl:function name="shared:move" as="empty-sequence()">
<xsl:param name="source" as="xs:string"/>
<xsl:param name="target" as="xs:string"/>
<xsl:if test="file:exists($source) and $source ne $target">
<xsl:sequence select="shared:log('DEBUG', concat('Moving ', $source, ' to ', $target))"/>
<xsl:sequence select="file:move($source, $target)"/>
</xsl:if>
</xsl:function>
<!-- *********************************************************************************************************** -->
<xsl:function name="shared:move-files">
<xsl:param name="source" as="xs:string"/>
<xsl:param name="target" as="xs:string"/>
<xsl:if test="file:is-dir($source) and file:is-dir($target)">
<xsl:for-each select="shared:list-files($source)">
<xsl:sequence select="shared:move(concat($source, .), $target)"/>
</xsl:for-each>
</xsl:if>
</xsl:function>
<!-- *********************************************************************************************************** -->
<xsl:function name="shared:next-day" as="xs:string">
<xsl:param name="date"/>
<xsl:sequence select="shared:shift-day($date, 1)"/>
</xsl:function>
<!-- *********************************************************************************************************** -->
<xsl:function name="shared:open-file" as="document-node()?">
<xsl:param name="pathAndFileName" as="xs:string"/>
<xsl:variable name="uri" select="shared:path-to-uri($pathAndFileName)"/>
<xsl:sequence select="shared:doc($uri)"/>
</xsl:function>
<!-- *********************************************************************************************************** -->
<xsl:function name="shared:open-file" as="document-node()?">
<xsl:param name="baseURI" as="xs:string"/>
<xsl:param name="fileName" as="xs:string"/>
<xsl:variable name="pathAndFileName" select="concat($baseURI, $fileName)"/>
<xsl:sequence select="shared:open-file($pathAndFileName)"/>
</xsl:function>
<!-- *********************************************************************************************************** -->
<xsl:function name="shared:open-file-without-logging" as="document-node()?">
<xsl:param name="pathAndFileName" as="xs:string"/>
<xsl:variable name="uri" select="shared:path-to-uri($pathAndFileName)"/>
<xsl:sequence select="if (doc-available($uri)) then saxon:discard-document(doc($uri)) else ()"/>
</xsl:function>
<!-- *********************************************************************************************************** -->
<xsl:function name="shared:open-file-without-logging" as="document-node()?">
<xsl:param name="baseURI" as="xs:string"/>
<xsl:param name="fileName" as="xs:string"/>
<xsl:variable name="pathAndFileName" select="concat($baseURI, $fileName)"/>
<xsl:sequence select="shared:open-file-without-logging($pathAndFileName)"/>
</xsl:function>
<!-- *********************************************************************************************************** -->
<xsl:function name="shared:open-files" as="document-node()*">
<xsl:param name="baseURI" as="xs:string"/>
<xsl:param name="pattern" as="xs:string"/>
<xsl:variable name="uri" select="shared:path-to-uri($baseURI)"/>
<xsl:variable name="files" select="collection(concat($uri, '?select=', $pattern))"/>
<xsl:sequence select="shared:log('DEBUG', concat('Nb of loaded files = ', count($files)))"/>
<xsl:for-each select="$files">
<xsl:sort select="document-uri(.)"/>
<xsl:sequence select="saxon:discard-document(.)"/>
</xsl:for-each>
</xsl:function>
<!-- *********************************************************************************************************** -->
<xsl:function name="shared:output-parameters" as="map(*)">
<xsl:map>
<xsl:map-entry key="'xml'">
<xsl:map>
<xsl:map-entry key="'method'" select="'xml'"/>
<xsl:map-entry key="'omit-xml-declaration'" select="false()"/>
<xsl:map-entry key="'indent'" select="true()"/>
<xsl:map-entry key="QName('http://saxon.sf.net/', 'indent-spaces')" select="0"/>
<xsl:map-entry key="QName('http://saxon.sf.net/', 'line-length')" select="100000"/>
<xsl:map-entry key="QName('http://saxon.sf.net/', 'attribute-order')" select="QName('', 'xxx')"/>
</xsl:map>
</xsl:map-entry>
<xsl:map-entry key="'html'">
<xsl:map>
<xsl:map-entry key="'method'" select="'html'"/>
<xsl:map-entry key="'indent'" select="true()"/>
<xsl:map-entry key="QName('http://saxon.sf.net/', 'indent-spaces')" select="0"/>
<xsl:map-entry key="QName('http://saxon.sf.net/', 'line-length')" select="100000"/>
<xsl:map-entry key="QName('http://saxon.sf.net/', 'attribute-order')" select="QName('', 'xxx')"/>
</xsl:map>
</xsl:map-entry>
<xsl:map-entry key="'xhtml'">
<xsl:map>
<xsl:map-entry key="'method'" select="'xhtml'"/>
<xsl:map-entry key="'indent'" select="true()"/>
<xsl:map-entry key="QName('http://saxon.sf.net/', 'indent-spaces')" select="0"/>
<xsl:map-entry key="QName('http://saxon.sf.net/', 'line-length')" select="100000"/>
<xsl:map-entry key="QName('http://saxon.sf.net/', 'attribute-order')" select="QName('', 'xxx')"/>
</xsl:map>
</xsl:map-entry>
<xsl:map-entry key="'json'">
<xsl:map>
<xsl:map-entry key="'method'" select="'json'"/>
</xsl:map>
</xsl:map-entry>
<xsl:map-entry key="'txt'">
<xsl:map>
<xsl:map-entry key="'method'" select="'text'"/>
</xsl:map>
</xsl:map-entry>
<xsl:map-entry key="'csv'">
<xsl:map>
<xsl:map-entry key="'method'" select="'text'"/>
</xsl:map>
</xsl:map-entry>
<xsl:map-entry key="'hkt'">
<xsl:map>
<xsl:map-entry key="'method'" select="'text'"/>
</xsl:map>
</xsl:map-entry>
</xsl:map>
</xsl:function>
<!-- *********************************************************************************************************** -->
<xsl:function name="shared:output-parameters-for-uri" as="map(*)">
<xsl:param name="uri" as="xs:string"/>
<xsl:sequence select="($output-parameters(lower-case(shared:file-extension($uri))), $output-parameters('xml'))[1]"/>
</xsl:function>
<!-- *********************************************************************************************************** -->
<xsl:function name="shared:path-to-uri" as="xs:string">
<xsl:param name="path" as="xs:string"/>
<xsl:sequence select="file:path-to-uri($path)"/>
</xsl:function>
<!-- *********************************************************************************************************** -->
<xsl:function name="shared:path-to-uri" as="xs:string">
<xsl:param name="baseURI" as="xs:string"/>
<xsl:param name="fileName" as="xs:string"/>
<xsl:variable name="path" select="concat($baseURI, $fileName)"/>
<xsl:sequence select="file:path-to-uri($path)"/>
</xsl:function>
<!-- *********************************************************************************************************** -->
<xsl:function name="shared:previous-day" as="xs:string">
<xsl:param name="date"/>
<xsl:sequence select="shared:shift-day($date, -1)"/>
</xsl:function>
<!-- *********************************************************************************************************** -->
<xsl:function name="shared:radians-to-degrees" as="xs:double">
<xsl:param name="angleInRadians" as="xs:double"/>
<xsl:sequence select="$angleInRadians div math:pi() * 180"/>
</xsl:function>
<!-- *********************************************************************************************************** -->
<xsl:function name="shared:remove-attributes">
<xsl:param name="elements"/>
<xsl:param name="names"/>
<xsl:for-each select="$elements">
<xsl:copy>
<xsl:sequence select="(@*[not(name() = $names)], node())"/>
</xsl:copy>
</xsl:for-each>
</xsl:function>
<!-- *********************************************************************************************************** -->
<xsl:function name="shared:remove-digest">
<xsl:param name="pElement"/>
<xsl:for-each select="$pElement">
<xsl:sequence select="shared:remove-attributes(., 'digest')"/>
</xsl:for-each>
</xsl:function>
<!-- *********************************************************************************************************** -->
<xsl:function name="shared:shift-day" as="xs:string">
<xsl:param name="date"/>
<xsl:param name="nbOfDays"/>
<xsl:variable name="pDate" select="xs:date($date)"/>
<xsl:variable name="pNbOfDays" select="xs:integer($nbOfDays)"/>
<xsl:choose>
<xsl:when test="$pNbOfDays gt 0">
<!-- Add abs to avoid compilation warning -->
<xsl:value-of select="$pDate + xs:dayTimeDuration(concat('P',abs($pNbOfDays),'D'))"/>
</xsl:when>
<xsl:when test="$pNbOfDays lt 0">
<xsl:value-of select="$pDate - xs:dayTimeDuration(concat('P',abs($pNbOfDays),'D'))"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$pDate"/>
</xsl:otherwise>
</xsl:choose>
</xsl:function>
<!-- *********************************************************************************************************** -->
<xsl:function name="shared:sind" as="xs:double?">
<xsl:param name="angleInDegrees" as="xs:double?"/>
<xsl:sequence select="if (exists($angleInDegrees)) then math:sin(shared:degrees-to-radians($angleInDegrees)) else ()"/>
</xsl:function>
<!-- *********************************************************************************************************** -->
<xsl:function name="shared:sleep">
<xsl:param name="seconds" as="xs:integer"/>
<xsl:sequence select="shared:log('DEBUG', concat('Sleeping for ', $seconds, ' seconds...'))"/>
<xsl:sequence select="thread:sleep(1000*$seconds)"/>
</xsl:function>
<!-- *********************************************************************************************************** -->
<xsl:function name="shared:split" as="element()*">
<xsl:param name="element" as="element()"/>
<xsl:param name="entityVersions" as="element()*"/>
<xsl:param name="purgeDate" as="xs:string"/>
<xsl:variable name="validities" select="shared:get-validities($element, $entityVersions, $purgeDate)"/>
<xsl:for-each select="$validities">
<xsl:variable name="validFromDate" select="@validFromDate"/>
<xsl:variable name="validToDate" select="@validToDate"/>
<xsl:for-each select="$element">
<xsl:copy>
<xsl:sequence select="@* except (@validFromDate, @validToDate)"/>
<xsl:attribute name="validFromDate" select="$validFromDate"/>
<xsl:attribute name="validToDate" select="$validToDate"/>
<!-- Copy all child elements to avoid losing info -->
<xsl:sequence select="*"/>
</xsl:copy>
</xsl:for-each>
</xsl:for-each>
</xsl:function>
<!-- *********************************************************************************************************** -->
<xsl:function name="shared:tand" as="xs:double?">
<xsl:param name="angleInDegrees" as="xs:double?"/>
<xsl:sequence select="if (exists($angleInDegrees)) then math:tan(shared:degrees-to-radians($angleInDegrees)) else ()"/>
</xsl:function>
<!-- *********************************************************************************************************** -->
<xsl:function name="shared:to-folder" as="xs:string?">
<xsl:param name="property" as="xs:string?"/>
<xsl:for-each select="$property">
<xsl:for-each select="translate(., '\', '/')">
<xsl:sequence select="if (ends-with(., '/')) then . else concat(., '/')"/>
</xsl:for-each>
</xsl:for-each>
</xsl:function>
<!-- *********************************************************************************************************** -->
<xsl:function name="shared:total-minutes-from-time" as="xs:integer">
<xsl:param name="time" as="xs:string"/>
<!-- hours-from-time() returns 0 for 24:00:00 -->
<xsl:sequence select="60*xs:integer(substring($time, 1, 2)) + minutes-from-time(xs:time($time))"/>
</xsl:function>
<!-- *********************************************************************************************************** -->
<xsl:template name="shared:transform">
<xsl:param name="options" as="map(*)"/>
<xsl:variable name="startTime" select="saxon:timestamp()"/>
<xsl:sequence select="$startTime[shared:always-false()]"/>
<xsl:call-template name="shared:write">
<xsl:with-param name="output" select="shared:transform($options)"/>
</xsl:call-template>
<xsl:sequence select="shared:log-execution-time($startTime)"/>
</xsl:template>
<!-- *********************************************************************************************************** -->
<xsl:function name="shared:transform" as="map(*)">
<xsl:param name="options" as="map(*)"/>
<xsl:sequence select="shared:log-transform-options($options)"/>
<xsl:sequence select="transform($options)"/>
</xsl:function>
<!-- *********************************************************************************************************** -->
<xsl:template name="shared:transform-with-saxon">
<xsl:param name="options" as="map(*)"/>
<xsl:variable name="startTime" select="saxon:timestamp()"/>
<xsl:sequence select="$startTime[shared:always-false()]"/>
<xsl:call-template name="shared:write">
<xsl:with-param name="output" select="shared:transform-with-saxon($options)"/>
</xsl:call-template>
<xsl:sequence select="shared:log-execution-time($startTime)"/>
</xsl:template>
<!-- *********************************************************************************************************** -->
<xsl:function name="shared:transform-with-saxon" as="map(*)">
<xsl:param name="options" as="map(*)"/>
<xsl:sequence select="shared:log-transform-options($options)"/>
<xsl:variable name="stylesheet" select="saxon:compile-stylesheet(doc($options?stylesheet-location))"/>
<xsl:variable name="source"
select="if (exists($options?source-node)) then $options?source-node else if (exists($options?source-location)) then doc($options?source-location) else shared:dummy-doc()"/>
<xsl:variable name="base-output-uri" select="($options?base-output-uri, 'output')[1]"/>
<xsl:map-entry key="$base-output-uri" select="saxon:transform($stylesheet, $source, $options?stylesheet-params)"/>
</xsl:function>
<!-- *********************************************************************************************************** -->
<xsl:function name="shared:unzip">
<xsl:param name="source-file" as="xs:string"/>
<xsl:param name="target-folder" as="xs:string"/>
<!-- Code inspired by arch:to-files(), see http://expath.org/spec/archive/editor#fn.to.files Archive Module, EXPath Candidate Module 12 May 2014 -->
<xsl:sequence select="shared:log('DEBUG', concat('Unzipping ', $source-file, ' to ', $target-folder))"/>
<xsl:variable name="archive" select="file:read-binary($source-file)"/>
<xsl:variable name="entries" select="arch:entries($archive)"/>
<xsl:variable name="dirs" select="$entries[ends-with(., '/')]"/>
<xsl:for-each select="$dirs">
<xsl:sequence select="file:create-dir(concat($target-folder, .))"/>
</xsl:for-each>
<!-- Tuning: extract all binary data in one call -->
<xsl:variable name="files" select="$entries except $dirs"/>
<xsl:variable name="binary-data" select="arch:extract-binary($archive, $files)"/>
<xsl:for-each select="$files">
<xsl:variable name="index" select="position()"/>
<xsl:sequence select="file:write-binary(concat($target-folder, .), $binary-data[$index])"/>
</xsl:for-each>
</xsl:function>
<!-- *********************************************************************************************************** -->
<xsl:function name="shared:unzip-ext">
<xsl:param name="source-file" as="xs:string"/>
<xsl:param name="target-folder" as="xs:string"/>
<xsl:sequence select="shared:log('DEBUG', concat('Unzipping ', $source-file, ' to ', $target-folder))"/>
<xsl:sequence select="ext:unzip($source-file, $target-folder)"/>
</xsl:function>
<!-- *********************************************************************************************************** -->
<xsl:function name="shared:UUID" as="xs:string">
<xsl:param name="element" as="item()*"/>
<xsl:sequence select="ext:UUID(serialize($element))"/>
</xsl:function>
<!-- *********************************************************************************************************** -->
<xsl:function name="shared:week-of-year" as="xs:string">
<xsl:param name="date" as="xs:string"/>
<xsl:variable name="day-of-week" select="shared:day-of-week($date)"/>
<xsl:variable name="ref-Thursday" select="xs:date(shared:shift-day($date, 4 - $day-of-week))"/>
<xsl:sequence select="format-date($ref-Thursday, '[Y]-[W,2]', (), 'ISO', ())"/>
</xsl:function>
<!-- *********************************************************************************************************** -->
<xsl:template name="shared:validate">
<xsl:param name="options" as="map(*)"/>
<xsl:variable name="startTime" select="saxon:timestamp()"/>
<xsl:sequence select="$startTime[shared:always-false()]"/>
<xsl:sequence select="shared:validate($options)"/>
<xsl:sequence select="shared:log-execution-time($startTime)"/>
</xsl:template>
<!-- *********************************************************************************************************** -->
<xsl:function name="shared:validate">
<xsl:param name="options" as="map(*)"/>
<xsl:sequence select="shared:log('DEBUG', concat('Validating ', $options?xml, ' with ', $options?xsd))"/>
<xsl:sequence select="ext:validate($options?xml, $options?xsd)"/>
</xsl:function>
<!-- *********************************************************************************************************** -->
<xsl:template name="shared:write">
<xsl:param name="output" as="map(*)"/>
<xsl:for-each select="map:keys($output)">
<xsl:sort select="."/>
<xsl:sequence select="shared:write(., map:get($output, .))"/>
</xsl:for-each>
</xsl:template>
<!-- *********************************************************************************************************** -->
<xsl:function name="shared:write">
<xsl:param name="href" as="xs:string"/>
<xsl:param name="items" as="item()*"/>
<!-- Exclude default added "output" when base-output-uri is absent by checking is-absolute-uri() -->
<xsl:if test="shared:is-absolute-uri($href)">
<xsl:sequence select="shared:log('DEBUG', concat('Exporting ', $href))"/>
<xsl:variable name="params" select="shared:output-parameters-for-uri($href)"/>
<!-- Use file:write or file:write-text instead of xsl:result-document because the latter doesn't work when calling nested transform() functions -->
<xsl:sequence select="file:write-text($href, serialize($items, $params))"/>
</xsl:if>
</xsl:function>
<!-- *********************************************************************************************************** -->
<xsl:function name="shared:zip">
<xsl:param name="source-folder" as="xs:string"/>
<xsl:param name="target-file" as="xs:string"/>
<xsl:sequence select="shared:zip($source-folder, '', $target-file)"/>
</xsl:function>
<!-- *********************************************************************************************************** -->
<xsl:function name="shared:zip">
<xsl:param name="source-folder" as="xs:string"/>
<xsl:param name="source-files" as="xs:string*"/>
<xsl:param name="target-file" as="xs:string"/>
<!-- Code inspired by arch:from-files(), see http://expath.org/spec/archive/editor#fn.from.files Archive Module, EXPath Candidate Module 12 May 2014 -->
<xsl:sequence select="shared:log('DEBUG', concat('Zipping ', $source-folder, ' to ', $target-file))"/>
<xsl:variable name="absolute.files" select="for $f in $source-files return concat($source-folder, $f)"/>
<xsl:variable name="all" as="xs:string*" select="for $f in $absolute.files return if(file:is-dir($f)) then (for $f1 in shared:list($f,true()) return concat($f,$f1)) else $f"/>
<xsl:variable name="content" as="xs:base64Binary*" select="for $f in $all return if(file:is-dir($f)) then xs:base64Binary('') else file:read-binary($f)"/>
<xsl:variable name="relative.names" select="for $n in $all return replace($n, $source-folder, '')"/>
<xsl:variable name="archive" select="arch:create($relative.names, $content)"/>
<xsl:sequence select="file:write-binary($target-file, $archive)"/>
</xsl:function>
<!-- *********************************************************************************************************** -->
<xsl:function name="shared:zip-ext">
<xsl:param name="source-folder" as="xs:string"/>
<xsl:param name="target-file" as="xs:string"/>
<xsl:sequence select="shared:log('DEBUG', concat('Zipping ', $source-folder, ' to ', $target-file))"/>
<xsl:sequence select="ext:zip($source-folder, $target-file)"/>
</xsl:function>
<!-- *********************************************************************************************************** -->
</xsl:stylesheet>
(3-3/8)