Project

Profile

Help

Bug #6026 » complete-node.xslt

Johan Gheys, 2023-05-09 19:42

 
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:a371="http://www.infrabel.be/Artemis/Infrastructure/20080711"
xmlns:local="urn:local-functions"
xmlns:macro="http://www.infrabel.be/int/macro"
xmlns:meso="http://www.infrabel.be/int/meso"
xmlns:micro="http://www.infrabel.be/int/micro"
xmlns:shared="urn:shared-functions"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
version="2.0">
<xsl:import href="/shared/shared-functions.xslt"/>
<xsl:param name="macro-trackEdge-file" as="xs:string"/>
<xsl:param name="nodeByCatenaryCase-file" as="xs:string"/>
<xsl:param name="nodeByGig-file" as="xs:string"/>
<xsl:param name="nodeByLocation-file" as="xs:string"/>
<xsl:param name="creation-date" as="xs:string"/>
<xsl:param name="purge-date" as="xs:string"/>
<xsl:strip-space elements="*"/>
<xsl:variable name="macro-trackEdge-xml" select="shared:open-file($macro-trackEdge-file)"/>
<xsl:variable name="nodeByCatenaryCase-xml" select="shared:open-file($nodeByCatenaryCase-file)"/>
<xsl:variable name="nodeByGig-xml" select="shared:open-file($nodeByGig-file)"/>
<xsl:variable name="nodeByLocation-xml" select="shared:open-file($nodeByLocation-file)"/>
<xsl:variable name="directions" select="'up', 'down'"/>
<xsl:variable name="inverseDirections" select="'down', 'up'"/>
<xsl:variable name="normalDrivingDirections" select="'up', 'down', 'up+down'"/>
<xsl:variable name="inverseNormalDrivingDirections" select="'down', 'up', 'up+down'"/>
<xsl:key name="by-nodeId" match="*" use="@nodeId"/>
<xsl:key name="by-minPtcarId-maxPtcarId" match="*"
use="concat(min((refs/a371:fromPtcarRef/@ptcarId, refs/a371:toPtcarRef/@ptcarId)), $separator, max((refs/a371:fromPtcarRef/@ptcarId, refs/a371:toPtcarRef/@ptcarId)))"/>

<xsl:template match="micro:nodes">
<xsl:copy>
<xsl:attribute name="creationDate" select="$creation-date"/>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>

<xsl:template match="*[exists(@validToDate)]" priority="2">
<xsl:if test="@validToDate ge $purge-date">
<xsl:next-match/>
</xsl:if>
</xsl:template>

<xsl:template match="micro:border" priority="1">
<xsl:variable name="border" select="local:complete-and-split-border(.)"/>
<xsl:sequence select="local:transform-to-export-border($border)"/>
</xsl:template>

<xsl:template match="micro:locationPoint" priority="1">
<xsl:variable name="locationPoint" select="local:complete-and-split-node(.)"/>
<xsl:sequence select="local:transform-to-export-locationPoint($locationPoint)"/>
</xsl:template>

<xsl:template match="*[exists(@validToDate)]" priority="0">
<xsl:variable name="node" select="local:complete-and-split-node(.)"/>
<xsl:sequence select="local:transform-to-export-node($node)"/>
</xsl:template>

<xsl:function name="local:catenaryCaseRef" as="element()*">
<xsl:param name="nodeByCatenaryCase" as="element()*"/>
<xsl:for-each select="$nodeByCatenaryCase">
<xsl:element name="micro:catenaryCaseRef">
<xsl:sequence select="@catenaryCaseId, @catenaryCaseBorderPort, @case"/>
</xsl:element>
</xsl:for-each>
</xsl:function>

