Project

Profile

Help

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

Johan Gheys, 2021-03-12 10:10

 
<?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:int="http://www.infrabel.be/INT"
xmlns:cern="http://www.infrabel.be/ups/timetable/2014/09"
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="node-xml" as="document-node()"/>
<xsl:param name="routeEdge-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="concat($run/@last-publish-folder, 'tms/train/')"/>
<!-- *********************************************************************************************************** -->
<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, 3655, 3668, 3690, 3691)">-->
<xsl:variable name="trainXML" select="shared:open-file($timetable-folder, @href)"/>
<xsl:variable name="train-1" select="local:get-microTrainVariant($trainXML, $run/@selectionLayer, $run/@creationDate, $run/@purgeDate)"/>
<xsl:variable name="train-2" select="local:add-traction-and-routeEdgeSections($train-1)"/>
<xsl:variable name="train-3" select="local:group-by-midnight($train-2)"/>
<xsl:variable name="train-4" select="local:filter-timetablePoints($train-3)"/>
<xsl:variable name="train" select="local:sort-microTrainVariant($train-4)"/>
<xsl:result-document href="{shared:path-to-uri($output-folder, @href)}" method="xml">
<xsl:sequence select="$train"/>
</xsl:result-document>
<!-- </xsl:if>-->
</xsl:template>
<!-- *********************************************************************************************************** -->
<xsl:template mode="add-node-and-midnight" match="*">
<xsl:element name="{local-name()}">
<xsl:sequence select="@*"/>
<xsl:apply-templates mode="add-node-and-midnight"/>
</xsl:element>
</xsl:template>
<!-- *********************************************************************************************************** -->
<xsl:template mode="add-node-and-midnight" match="cern:point">
<xsl:param name="departureDate" as="xs:string" tunnel="yes"/>
<xsl:variable name="node" select="local:get-node-for-id(@nodeId, $departureDate)"/>
<xsl:element name="{local-name()}">
<xsl:sequence select="@nodeSequenceNo, @nodeId"/>
<xsl:for-each select="$node">
<xsl:attribute name="nodeName" select="@name"/>
<xsl:attribute name="nodeClass" select="local-name()"/>
<xsl:attribute name="serZoneSymbolicName" select="@serZoneSymbolicName"/>
<xsl:sequence select="@serZoneSymbolicName, @ptrefId"/>
</xsl:for-each>
<xsl:sequence select="@* except (@nodeSequenceNo, @nodeId)"/>
<xsl:apply-templates mode="add-node-and-midnight"/>
</xsl:element>
</xsl:template>
<!-- *********************************************************************************************************** -->
<xsl:template mode="add-node-and-midnight" match="cern:in">
<xsl:element name="{local-name()}">
<xsl:choose>
<xsl:when test="exists(@time) and @time ne '00:00:00'">
<xsl:attribute name="midnight" select="(@midnight, 0)[1]"/>
<xsl:attribute name="time" select="@time"/>
</xsl:when>
<xsl:when test="exists(@time) and @time eq '00:00:00'">
<xsl:attribute name="midnight" select="(@midnight, 0)[1] - 1"/>
<xsl:attribute name="time" select="'24:00:00'"/>
</xsl:when>
</xsl:choose>
<xsl:sequence select="@* except (@midnight, @time)"/>
<xsl:apply-templates mode="add-node-and-midnight"/>
</xsl:element>
</xsl:template>
<!-- *********************************************************************************************************** -->
<xsl:template mode="add-node-and-midnight" match="cern:out">
<xsl:element name="{local-name()}">
<xsl:if test="exists(@time)">
<xsl:attribute name="midnight" select="(@midnight, 0)[1]"/>
<xsl:attribute name="time" select="@time"/>
</xsl:if>
<xsl:sequence select="@* except (@midnight, @time)"/>
<xsl:apply-templates mode="add-node-and-midnight"/>
</xsl:element>
</xsl:template>
<!-- *********************************************************************************************************** -->
<xsl:template mode="add-node-and-midnight" match="cern:infos"/>
<!-- *********************************************************************************************************** -->
<xsl:template mode="add-routeEdges add-traction-and-routeEdgeSections filter-timetablePoints group-by-midnight" match="*">
<xsl:copy>
<xsl:sequence select="@*"/>
<xsl:apply-templates mode="#current"/>
</xsl:copy>
</xsl:template>
<!-- *********************************************************************************************************** -->
<xsl:template mode="add-routeEdges" match="point">
<xsl:variable name="routeEdgeNodes" select="local:get-routeEdgeNodes-for-point(.)"/>
<xsl:copy>
<xsl:sequence select="@*"/>
<xsl:apply-templates mode="add-routeEdges">
<xsl:with-param name="routeEdgeNodes" select="$routeEdgeNodes" tunnel="yes"/>
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
<!-- *********************************************************************************************************** -->
<xsl:template mode="add-routeEdges" match="in">
<xsl:param name="routeEdgeNodes" as="element()*" tunnel="yes"/>
<xsl:variable name="routeEdgeNode" select="$routeEdgeNodes[int:in/@port = current()/@port]"/>
<xsl:copy>
<xsl:sequence select="@*"/>
<xsl:apply-templates mode="add-routeEdges"/>
<xsl:for-each select="$routeEdgeNode">
<xsl:variable name="distance" select="@distance"/>
<xsl:for-each select="ancestor::int:routeEdge">
<xsl:element name="routeEdgeRef">
<xsl:attribute name="routeEdgeId" select="@id"/>
<xsl:attribute name="distance" select="$distance"/>
<xsl:attribute name="length" select="int:nodes/*[last()]/@distance"/>
<xsl:sequence select="@course"/>
</xsl:element>
</xsl:for-each>
</xsl:for-each>
</xsl:copy>
</xsl:template>
<!-- *********************************************************************************************************** -->
<xsl:template mode="add-routeEdges" match="out">
<xsl:param name="routeEdgeNodes" as="element()*" tunnel="yes"/>
<xsl:variable name="routeEdgeNode" select="$routeEdgeNodes[int:out/@port = current()/@port]"/>
<xsl:copy>
<xsl:sequence select="@*"/>
<xsl:apply-templates mode="add-routeEdges"/>
<xsl:for-each select="$routeEdgeNode">
<xsl:variable name="distance" select="@distance"/>
<xsl:for-each select="ancestor::int:routeEdge">
<xsl:element name="routeEdgeRef">
<xsl:attribute name="routeEdgeId" select="@id"/>
<xsl:attribute name="distance" select="$distance"/>
<xsl:attribute name="length" select="int:nodes/*[last()]/@distance"/>
<xsl:sequence select="@course"/>
</xsl:element>
</xsl:for-each>
</xsl:for-each>
</xsl:copy>
</xsl:template>
<!-- *********************************************************************************************************** -->
<xsl:template mode="add-traction-and-routeEdgeSections" match="microTrainVariant">
<xsl:variable name="timetablePoints-1" as="element()">
<xsl:apply-templates mode="add-routeEdges" select="timetablePoints"/>
</xsl:variable>
<xsl:variable name="tractionSections" select="local:create-tractionSections-from-timetable($timetablePoints-1)"/>
<xsl:variable name="routeEdgeSections" select="local:create-routeEdgeSections-from-timetable($timetablePoints-1)"/>
<xsl:copy>
<xsl:sequence select="@*, *"/>
<xsl:element name="tractionSections">
<xsl:sequence select="$tractionSections"/>
</xsl:element>
<xsl:element name="routeEdgeSections">
<xsl:sequence select="$routeEdgeSections"/>
</xsl:element>
</xsl:copy>
</xsl:template>
<!-- *********************************************************************************************************** -->
<xsl:template mode="filter-timetablePoints" match="midnightSection">
<xsl:variable name="filtered-points" as="element()*">
<xsl:apply-templates mode="filter-timetablePoints" select="routeEdgeSections/routeEdgeSection"/>
</xsl:variable>
<xsl:copy>
<xsl:sequence select="@*, date"/>
<xsl:if test="exists($filtered-points)">
<xsl:element name="timetablePoints">
<xsl:sequence select="$filtered-points"/>
</xsl:element>
</xsl:if>
<xsl:sequence select="* except (date, timetablePoints)"/>
</xsl:copy>
</xsl:template>
<!-- *********************************************************************************************************** -->
<xsl:template mode="filter-timetablePoints" match="routeEdgeSection" as="element(point)*">
<xsl:if test="empty(@routeEdgeId)">
<xsl:sequence select="ancestor::midnightSection/timetablePoints/point[(@nodeSequenceNo - current()/@outNodeSequenceNo ge 0) and (current()/@inNodeSequenceNo - @nodeSequenceNo ge 0)]"/>
</xsl:if>
</xsl:template>
<!-- *********************************************************************************************************** -->
<xsl:template mode="group-by-midnight" match="timetablePoints">
<xsl:variable name="timetablePoints" select="."/>
<xsl:variable name="microTrainVariant" select="ancestor::microTrainVariant"/>
<xsl:variable name="midnightSections" select="local:create-midnightSections-from-timetable(., $microTrainVariant/@departDay, $microTrainVariant/@destDay)"/>
<xsl:variable name="departureDates" select="$microTrainVariant/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[(@nodeSequenceNo - $currentMidnightSection/@outNodeSequenceNo ge 0) and ($currentMidnightSection/@inNodeSequenceNo - @nodeSequenceNo ge 0)]"/>
<xsl:variable name="tractionSections"
select="$microTrainVariant/tractionSections/tractionSection[(@inNodeSequenceNo - $currentMidnightSection/@outNodeSequenceNo ge 0) and ($currentMidnightSection/@inNodeSequenceNo - @outNodeSequenceNo ge 0)]"/>
<xsl:variable name="routeEdgeSections"
select="$microTrainVariant/routeEdgeSections/routeEdgeSection[(@inNodeSequenceNo - $currentMidnightSection/@outNodeSequenceNo ge 0) and ($currentMidnightSection/@inNodeSequenceNo - @outNodeSequenceNo ge 0)][(@inMidnight - $currentMidnightSection/@midnight ge 0) and ($currentMidnightSection/@midnight - @outMidnight 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:element name="routeEdgeSections">
<xsl:sequence select="$routeEdgeSections"/>
</xsl:element>
</xsl:copy>
</xsl:for-each>
</xsl:template>
<!-- *********************************************************************************************************** -->
<xsl:template mode="group-by-midnight" match="tractionSections|routeEdgeSections"/>
<!-- *********************************************************************************************************** -->
<xsl:function name="local:add-traction-and-routeEdgeSections" as="element(train)">
<xsl:param name="train" as="element()"/>
<xsl:apply-templates select="$train" mode="add-traction-and-routeEdgeSections"/>
</xsl:function>
<!-- *********************************************************************************************************** -->
<xsl:function name="local:are-routeEdges-needed-for-point" as="xs:boolean">
<xsl:param name="point" as="element()"/>
<xsl:for-each select="$point">
<xsl:choose>
<xsl:when test="@nodeClass = ('deadEnd', 'endOfModel', 'locationPoint')">
<xsl:sequence select="true()"/>
</xsl:when>
<xsl:when test="@nodeClass = 'stopSignal'">
<xsl:sequence select="exists(@ptrefId)"/>
</xsl:when>
<xsl:otherwise>
<xsl:sequence select="false()"/>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</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[./in/@midnight = $midnight or ./out/@midnight = $midnight]"/>
<xsl:variable name="previousPoint" select="$timetablePoints/point[./in/@midnight - $midnight lt 0 or ./out/@midnight - $midnight lt 0][last()]"/>
<xsl:variable name="nextPoint" select="$timetablePoints/point[./in/@midnight - $midnight gt 0 or ./out/@midnight - $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/@nodeSequenceNo, $toPoint/@nodeSequenceNo, $midnight)"/>
</xsl:if>
</xsl:for-each>
</xsl:function>
<!-- *********************************************************************************************************** -->
<xsl:function name="local:create-routeEdgeSections-from-timetable" as="element(routeEdgeSection)*">
<xsl:param name="timetablePoints" as="element()"/>
<xsl:for-each select="$timetablePoints">
<xsl:variable name="timetablePoints" select="."/>
<xsl:variable name="relevantPoints"
select="point[exists(@nodeId)][position() = (1, last()) or exists(./in/routeEdgeRef) or exists(./out/routeEdgeRef)]"/>
<xsl:variable name="routeEdgeChangePoints"
select="$relevantPoints[position() = (1, last()) or string-join(./in/routeEdgeRef/@routeEdgeId, ' ') != string-join(./out/routeEdgeRef/@routeEdgeId, ' ')]"/>
<xsl:for-each select="$routeEdgeChangePoints[position() ne last()]">
<xsl:variable name="index" select="position()"/>
<xsl:variable name="outPoint" select="."/>
<xsl:variable name="inPoint" select="$routeEdgeChangePoints[$index + 1]"/>
<xsl:variable name="intersection"
select="local:intersect-routeEdge($timetablePoints/point[(@nodeSequenceNo - $outPoint/@nodeSequenceNo ge 0) and ($inPoint/@nodeSequenceNo - @nodeSequenceNo ge 0)])"/>
<xsl:sequence select="local:new-routeEdgeSection($outPoint, $inPoint, $intersection/@routeEdgeId)"/>
</xsl:for-each>
</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 = 'true']"/>
<xsl:variable name="tractionSections1" as="item()*">
<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:filter-timetablePoints" as="element(train)">
<xsl:param name="train" as="element()"/>
<xsl:apply-templates select="$train" mode="filter-timetablePoints"/>
</xsl:function>
<!-- *********************************************************************************************************** -->
<xsl:function name="local:get-course" as="xs:string?">
<xsl:param name="points" as="element()*"/>
<xsl:variable name="course"
select="string-join($points[@nodeClass = ('switch', 'crossing')]/string-join((./in/@port, @nodeName, ./out/@port),'-'), '|')"/>
<xsl:if test="string-length($course) gt 0">
<xsl:sequence select="$course"/>
</xsl:if>
</xsl:function>
<!-- *********************************************************************************************************** -->
<xsl:function name="local:get-microTrainVariant" 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:for-each select="cern:train">
<!--<xsl:if test="@trainNo = (123, 521, 544, 33343, 47524)">-->
<xsl:element name="train">
<xsl:attribute name="functionalKey" select="local:get-train-functionalKey(@natureCode, @trainNo, @discriminator)"/>
<xsl:sequence select="@natureCode, @trainNo, @discriminator"/>
<xsl:attribute name="href" select="$href"/>
<xsl:attribute name="creationDate" select="$creationDate"/>
<xsl:for-each select=".//cern:microTrainVariant">
<xsl:variable name="departureDate" select="shared:get-vector-dates-for-layerVPK(cern:layerVPK, $selectionLayer)"/>
<xsl:variable name="dateFrom" select="$departureDate[1]"/>
<xsl:variable name="dateTo" select="$departureDate[last()]"/>
<xsl:if test="$dateTo ge $purgeDate">
<xsl:variable name="firstPoint" select="cern:timetablePoints/cern:point[1]"/>
<xsl:variable name="departDay" select="($firstPoint/cern:in/@midnight, $firstPoint/cern:out/@midnight, 0)[1]"/>
<xsl:variable name="lastPoint" select="cern:timetablePoints/cern:point[last()]"/>
<xsl:variable name="destDay" select="($lastPoint/cern:out/@midnight, $lastPoint/cern:in/@midnight, 0)[1]"/>
<xsl:variable name="macroTrainVariant" select="ancestor::cern:macroTrainVariant"/>
<xsl:variable name="train" select="ancestor::cern:train"/>
<xsl:element name="microTrainVariant">
<xsl:sequence select="@id, @layer"/>
<xsl:if test="@layer eq 'season'">
<xsl:sequence select="$macroTrainVariant/@car, $macroTrainVariant/@per"/>
</xsl:if>
<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="type" select="$train/@type"/>
<xsl:attribute name="isEmpty" select="($macroTrainVariant/@isEmpty, 'false')[1]"/>
<xsl:attribute name="trainOperator" select="$macroTrainVariant/@trainOperator"/>
<xsl:if test="exists($macroTrainVariant/@bulletinName)">
<xsl:attribute name="bulletinName" select="$macroTrainVariant/@bulletinName"/>
<xsl:attribute name="bulletinVersionId" select="$macroTrainVariant/@bulletinVersionId"/>
</xsl:if>
<xsl:element name="departureDate">
<xsl:sequence select="shared:group-dates-by-week($departureDate)"/>
</xsl:element>
<xsl:apply-templates select="cern:timetablePoints" mode="add-node-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:for-each>
</xsl:function>
<!-- *********************************************************************************************************** -->
<xsl:function name="local:get-node-for-id" as="element()?">
<xsl:param name="id" as="xs:string?"/>
<xsl:param name="date" as="xs:string"/>
<xsl:if test="exists($id)">
<xsl:sequence select="key('by-id', $id, $node-xml)[$date >= @validFromDate and @validToDate >= $date]"/>
</xsl:if>
</xsl:function>
<!-- *********************************************************************************************************** -->
<xsl:function name="local:get-routeEdgeNodes-for-point" as="element()*">
<xsl:param name="point" as="element()"/>
<xsl:for-each select="$point">
<xsl:if test="local:are-routeEdges-needed-for-point(.)">
<xsl:variable name="date" select="ancestor::microTrainVariant/@dateFrom"/>
<xsl:sequence select="local:get-routeEdgeNodes-for-nodeId(@nodeId, $date)"/>
</xsl:if>
</xsl:for-each>
</xsl:function>
<!-- *********************************************************************************************************** -->
<xsl:function name="local:get-routeEdgeNodes-for-nodeId" as="element()*">
<xsl:param name="nodeId" as="xs:string"/>
<xsl:param name="date" as="xs:string"/>
<xsl:sequence select="key('by-id', $nodeId, $routeEdge-xml)[ancestor::int:routeEdge[$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:intersect-routeEdge" as="element()*">
<xsl:param name="points" as="element()*"/>
<xsl:variable name="newRouteEdgeRef" as="element()*">
<xsl:iterate select="$points">
<xsl:param name="routeEdgeRef" as="element()*"/>
<xsl:on-completion>
<xsl:sequence select="$routeEdgeRef"/>
</xsl:on-completion>
<xsl:variable name="newRouteEdgeRef"
select="if (position() eq 1) then out/routeEdgeRef else if (empty(current()/in/routeEdgeRef)) then $routeEdgeRef else $routeEdgeRef[@routeEdgeId = current()/in/routeEdgeRef/@routeEdgeId]"/>
<xsl:next-iteration>
<xsl:with-param name="routeEdgeRef" select="$newRouteEdgeRef"/>
</xsl:next-iteration>
</xsl:iterate>
</xsl:variable>
<xsl:variable name="course" select="local:get-course($points)"/>
<xsl:sequence select="if (count($newRouteEdgeRef) le 1) then $newRouteEdgeRef else $newRouteEdgeRef[@course eq $course]"/>
</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]/@outNodeSequenceNo, $tractionSections[2]/@inNodeSequenceNo, $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]/@outNodeSequenceNo, $tractionSections[last()]/@inNodeSequenceNo, $tractionSections[last() - 1]/@tractionCode)"/>
</xsl:when>
<xsl:otherwise>
<xsl:sequence select="$tractionSections"/>
</xsl:otherwise>
</xsl:choose>
</xsl:function>
<!-- *********************************************************************************************************** -->
<xsl:function name="local:new-midnightSection" as="element(midnightSection)">
<xsl:param name="outNodeSequenceNo" as="xs:integer"/>
<xsl:param name="inNodeSequenceNo" as="xs:integer"/>
<xsl:param name="midnight" as="xs:integer"/>
<xsl:element name="midnightSection">
<xsl:attribute name="outNodeSequenceNo" select="$outNodeSequenceNo"/>
<xsl:attribute name="inNodeSequenceNo" select="$inNodeSequenceNo"/>
<xsl:attribute name="midnight" select="$midnight"/>
</xsl:element>
</xsl:function>
<!-- *********************************************************************************************************** -->
<xsl:function name="local:new-routeEdgeSection" as="element(routeEdgeSection)">
<xsl:param name="outPoint" as="element(point)"/>
<xsl:param name="inPoint" as="element(point)"/>
<xsl:param name="routeEdgeId" as="xs:string?"/>
<xsl:variable name="outRouteEdgeRef" select="$outPoint/out/routeEdgeRef[@routeEdgeId eq $routeEdgeId]"/>
<xsl:variable name="inRouteEdgeRef" select="$inPoint/in/routeEdgeRef[@routeEdgeId eq $routeEdgeId]"/>
<xsl:variable name="distancesNeeded" select="$outRouteEdgeRef/@distance != 0 or $inRouteEdgeRef/@distance != $inRouteEdgeRef/@length"/>
<xsl:variable name="fromDistance" select="if ($distancesNeeded) then $outRouteEdgeRef/@distance else ()"/>
<xsl:variable name="toDistance" select="if ($distancesNeeded) then $inRouteEdgeRef/@distance else ()"/>
<xsl:sequence
select="local:new-routeEdgeSection($outPoint/@nodeSequenceNo, $outPoint/out/@midnight, $outPoint/out/@time, $inPoint/@nodeSequenceNo, $inPoint/in/@midnight, $inPoint/in/@time, $routeEdgeId, $fromDistance, $toDistance)"/>
</xsl:function>
<!-- *********************************************************************************************************** -->
<xsl:function name="local:new-routeEdgeSection" as="element(routeEdgeSection)">
<xsl:param name="outNodeSequenceNo" as="xs:integer"/>
<xsl:param name="outMidnight" as="xs:integer"/>
<xsl:param name="outTime" as="xs:string"/>
<xsl:param name="inNodeSequenceNo" as="xs:integer"/>
<xsl:param name="inMidnight" as="xs:integer"/>
<xsl:param name="inTime" as="xs:string"/>
<xsl:param name="routeEdgeId" as="xs:string?"/>
<xsl:param name="fromDistance" as="xs:integer?"/>
<xsl:param name="toDistance" as="xs:integer?"/>
<xsl:element name="routeEdgeSection">
<xsl:attribute name="outNodeSequenceNo" select="$outNodeSequenceNo"/>
<xsl:attribute name="outMidnight" select="$outMidnight"/>
<xsl:attribute name="outTime" select="$outTime"/>
<xsl:attribute name="inNodeSequenceNo" select="$inNodeSequenceNo"/>
<xsl:attribute name="inMidnight" select="$inMidnight"/>
<xsl:attribute name="inTime" select="$inTime"/>
<xsl:if test="exists($routeEdgeId)">
<xsl:attribute name="routeEdgeId" select="$routeEdgeId"/>
</xsl:if>
<xsl:if test="exists($fromDistance)">
<xsl:attribute name="fromDistance" select="$fromDistance"/>
</xsl:if>
<xsl:if test="exists($toDistance)">
<xsl:attribute name="toDistance" select="$toDistance"/>
</xsl:if>
</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/@nodeSequenceNo, $inPoint/@nodeSequenceNo, $outPoint/out/@tractionCode)"/>
</xsl:function>
<!-- *********************************************************************************************************** -->
<xsl:function name="local:new-tractionSection" as="element(tractionSection)">
<xsl:param name="outNodeSequenceNo" as="xs:integer"/>
<xsl:param name="inNodeSequenceNo" as="xs:integer"/>
<xsl:param name="tractionCode" as="xs:string?"/>
<xsl:element name="tractionSection">
<xsl:attribute name="outNodeSequenceNo" select="$outNodeSequenceNo"/>
<xsl:attribute name="inNodeSequenceNo" select="$inNodeSequenceNo"/>
<xsl:if test="exists($tractionCode)">
<xsl:attribute name="tractionCode" select="$tractionCode"/>
</xsl:if>
</xsl:element>
</xsl:function>
<!-- *********************************************************************************************************** -->
<xsl:function name="local:sort-microTrainVariant" as="element()">
<xsl:param name="train" as="element()"/>
<xsl:for-each select="$train">
<xsl:copy>
<xsl:sequence select="@*"/>
<xsl:perform-sort select="microTrainVariant">
<xsl:sort select="@layer ne 'season'"/>
<xsl:sort select="@dateFrom"/>
</xsl:perform-sort>
</xsl:copy>
</xsl:for-each>
</xsl:function>
<!-- *********************************************************************************************************** -->
</xsl:stylesheet>
(1-1/8)