Project

Profile

Help

Support #4934 » create-trains-by-day.xslt

Johan Gheys, 2021-09-20 11:38

 
<?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:file="http://expath.org/ns/file"
xmlns:cern="http://www.infrabel.be/Artemis/Timetable"
xmlns:shared="urn:shared-functions"
xmlns:local="urn:local-functions"
version="2.0">
<xsl:import href="/shared/shared-functions.xslt"/>
<xsl:param name="output-folder" as="xs:string"/>
<xsl:param name="run-file" as="xs:string"/>
<xsl:param name="lineSection-xml" as="document-node()"/>
<xsl:param name="bulletin-xml" as="document-node()"/>
<xsl:param name="end-digit" as="xs:integer"/>
<xsl:strip-space elements="*"/>
<xsl:variable name="runXML" select="shared:open-file($run-file)"/>
<xsl:variable name="run" select="$runXML/run"/>
<xsl:variable name="timetable-folder" select="local:timetable-folder()"/>
<xsl:variable name="new-layer" select="local:new-layer()"/>
<xsl:key name="by-lineSectionId" match="*" use="@lineSectionId"/>
<!-- *********************************************************************************************************** -->
<xsl:template match="trains">
<xsl:apply-templates select="train[@lastUpdateDate = current()/@creationDate][ends-with(@trainNo, string($end-digit))]"/>
</xsl:template>
<!-- *********************************************************************************************************** -->
<xsl:template match="train">
<xsl:if test="position() = (1, last()) or position() mod 1000 = 0">
<xsl:sequence select="shared:log('DEBUG', concat('Processing train ', position(), '/', last()))"/>
</xsl:if>
<!-- <xsl:if test="@trainNo = (10, 123, 3655, 3668, 3690, 3691)">-->
<xsl:variable name="trainXML" select="shared:open-file($timetable-folder, @href)"/>
<xsl:variable name="train-1" select="local:get-global-and-localTrainVariant($trainXML, $run/@selectionLayer, $run/@creationDate, $run/@purgeDate)"/>
<xsl:variable name="train-2" select="local:add-tractionSections($train-1)"/>
<xsl:variable name="train-3" select="local:group-by-midnight($train-2)"/>
<xsl:variable name="train" select="local:sort-global-and-localTrainVariant($train-3)"/>
<xsl:variable name="fileName" select="shared:path-to-uri($output-folder, @href)"/>
<xsl:result-document href="{$fileName}" method="xml">
<xsl:sequence select="$train"/>
</xsl:result-document>
<!-- </xsl:if>-->
</xsl:template>
<!-- *********************************************************************************************************** -->
<xsl:template mode="add-position-and-midnight" match="*">
<xsl:element name="{local-name()}">
<xsl:sequence select="@*"/>
<xsl:apply-templates mode="add-position-and-midnight"/>
</xsl:element>
</xsl:template>
<!-- *********************************************************************************************************** -->
<xsl:template mode="add-position-and-midnight" match="timetablePoints">
<xsl:element name="{local-name()}">
<!-- Exclude ptrefPoint to have a clean value for position -->
<xsl:apply-templates mode="add-position-and-midnight" select="point"/>
</xsl:element>
</xsl:template>
<!-- *********************************************************************************************************** -->
<xsl:template mode="add-position-and-midnight" match="point">
<xsl:element name="{local-name()}">
<!-- position -->
<xsl:attribute name="position" select="position()"/>
<!-- inMidnight -->
<xsl:choose>
<xsl:when test="exists(@inTime) and @inTime ne '00:00:00'">
<xsl:attribute name="inMidnight" select="(@inMidnight, 0)[1]"/>
<xsl:attribute name="inTime" select="@inTime"/>
</xsl:when>
<xsl:when test="exists(@inTime) and @inTime eq '00:00:00'">
<xsl:attribute name="inMidnight" select="(@inMidnight, 0)[1] - 1"/>
<xsl:attribute name="inTime" select="'24:00:00'"/>
</xsl:when>
</xsl:choose>
<!-- outMidnight -->
<xsl:if test="exists(@outTime)">
<xsl:attribute name="outMidnight" select="(@outMidnight, 0)[1]"/>
<xsl:attribute name="outTime" select="@outTime"/>
</xsl:if>
<xsl:sequence select="@* except (@inMidnight, @inTime, @outMidnight, @outTime)"/>
<xsl:apply-templates mode="add-position-and-midnight"/>
</xsl:element>
</xsl:template>
<!-- *********************************************************************************************************** -->
<xsl:template mode="add-position-and-midnight" match="lineSection">
<xsl:param name="departureDate" as="xs:string" tunnel="yes"/>
<xsl:variable name="lineSection" select="local:get-lineSection-for-id(@id, $departureDate)"/>
<xsl:element name="{local-name()}">
<xsl:attribute name="lineId" select="$lineSection/@lineId"/>
<xsl:attribute name="lineName" select="$lineSection/@lineName"/>
<xsl:sequence select="@*"/>
<xsl:apply-templates mode="add-position-and-midnight"/>
</xsl:element>
</xsl:template>
<!-- *********************************************************************************************************** -->
<xsl:template mode="add-position-and-midnight" match="layerVPK|vectors|inInfos|outInfos"/>
<!-- *********************************************************************************************************** -->
<xsl:template mode="add-tractionSections group-by-midnight" match="*">
<xsl:copy>
<xsl:sequence select="@*"/>
<xsl:apply-templates mode="#current"/>
</xsl:copy>
</xsl:template>
<!-- *********************************************************************************************************** -->
<xsl:template mode="add-tractionSections" match="localTrainVariant">
<xsl:variable name="tractionSections" select="local:create-tractionSections-from-timetable(timetablePoints)"/>
<xsl:copy>
<xsl:sequence select="@*, *"/>
<xsl:element name="tractionSections">
<xsl:sequence select="$tractionSections"/>
</xsl:element>
</xsl:copy>
</xsl:template>
<!-- *********************************************************************************************************** -->
<xsl:template mode="group-by-midnight" match="timetablePoints">
<xsl:variable name="timetablePoints" select="."/>
<xsl:variable name="localTrainVariant" select="ancestor::localTrainVariant"/>
<xsl:variable name="midnightSections" select="local:create-midnightSections-from-timetable(., $localTrainVariant/@departDay, $localTrainVariant/@destDay)"/>
<xsl:variable name="departureDates" select="$localTrainVariant/departureDate/week/tokenize(., ' ')"/>
<xsl:for-each select="$midnightSections">
<xsl:variable name="currentMidnightSection" select="."/>
<xsl:variable name="dates" select="for $d in $departureDates return shared:shift-day($d, @midnight)"/>
<xsl:variable name="points" select="$timetablePoints/point[(@position - $currentMidnightSection/@outPosition ge 0) and ($currentMidnightSection/@inPosition - @position ge 0)]"/>
<xsl:variable name="tractionSections"
select="$localTrainVariant/tractionSections/tractionSection[(@inPosition - $currentMidnightSection/@outPosition ge 0) and ($currentMidnightSection/@inPosition - @outPosition ge 0)]"/>
<xsl:copy>
<xsl:attribute name="midnight" select="@midnight"/>
<xsl:element name="date">
<xsl:sequence select="shared:group-dates-by-week($dates)"/>
</xsl:element>
<xsl:element name="timetablePoints">
<xsl:sequence select="$points"/>
</xsl:element>
<xsl:element name="tractionSections">
<xsl:sequence select="$tractionSections"/>
</xsl:element>
</xsl:copy>
</xsl:for-each>
</xsl:template>
<!-- *********************************************************************************************************** -->
<xsl:template mode="group-by-midnight" match="tractionSections"/>
<!-- *********************************************************************************************************** -->
<xsl:function name="local:add-tractionSections" as="element(train)">
<xsl:param name="train" as="element()"/>
<xsl:apply-templates select="$train" mode="add-tractionSections"/>
</xsl:function>
<!-- *********************************************************************************************************** -->
<xsl:function name="local:category" as="xs:string">
<xsl:param name="trainType" as="xs:integer"/>
<xsl:param name="trainPAV" as="xs:integer"/>
<xsl:choose>
<xsl:when test="$trainType eq 1 and $trainPAV eq 1">
<xsl:sequence select="'HKV'"/>
</xsl:when>
<xsl:when test="$trainType eq 1 and $trainPAV eq 2">
<xsl:sequence select="'HPV'"/>
</xsl:when>
<xsl:when test="$trainType eq 2 and $trainPAV eq 1">
<xsl:sequence select="'HKM'"/>
</xsl:when>
<xsl:when test="$trainType eq 2 and $trainPAV eq 2">
<xsl:sequence select="'HPM'"/>
</xsl:when>
</xsl:choose>
</xsl:function>
<!-- *********************************************************************************************************** -->
<xsl:function name="local:create-midnightSections-from-timetable" as="element(midnightSection)*">
<xsl:param name="timetablePoints" as="element()"/>
<xsl:param name="departDay" as="xs:integer"/>
<xsl:param name="destDay" as="xs:integer"/>
<xsl:for-each select="$departDay to $destDay">
<xsl:variable name="midnight" select="."/>
<xsl:variable name="selectedPoints" select="$timetablePoints/point[@inMidnight = $midnight or @outMidnight = $midnight]"/>
<xsl:variable name="previousPoint" select="$timetablePoints/point[@inMidnight - $midnight lt 0 or @outMidnight - $midnight lt 0][last()]"/>
<xsl:variable name="nextPoint" select="$timetablePoints/point[@inMidnight -$midnight gt 0 or @outMidnight - $midnight gt 0][1]"/>
<xsl:variable name="fromPoint" select="($previousPoint, $selectedPoints[1])[1]"/>
<xsl:variable name="toPoint" select="($nextPoint, $selectedPoints[last()])[1]"/>
<xsl:if test="exists($fromPoint) and exists($toPoint)">
<xsl:sequence select="local:new-midnightSection($fromPoint/@position, $toPoint/@position, $midnight)"/>
</xsl:if>
</xsl:for-each>
</xsl:function>
<!-- *********************************************************************************************************** -->
<xsl:function name="local:create-tractionSections-from-timetable" as="element(tractionSection)*">
<xsl:param name="timetablePoints" as="element()"/>
<xsl:variable name="tractionCodeChangePoints" select="$timetablePoints/point[position() = (1, last()) or @motorChange = 1]"/>
<xsl:variable name="tractionSections1" as="element()*">
<xsl:for-each select="$tractionCodeChangePoints[position() ne last()]">
<xsl:variable name="index" select="position()"/>
<xsl:variable name="outPoint" select="."/>
<xsl:variable name="inPoint" select="$tractionCodeChangePoints[$index + 1]"/>
<xsl:sequence select="local:new-tractionSection($outPoint, $inPoint)"/>
</xsl:for-each>
</xsl:variable>
<xsl:variable name="tractionSections2" select="local:merge-first-and-second-tractionSections($tractionSections1)"/>
<xsl:sequence select="local:merge-last-and-second-last-tractionSections($tractionSections2)"/>
</xsl:function>
<!-- *********************************************************************************************************** -->
<xsl:function name="local:get-bulletin-for-id" as="element()?">
<xsl:param name="id" as="xs:integer?"/>
<xsl:if test="exists($bulletin-xml)">
<xsl:for-each select="$id">
<xsl:sequence select="key('by-id', string(.), $bulletin-xml)"/>
</xsl:for-each>
</xsl:if>
</xsl:function>
<!-- *********************************************************************************************************** -->
<xsl:function name="local:get-bulletin-name" as="xs:string?">
<xsl:param name="bulletin" as="element()?"/>
<xsl:for-each select="$bulletin">
<xsl:variable name="nameParts" select="tokenize(@name, '-')"/>
<xsl:sequence select="concat($nameParts[2],'-',$nameParts[3])"/>
</xsl:for-each>
</xsl:function>
<!-- *********************************************************************************************************** -->
<xsl:function name="local:get-global-and-localTrainVariant" as="element(train)">
<xsl:param name="trainXML" as="document-node()"/>
<xsl:param name="selectionLayer" as="xs:string"/>
<xsl:param name="creationDate" as="xs:string"/>
<xsl:param name="purgeDate" as="xs:string"/>
<xsl:for-each select="$trainXML">
<xsl:variable name="href" select="file:name(document-uri(.))"/>
<xsl:variable name="gtv" select="cern:trains/globalTrainVariant"/>
<xsl:for-each select="$gtv[1]">
<!--<xsl:if test="@trainNo = (123, 521, 544, 33343, 47524) and ((@departDay, 0)[1] != 0 or (@destDay, 0)[1] != 0)">-->
<xsl:element name="train">
<xsl:attribute name="functionalKey" select="local:get-train-functionalKey(@PAV, @trainNo, @PAVdiscriminator)"/>
<xsl:if test="exists(@PAV)">
<xsl:attribute name="natureCode" select="@PAV"/>
</xsl:if>
<xsl:sequence select="@trainNo"/>
<xsl:if test="exists(@PAVdiscriminator)">
<xsl:attribute name="discriminator" select="@PAVdiscriminator"/>
</xsl:if>
<xsl:attribute name="href" select="$href"/>
<xsl:attribute name="creationDate" select="$creationDate"/>
<xsl:for-each select="$gtv">
<xsl:variable name="currentGtv" select="."/>
<xsl:variable name="departDay" as="xs:integer" select="(@departDay, 0)[1]"/>
<xsl:variable name="destDay" as="xs:integer" select="(@destDay, 0)[1]"/>
<xsl:variable name="gtvDepartureDate" select="shared:get-vector-dates(vectors/vector, $selectionLayer)"/>
<xsl:variable name="dateFrom" select="$gtvDepartureDate[1]"/>
<xsl:variable name="dateTo" select="$gtvDepartureDate[last()]"/>
<xsl:if test="$dateTo ge $purgeDate">
<xsl:element name="globalTrainVariant">
<xsl:attribute name="id" select="@id"/>
<xsl:attribute name="layer" select="$new-layer(@layer)"/>
<xsl:sequence select="@car, @per"/>
<xsl:attribute name="dateFrom" select="$dateFrom"/>
<xsl:attribute name="departDay" select="$departDay"/>
<xsl:attribute name="dateTo" select="$dateTo"/>
<xsl:attribute name="destDay" select="$destDay"/>
<xsl:attribute name="category" select="local:category(@trainType, @trainPAV)"/>
<xsl:attribute name="trainOperator" select="@trainOperator"/>
<xsl:element name="departureDate">
<xsl:sequence select="shared:group-dates-by-week($gtvDepartureDate)"/>
</xsl:element>
<xsl:for-each select="train">
<xsl:variable name="ltvDepartureDate" select="shared:get-vector-dates(vectors/vector, $selectionLayer)"/>
<xsl:variable name="dateFrom" select="$ltvDepartureDate[1]"/>
<xsl:variable name="dateTo" select="$ltvDepartureDate[last()]"/>
<xsl:if test="$dateTo ge $purgeDate">
<xsl:variable name="bulletin" select="local:get-bulletin-for-id(@bulletinId)"/>
<xsl:element name="localTrainVariant">
<xsl:attribute name="id" select="@id"/>
<xsl:attribute name="layer" select="$new-layer(@layer)"/>
<xsl:attribute name="dateFrom" select="$dateFrom"/>
<xsl:attribute name="departDay" select="$departDay"/>
<xsl:attribute name="dateTo" select="$dateTo"/>
<xsl:attribute name="destDay" select="$destDay"/>
<xsl:if test="exists($bulletin)">
<xsl:attribute name="bulletinId" select="$bulletin/@id"/>
<xsl:attribute name="bulletin" select="local:get-bulletin-name($bulletin)"/>
</xsl:if>
<xsl:element name="departureDate">
<xsl:sequence select="shared:group-dates-by-week($ltvDepartureDate)"/>
</xsl:element>
<xsl:apply-templates select="timetablePoints" mode="add-position-and-midnight">
<xsl:with-param name="departureDate" select="$dateTo" tunnel="yes"/>
</xsl:apply-templates>
</xsl:element>
</xsl:if>
</xsl:for-each>
</xsl:element>
</xsl:if>
</xsl:for-each>
</xsl:element>
<!--</xsl:if>-->
</xsl:for-each>
</xsl:for-each>
</xsl:function>
<!-- *********************************************************************************************************** -->
<xsl:function name="local:get-lineSection-for-id" as="element()?">
<xsl:param name="id" as="xs:integer"/>
<xsl:param name="date" as="xs:string"/>
<xsl:sequence select="key('by-id', string($id), $lineSection-xml)[$date >= @validFromDate and @validToDate >= $date]"/>
</xsl:function>
<!-- *********************************************************************************************************** -->
<xsl:function name="local:get-train-functionalKey" as="xs:string">
<xsl:param name="natureCode" as="xs:string?"/>
<xsl:param name="trainNo" as="xs:integer"/>
<xsl:param name="discriminator" as="xs:integer?"/>
<xsl:sequence select="string-join((concat($natureCode, $trainNo), $discriminator),'/')"/>
</xsl:function>
<!-- *********************************************************************************************************** -->
<xsl:function name="local:group-by-midnight" as="element(train)">
<xsl:param name="train" as="element()"/>
<xsl:apply-templates select="$train" mode="group-by-midnight"/>
</xsl:function>
<!-- *********************************************************************************************************** -->
<xsl:function name="local:merge-first-and-second-tractionSections" as="element(tractionSection)*">
<xsl:param name="tractionSections" as="element(tractionSection)*"/>
<xsl:choose>
<xsl:when test="empty($tractionSections[1]/@tractionCode) and exists($tractionSections[2]/@tractionCode)">
<xsl:sequence select="local:new-tractionSection($tractionSections[1]/@outPosition, $tractionSections[2]/@inPosition, $tractionSections[2]/@tractionCode)"/>
<xsl:sequence select="$tractionSections[position() gt 2]"/>
</xsl:when>
<xsl:otherwise>
<xsl:sequence select="$tractionSections"/>
</xsl:otherwise>
</xsl:choose>
</xsl:function>
<!-- *********************************************************************************************************** -->
<xsl:function name="local:merge-last-and-second-last-tractionSections" as="element(tractionSection)*">
<xsl:param name="tractionSections" as="element(tractionSection)*"/>
<xsl:choose>
<xsl:when test="empty($tractionSections[last()]/@tractionCode) and exists($tractionSections[last() - 1]/@tractionCode)">
<xsl:sequence select="$tractionSections[position() lt last() - 1]"/>
<xsl:sequence
select="local:new-tractionSection($tractionSections[last() - 1]/@outPosition, $tractionSections[last()]/@inPosition, $tractionSections[last() - 1]/@tractionCode)"/>
</xsl:when>
<xsl:otherwise>
<xsl:sequence select="$tractionSections"/>
</xsl:otherwise>
</xsl:choose>
</xsl:function>
<!-- *********************************************************************************************************** -->
<xsl:function name="local:new-layer" as="map(*)">
<xsl:map>
<xsl:map-entry key="'S'" select="'season'"/>
<xsl:map-entry key="'D'" select="'daily'"/>
<xsl:map-entry key="'X'" select="'dailyDelete'"/>
</xsl:map>
</xsl:function>
<!-- *********************************************************************************************************** -->
<xsl:function name="local:new-midnightSection" as="element(midnightSection)">
<xsl:param name="outPosition" as="xs:integer"/>
<xsl:param name="inPosition" as="xs:integer"/>
<xsl:param name="midnight" as="xs:integer"/>
<xsl:element name="midnightSection">
<xsl:attribute name="outPosition" select="$outPosition"/>
<xsl:attribute name="inPosition" select="$inPosition"/>
<xsl:attribute name="midnight" select="$midnight"/>
</xsl:element>
</xsl:function>
<!-- *********************************************************************************************************** -->
<xsl:function name="local:new-tractionSection" as="element(tractionSection)">
<xsl:param name="outPoint" as="element(point)"/>
<xsl:param name="inPoint" as="element(point)"/>
<xsl:sequence select="local:new-tractionSection($outPoint/@position, $inPoint/@position, $outPoint/@tractionCode)"/>
</xsl:function>
<!-- *********************************************************************************************************** -->
<xsl:function name="local:new-tractionSection" as="element(tractionSection)">
<xsl:param name="outPosition" as="xs:integer"/>
<xsl:param name="inPosition" as="xs:integer"/>
<xsl:param name="tractionCode" as="xs:string?"/>
<xsl:element name="tractionSection">
<xsl:attribute name="outPosition" select="$outPosition"/>
<xsl:attribute name="inPosition" select="$inPosition"/>
<xsl:if test="exists($tractionCode)">
<xsl:attribute name="tractionCode" select="$tractionCode"/>
</xsl:if>
</xsl:element>
</xsl:function>
<!-- *********************************************************************************************************** -->
<xsl:function name="local:sort-global-and-localTrainVariant" as="element()">
<xsl:param name="train" as="element()"/>
<xsl:for-each select="$train">
<xsl:copy>
<xsl:sequence select="@*"/>
<xsl:for-each select="globalTrainVariant">
<xsl:sort select="@layer ne 'season'"/>
<xsl:sort select="@dateFrom"/>
<xsl:copy>
<xsl:sequence select="@*, * except localTrainVariant"/>
<xsl:perform-sort select="localTrainVariant">
<xsl:sort select="@layer ne 'season'"/>
<xsl:sort select="@dateFrom"/>
</xsl:perform-sort>
</xsl:copy>
</xsl:for-each>
</xsl:copy>
</xsl:for-each>
</xsl:function>
<!-- *********************************************************************************************************** -->
<xsl:function name="local:timetable-folder" as="xs:string">
<xsl:sequence select="concat($run/@last-publish-folder, 'timetable/')"/>
</xsl:function>
<!-- *********************************************************************************************************** -->
</xsl:stylesheet>
(8-8/8)