<xsl:function name="local:complete-and-split-border" as="map(*)*">
<xsl:param name="border" as="element()"/>
<xsl:for-each select="$border">
<xsl:variable name="nodeByLocations" select="local:nodeByLocation(.)"/>
<xsl:variable name="validities" select="shared:get-validities(., $nodeByLocations, $purge-date)"/>
<xsl:for-each select="$validities">
<xsl:variable name="nodeByGig" select="local:nodeByGig($border, .)"/>
<xsl:variable name="nodeByLocation" select="$nodeByLocations[current()/@validToDate ge @validFromDate and @validToDate ge current()/@validFromDate]"/>
<xsl:variable name="nodeByCatenaryCase" select="local:nodeByCatenaryCase($border, .)"/>
<xsl:variable name="macro-trackEdge" select="local:macro-trackEdge($border, ., $nodeByLocation)"/>
<xsl:sequence select="local:split-border($border, ., $nodeByGig, $nodeByLocation, $nodeByCatenaryCase, $macro-trackEdge)"/>
</xsl:for-each>
</xsl:for-each>
</xsl:function>

<xsl:function name="local:complete-and-split-node" as="map(*)*">
<xsl:param name="node" as="element()"/>
<xsl:for-each select="$node">
<xsl:variable name="nodeByGig" select="local:nodeByGig(.)"/>
<xsl:variable name="nodeByLocation" select="local:nodeByLocation(.)"/>
<xsl:variable name="nodeByCatenaryCase" select="local:nodeByCatenaryCase(.)"/>
<xsl:sequence select="local:split-node(., $nodeByGig, $nodeByLocation, $nodeByCatenaryCase)"/>
</xsl:for-each>
</xsl:function>

<xsl:function name="local:direction" as="xs:string">
<xsl:param name="macro-trackEdge" as="element()"/>
<xsl:param name="ptcarId" as="xs:integer"/>
<xsl:param name="nextPtcarId" as="xs:integer"/>
<xsl:variable name="refDirection" select="'up'"/>
<xsl:choose>
<xsl:when test="($ptcarId = $macro-trackEdge/refs/a371:fromPtcarRef/@ptcarId) and ($nextPtcarId = $macro-trackEdge/refs/a371:toPtcarRef/@ptcarId)">
<xsl:sequence select="$refDirection"/>
</xsl:when>
<xsl:otherwise>
<xsl:variable name="index" select="index-of($directions, $refDirection)"/>
<xsl:sequence select="$inverseDirections[$index]"/>
</xsl:otherwise>
</xsl:choose>
</xsl:function>

<xsl:function name="local:gigRef" as="element()*">
<xsl:param name="nodeByGig" as="element()*"/>
<xsl:for-each select="$nodeByGig">
<xsl:element name="micro:gigRef">
<xsl:sequence select="@gigId, @gigBorderPort, @serZoneSymbolicName, @a371:serZoneId"/>
</xsl:element>
</xsl:for-each>
</xsl:function>

<xsl:function name="local:line-name" as="xs:string">
<xsl:param name="macro-trackEdge" as="element()"/>
<xsl:for-each select="$macro-trackEdge">
<xsl:sequence select="substring-after(tokenize(@name, $separator)[1], 'L')"/>
</xsl:for-each>
</xsl:function>

<xsl:function name="local:lineSectionTrackRef" as="element()*">
<xsl:param name="macro-trackEdge" as="element()*"/>
<xsl:param name="nodeByLocation" as="element()*"/>
<xsl:param name="node" as="element()"/>
<xsl:variable name="locationBorderFunction" as="element()?" select="$node/micro:functions/micro:locationBorder"/>
<!-- Add a371:lineSectionTrackRef for each macro:trackEdge for the same line and track (independent of the concerned lineSection) to avoid future information loss -->
<xsl:variable name="lineId" as="xs:integer?" select="$locationBorderFunction/@a371:lineId"/>
<xsl:variable name="trackId" as="xs:integer?" select="$locationBorderFunction/@a371:trackId"/>
<xsl:for-each select="$macro-trackEdge[refs/a371:lineSectionTrackRef/(@lineId = ($lineId, @lineId)[1] and @trackId = ($trackId, @trackId)[1])]">
<xsl:sort select="refs/a371:lineSectionTrackRef/@lineId" data-type="number"/>
<xsl:sort select="refs/a371:lineSectionTrackRef/@trackId" data-type="number"/>
<xsl:element name="a371:lineSectionTrackRef">
<xsl:attribute name="direction" select="local:direction(., $nodeByLocation[1]/@a371:ptcarId, $nodeByLocation[2]/@a371:ptcarId)"/>
<xsl:attribute name="functionalKey" select="concat(refs/macro:fromPortRef/@portId, $pipe, refs/macro:toPortRef/@portId)"/>
<xsl:attribute name="lineId" select="refs/a371:lineSectionTrackRef/@lineId"/>
<xsl:attribute name="lineName" select="local:line-name(.)"/>
<xsl:attribute name="lineSectionId" select="refs/a371:lineSectionTrackRef/@lineSectionId"/>
<xsl:attribute name="netId" select="refs/a371:netRef/@netId"/>
<xsl:attribute name="normalDrivingDirection" select="local:normalDrivingDirection(., $nodeByLocation[1]/@a371:ptcarId, $nodeByLocation[2]/@a371:ptcarId)"/>
<xsl:attribute name="trackId" select="refs/a371:lineSectionTrackRef/@trackId"/>
<xsl:attribute name="trackName" select="local:track-name(.)"/>
</xsl:element>
</xsl:for-each>
</xsl:function>

<xsl:function name="local:locationPoint-name" as="xs:string">
<xsl:param name="locationPoint" as="element()"/>
<xsl:param name="nodeByLocation" as="element()"/>
<xsl:for-each select="$locationPoint">
<xsl:choose>
<xsl:when test="exists(micro:functions/micro:operation/@nameDutch)">
<xsl:sequence select="concat($nodeByLocation/@locationShortNameDutch, ' - ', micro:functions/micro:operation/@nameDutch)"/>
</xsl:when>
<xsl:when test="exists(micro:functions/micro:local/@nameDutch)">
<xsl:sequence select="concat($nodeByLocation/@locationShortNameDutch, ' - ', micro:functions/micro:local/@nameDutch)"/>
</xsl:when>
<xsl:otherwise>
<xsl:sequence select="$nodeByLocation/@locationShortNameDutch"/>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</xsl:function>

<xsl:function name="local:locationSide" as="xs:integer*">
<xsl:param name="lineSectionTrackRef" as="element()*"/>
<xsl:param name="ptcarId" as="xs:integer"/>
<xsl:variable name="locationSide" as="xs:integer*">
<xsl:for-each select="$lineSectionTrackRef">
<xsl:variable name="functionalKey-parts" select="tokenize(@functionalKey, '\|')"/>
<xsl:variable name="from-position" select="1, 5"/>
<xsl:for-each select="$from-position">
<xsl:variable name="index" select="."/>
<xsl:if test="xs:integer($functionalKey-parts[$index]) eq $ptcarId">
<xsl:sequence select="xs:integer($functionalKey-parts[$index + 1])"/>
</xsl:if>
</xsl:for-each>
</xsl:for-each>
</xsl:variable>
<xsl:sequence select="sort(distinct-values($locationSide))"/>
</xsl:function>

<xsl:function name="local:macro-trackEdge" as="element()*">
<xsl:param name="border" as="element()"/>
<xsl:param name="validity" as="element()"/>
<xsl:param name="nodeByLocation" as="element()*"/>
<xsl:variable name="minPtcarId" select="min($nodeByLocation/@a371:ptcarId)"/>
<xsl:variable name="maxPtcarId" select="max($nodeByLocation/@a371:ptcarId)"/>
<xsl:if test="exists($border/micro:functions/micro:locationBorder) and $minPtcarId ne $maxPtcarId">
<xsl:sequence select="local:macro-trackEdge($minPtcarId, $maxPtcarId, $validity/@validFromDate, $validity/@validToDate)"/>
</xsl:if>
</xsl:function>

<xsl:function name="local:macro-trackEdge" as="element()*">
<xsl:param name="minPtcarId" as="xs:double"/>
<xsl:param name="maxPtcarId" as="xs:double"/>
<xsl:param name="validFromDate" as="xs:string"/>
<xsl:param name="validToDate" as="xs:string"/>
<xsl:sequence
select="$macro-trackEdge-xml/key('by-minPtcarId-maxPtcarId', concat($minPtcarId, $separator, $maxPtcarId))[$validToDate ge @validFromDate and @validToDate ge $validFromDate and @validToDate ge $purge-date]"/>
</xsl:function>

<xsl:function name="local:meso-locationRef" as="element()*">
<xsl:param name="nodeByLocation" as="element()*"/>
<xsl:for-each-group select="$nodeByLocation" group-by="@meso:locationId">
<xsl:element name="meso:locationRef">
<xsl:attribute name="locationId" select="current-grouping-key()"/>
<xsl:attribute name="a371:ptcarId" select="@a371:ptcarId"/>
</xsl:element>
</xsl:for-each-group>
</xsl:function>

<xsl:function name="local:meso-locationRef" as="element()*">
<xsl:param name="nodeByLocation" as="element()*"/>
<xsl:param name="lineSectionTrackRef" as="element()*"/>
<xsl:for-each-group select="$nodeByLocation" group-by="@meso:locationId">
<xsl:variable name="locationSide" as="xs:integer*" select="local:locationSide($lineSectionTrackRef, @a371:ptcarId)"/>
<xsl:element name="meso:locationRef">
<xsl:attribute name="locationId" select="current-grouping-key()"/>
<xsl:if test="count(current-group()) eq 1 and exists(@locationBorderPort)">
<xsl:attribute name="locationBorderPort" select="@locationBorderPort"/>
</xsl:if>
<xsl:if test="count($locationSide) eq 1">
<xsl:attribute name="locationSide" select="$locationSide"/>
</xsl:if>
<xsl:attribute name="a371:ptcarId" select="@a371:ptcarId"/>
</xsl:element>
</xsl:for-each-group>
</xsl:function>

<xsl:function name="local:micro-locationRef" as="element()*">
<xsl:param name="nodeByLocation" as="element()*"/>
<xsl:for-each select="$nodeByLocation">
<xsl:element name="micro:locationRef">
<xsl:sequence select="@locationId, @oldLocationId, @locationBorderPort, @a371:ptcarId"/>
</xsl:element>
</xsl:for-each>
</xsl:function>

<xsl:function name="local:nodeByCatenaryCase" as="element()*">
<xsl:param name="node" as="element()"/>
<xsl:for-each select="$node">
<xsl:sequence select="local:nodeByCatenaryCase(@id, @validFromDate, @validToDate)"/>
</xsl:for-each>
</xsl:function>

<xsl:function name="local:nodeByCatenaryCase" as="element()*">
<xsl:param name="node" as="element()"/>
<xsl:param name="validity" as="element()"/>
<xsl:for-each select="$node">
<xsl:sequence select="local:nodeByCatenaryCase(@id, $validity/@validFromDate, $validity/@validToDate)"/>
</xsl:for-each>
</xsl:function>

<xsl:function name="local:nodeByCatenaryCase" as="element()*">
<xsl:param name="nodeId" as="xs:string"/>
<xsl:param name="validFromDate" as="xs:string"/>
<xsl:param name="validToDate" as="xs:string"/>
<xsl:sequence select="$nodeByCatenaryCase-xml/key('by-nodeId', $nodeId)[$validToDate ge @validFromDate and @validToDate ge $validFromDate and @validToDate ge $purge-date]"/>
</xsl:function>

<xsl:function name="local:nodeByGig" as="element()*">
<xsl:param name="node" as="element()"/>
<xsl:for-each select="$node">
<xsl:sequence select="local:nodeByGig(@id, @validFromDate, @validToDate)"/>
</xsl:for-each>
</xsl:function>

<xsl:function name="local:nodeByGig" as="element()*">
<xsl:param name="node" as="element()"/>
<xsl:param name="validity" as="element()"/>
<xsl:for-each select="$node">
<xsl:sequence select="local:nodeByGig(@id, $validity/@validFromDate, $validity/@validToDate)"/>
</xsl:for-each>
</xsl:function>

<xsl:function name="local:nodeByGig" as="element()*">
<xsl:param name="nodeId" as="xs:string"/>
<xsl:param name="validFromDate" as="xs:string"/>
<xsl:param name="validToDate" as="xs:string"/>
<xsl:sequence select="$nodeByGig-xml/key('by-nodeId', $nodeId)[$validToDate ge @validFromDate and @validToDate ge $validFromDate and @validToDate ge $purge-date]"/>
</xsl:function>

<xsl:function name="local:nodeByLocation" as="element()*">
<xsl:param name="node" as="element()"/>
<xsl:for-each select="$node">
<xsl:sequence select="local:nodeByLocation(@id, @validFromDate, @validToDate)"/>
</xsl:for-each>
</xsl:function>

<xsl:function name="local:nodeByLocation" as="element()*">
<xsl:param name="node" as="element()"/>
<xsl:param name="validity" as="element()"/>
<xsl:for-each select="$node">
<xsl:sequence select="local:nodeByLocation(@id, $validity/@validFromDate, $validity/@validToDate)"/>
</xsl:for-each>
</xsl:function>

<xsl:function name="local:nodeByLocation" as="element()*">
<xsl:param name="nodeId" as="xs:string"/>
<xsl:param name="validFromDate" as="xs:string"/>
<xsl:param name="validToDate" as="xs:string"/>
<xsl:sequence select="$nodeByLocation-xml/key('by-nodeId', $nodeId)[$validToDate ge @validFromDate and @validToDate ge $validFromDate and @validToDate ge $purge-date]"/>
</xsl:function>

<xsl:function name="local:normalDrivingDirection" as="xs:string">
<xsl:param name="macro-trackEdge" as="element()"/>
<xsl:param name="ptcarId" as="xs:integer"/>
<xsl:param name="nextPtcarId" as="xs:integer"/>
<xsl:variable name="refNormalDrivingDirection" select="$macro-trackEdge/@normalDrivingDirection"/>
<xsl:choose>
<xsl:when test="($ptcarId = $macro-trackEdge/refs/a371:fromPtcarRef/@ptcarId) and ($nextPtcarId = $macro-trackEdge/refs/a371:toPtcarRef/@ptcarId)">
<xsl:sequence select="$refNormalDrivingDirection"/>
</xsl:when>
<xsl:otherwise>
<xsl:variable name="index" select="index-of($normalDrivingDirections, $refNormalDrivingDirection)"/>
<xsl:sequence select="$inverseNormalDrivingDirections[$index]"/>
</xsl:otherwise>
</xsl:choose>
</xsl:function>

<xsl:function name="local:patch-gigBorderPort" as="element()*">
<xsl:param name="nodeByLocation" as="element()*"/>
<xsl:param name="gigRef" as="element()*"/>
<xsl:choose>
<xsl:when test="count($gigRef) eq 2 and count($gigRef[exists(@gigBorderPort)]) eq 1">
<xsl:perform-sort>
<xsl:sort select="@gigBorderPort" data-type="number"/>
<xsl:sequence select="$gigRef[exists(@gigBorderPort)]"/>
<xsl:for-each select="$gigRef[empty(@gigBorderPort)]">
<xsl:copy>
<xsl:attribute name="gigBorderPort" select="3 - $gigRef[exists(@gigBorderPort)]/@gigBorderPort"/>
<xsl:sequence select="@*"/>
</xsl:copy>
</xsl:for-each>
</xsl:perform-sort>
</xsl:when>
<xsl:when
test="count($gigRef) eq 2 and empty($gigRef[exists(@gigBorderPort)]) and count(distinct-values($gigRef/@a371:serZoneId)) eq 2 and count(distinct-values($nodeByLocation/@a371:serZoneId)) eq 2">
<!-- Use ! to be sure of order -->
<xsl:variable name="serZoneIds" select="$nodeByLocation!@a371:serZoneId"/>
<xsl:perform-sort>
<xsl:sort select="@gigBorderPort" data-type="number"/>
<xsl:for-each select="$gigRef">
<xsl:copy>
<xsl:attribute name="gigBorderPort" select="index-of($serZoneIds, @a371:serZoneId)"/>
<xsl:sequence select="@*"/>
</xsl:copy>
</xsl:for-each>
</xsl:perform-sort>
</xsl:when>
<xsl:otherwise>
<xsl:sequence select="$gigRef"/>
</xsl:otherwise>
</xsl:choose>
</xsl:function>

<xsl:function name="local:split-border" as="map(*)*">
<xsl:param name="node" as="element()"/>
<xsl:param name="validity" as="element()"/>
<xsl:param name="nodeByGigs" as="element()*"/>
<xsl:param name="nodeByLocations" as="element()*"/>
<xsl:param name="nodeByCatenaryCases" as="element()*"/>
<xsl:param name="macro-trackEdges" as="element()*"/>
<xsl:variable name="validities" select="shared:get-validities($validity, ($nodeByGigs, $nodeByLocations, $nodeByCatenaryCases, $macro-trackEdges), $purge-date)"/>
<xsl:for-each select="$validities">
<xsl:variable name="nodeByGig" select="$nodeByGigs[current()/@validToDate ge @validFromDate and @validToDate ge current()/@validFromDate]"/>
<xsl:variable name="nodeByLocation" select="$nodeByLocations[current()/@validToDate ge @validFromDate and @validToDate ge current()/@validFromDate]"/>
<xsl:variable name="nodeByCatenaryCase" select="$nodeByCatenaryCases[current()/@validToDate ge @validFromDate and @validToDate ge current()/@validFromDate]"/>
<xsl:variable name="macro-trackEdge" select="$macro-trackEdges[current()/@validToDate ge @validFromDate and @validToDate ge current()/@validFromDate]"/>
<xsl:map>
<xsl:map-entry key="'node'" select="$node"/>
<xsl:map-entry key="'validFromDate'" select="@validFromDate"/>
<xsl:map-entry key="'validToDate'" select="@validToDate"/>
<xsl:map-entry key="'nodeByGig'">
<xsl:perform-sort select="$nodeByGig">
<xsl:sort select="@gigBorderPort" data-type="number"/>
</xsl:perform-sort>
</xsl:map-entry>
<xsl:map-entry key="'nodeByLocation'">
<xsl:perform-sort select="$nodeByLocation">
<xsl:sort select="@locationBorderPort" data-type="number"/>
</xsl:perform-sort>
</xsl:map-entry>
<xsl:map-entry key="'nodeByCatenaryCase'">
<xsl:perform-sort select="$nodeByCatenaryCase">
<xsl:sort select="@case" data-type="number"/>
<xsl:sort select="@catenaryCaseBorderPort" data-type="number"/>
</xsl:perform-sort>
</xsl:map-entry>
<xsl:map-entry key="'macro-trackEdge'" select="$macro-trackEdge"/>
</xsl:map>
</xsl:for-each>
</xsl:function>

<xsl:function name="local:split-node" as="map(*)*">
<xsl:param name="node" as="element()"/>
<xsl:param name="nodeByGigs" as="element()*"/>
<xsl:param name="nodeByLocations" as="element()*"/>
<xsl:param name="nodeByCatenaryCases" as="element()*"/>
<xsl:variable name="validities" select="shared:get-validities($node, ($nodeByGigs, $nodeByLocations, $nodeByCatenaryCases), $purge-date)"/>
<xsl:for-each select="$validities">
<xsl:variable name="nodeByGig" select="$nodeByGigs[current()/@validToDate ge @validFromDate and @validToDate ge current()/@validFromDate]"/>
<xsl:variable name="nodeByLocation" select="$nodeByLocations[current()/@validToDate ge @validFromDate and @validToDate ge current()/@validFromDate]"/>
<xsl:variable name="nodeByCatenaryCase" select="$nodeByCatenaryCases[current()/@validToDate ge @validFromDate and @validToDate ge current()/@validFromDate]"/>
<xsl:map>
<xsl:map-entry key="'node'" select="$node"/>
<xsl:map-entry key="'validFromDate'" select="@validFromDate"/>
<xsl:map-entry key="'validToDate'" select="@validToDate"/>
<xsl:map-entry key="'nodeByGig'" select="$nodeByGig"/>
<xsl:map-entry key="'nodeByLocation'" select="$nodeByLocation"/>
<xsl:map-entry key="'nodeByCatenaryCase'" select="$nodeByCatenaryCase"/>
</xsl:map>
</xsl:for-each>
</xsl:function>

<xsl:function name="local:track-name" as="xs:string">
<xsl:param name="macro-trackEdge" as="element()"/>
<xsl:for-each select="$macro-trackEdge">
<xsl:sequence select="tokenize(@name, $separator)[2]"/>
</xsl:for-each>
</xsl:function>

<xsl:function name="local:transform-to-export-border" as="element()*">
<xsl:param name="params" as="map(*)*"/>
<xsl:for-each select="$params">
<xsl:variable name="node" as="element()" select="?node"/>
<xsl:variable name="validFromDate" as="xs:string" select="?validFromDate"/>
<xsl:variable name="validToDate" as="xs:string" select="?validToDate"/>
<xsl:variable name="nodeByGig" as="element()*" select="?nodeByGig"/>
<xsl:variable name="nodeByLocation" as="element()*" select="?nodeByLocation"/>
<xsl:variable name="nodeByCatenaryCase" as="element()*" select="?nodeByCatenaryCase"/>
<xsl:variable name="macro-trackEdge" as="element()*" select="?macro-trackEdge"/>
<xsl:variable name="gigRef" select="local:patch-gigBorderPort($nodeByLocation, local:gigRef($nodeByGig))"/>
<xsl:variable name="lineSectionTrackRef" select="local:lineSectionTrackRef($macro-trackEdge, $nodeByLocation, $node)"/>
<xsl:variable name="micro-locationRef" select="local:micro-locationRef($nodeByLocation)"/>
<xsl:variable name="meso-locationRef" select="local:meso-locationRef($nodeByLocation, $lineSectionTrackRef)"/>
<xsl:variable name="catenaryCaseRef" select="local:catenaryCaseRef($nodeByCatenaryCase)"/>
<xsl:for-each select="$node">
<xsl:copy>
<xsl:sequence select="@* except (@validFromDate, @validToDate)"/>
<xsl:attribute name="validFromDate" select="$validFromDate"/>
<xsl:attribute name="validToDate" select="$validToDate"/>
<xsl:sequence select="*"/>
<xsl:element name="refs">
<xsl:perform-sort select="$gigRef, $micro-locationRef, $meso-locationRef, $catenaryCaseRef, $lineSectionTrackRef">
<xsl:sort select="name()"/>
</xsl:perform-sort>
</xsl:element>
</xsl:copy>
</xsl:for-each>
</xsl:for-each>
</xsl:function>

<xsl:function name="local:transform-to-export-locationPoint" as="element()*">
<xsl:param name="params" as="map(*)*"/>
<xsl:for-each select="$params">
<xsl:variable name="node" as="element()" select="?node"/>
<xsl:variable name="validFromDate" as="xs:string" select="?validFromDate"/>
<xsl:variable name="validToDate" as="xs:string" select="?validToDate"/>
<xsl:variable name="nodeByGig" as="element()" select="?nodeByGig"/>
<!-- nodeByLocation can be absent because micro-locations take into account future changes and nodeByLocation not -->
<xsl:variable name="nodeByLocation" as="element()?" select="?nodeByLocation"/>
<xsl:variable name="nodeByCatenaryCase" as="element()?" select="?nodeByCatenaryCase"/>
<xsl:variable name="gigRef" select="local:gigRef($nodeByGig)"/>
<xsl:variable name="micro-locationRef" select="local:micro-locationRef($nodeByLocation)"/>
<xsl:variable name="meso-locationRef" select="local:meso-locationRef($nodeByLocation)"/>
<xsl:variable name="catenaryCaseRef" select="local:catenaryCaseRef($nodeByCatenaryCase)"/>
<xsl:variable name="name" select="local:locationPoint-name($node, $nodeByLocation)"/>
<xsl:for-each select="$node">
<xsl:copy>
<xsl:sequence select="@* except (@validFromDate, @validToDate)"/>
<xsl:attribute name="validFromDate" select="$validFromDate"/>
<xsl:attribute name="validToDate" select="$validToDate"/>
<xsl:attribute name="name" select="$name"/>
<xsl:sequence select="*"/>
<xsl:element name="refs">
<xsl:perform-sort select="$gigRef, $micro-locationRef, $meso-locationRef, $catenaryCaseRef">
<xsl:sort select="name()"/>
</xsl:perform-sort>
</xsl:element>
</xsl:copy>
</xsl:for-each>
</xsl:for-each>
</xsl:function>

<xsl:function name="local:transform-to-export-node" as="element()*">
<xsl:param name="params" as="map(*)*"/>
<xsl:for-each select="$params">
<xsl:variable name="node" as="element()" select="?node"/>
<xsl:variable name="validFromDate" as="xs:string" select="?validFromDate"/>
<xsl:variable name="validToDate" as="xs:string" select="?validToDate"/>
<xsl:variable name="nodeByGig" as="element()" select="?nodeByGig"/>
<xsl:variable name="nodeByLocation" as="element()?" select="?nodeByLocation"/>
<xsl:variable name="nodeByCatenaryCase" as="element()?" select="?nodeByCatenaryCase"/>
<xsl:variable name="gigRef" select="local:gigRef($nodeByGig)"/>
<xsl:variable name="micro-locationRef" select="local:micro-locationRef($nodeByLocation)"/>
<xsl:variable name="meso-locationRef" select="local:meso-locationRef($nodeByLocation)"/>
<xsl:variable name="catenaryCaseRef" select="local:catenaryCaseRef($nodeByCatenaryCase)"/>
<xsl:for-each select="$node">
<xsl:copy>
<xsl:sequence select="@* except (@validFromDate, @validToDate)"/>
<xsl:attribute name="validFromDate" select="$validFromDate"/>
<xsl:attribute name="validToDate" select="$validToDate"/>
<xsl:sequence select="*"/>
<xsl:element name="refs">
<xsl:perform-sort select="$gigRef, $micro-locationRef, $meso-locationRef, $catenaryCaseRef">
<xsl:sort select="name()"/>
</xsl:perform-sort>
</xsl:element>
</xsl:copy>
</xsl:for-each>
</xsl:for-each>
</xsl:function>

<xsl:template mode="#all" match="@*|*">
<xsl:copy>
<xsl:apply-templates select="@*|*" mode="#current"/>
</xsl:copy>
</xsl:template>

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