xslt 2.0 - Comparing to two lists -


this long, long question. apologies.

my xslt not bad can see reputation. i've been struggling day solve coding problem , have, in end, come solution don't it.

it seems me have managed code procedural solution in functional language , welcome more elegant, cleaner solutions more in spirit of xslt.

i doing data reconciliation exercise between 2 computer systems holding similar data.

the data in question public transport routes, each route consisting of list of points e.g.

<routes>     <route id="1">             <point id="1"/>                       <point id="2"/>                       <point id="3"/>                       <point id="4"/>                       <point id="5"/>               </route> </routes> 

none of id's simple, incrementing integers in reality of course.

for 'business reasons' route may appear in other system as

<routes>     <route id="1">             <point id="1"/>                       <point id="2"/>               </route>     <route id="1a">             <point id="3"/>                       <point id="4"/>                       <point id="5"/>               </route> </routes> 

we can assume point id's match between systems enough

now, have code compares route 1 in 1 system , routes start 1 in other system , produces like:

<routes>     <route>         <point id="1" in="y"/>         <point id="2" in="y"/>         <point id="3" in="n"/>         <point id="4" in="n"/>         <point id="5" in="y"/>         <point id="6" in="y"/>         <point id="7" in="n"/>         <point id="8" in="n"/>         <point id="9" in="n"/>                     </route> </routes> 

where in='y' means point in system b route

this sort of output little difficult business understand. deal following easier

<routes>     <route>         <route>             <group startpoint="1" endpoint="2" in="y"/>             <group startpoint="3" endpoint="4" in="n"/>             <group startpoint="5" endpoint="6 "in="y"/>             <group startpoint="7" endpoint="9" in="y"/>         </route>     </route> </routes> 

obviously, don't show them thing this. shows them excel sheets text description of things, want reduce points of list not change status sections start , ends more easy understand in business terms.

in other words want see route same first half of other route skips bunch of points matches again.

so....

how reduce sequences of y , n elements element started saying y here till here said n here here , n last few. hope makes sense

my test data:

<routes>     <route>         <point id="1" in="y"/>         <point id="2" in="y"/>         <point id="3" in="n"/>         <point id="4" in="n"/>         <point id="5" in="y"/>         <point id="6" in="y"/>         <point id="7" in="n"/>         <point id="8" in="n"/>         <point id="9" in="n"/>                     </route> </routes> 

my solution:

<?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" exclude-result-prefixes="xs" version="2.0">      <xsl:template match="/">     <routes>         <xsl:apply-templates select="/routes"/>     </routes> </xsl:template>  <xsl:template match="/routes">     <route>         <xsl:apply-templates select="route"/>     </route> </xsl:template>  <xsl:template match="/routes/route">     <xsl:copy>         <xsl:copy-of select="@*"/>         <xsl:apply-templates select="." mode="pointy">             <xsl:with-param name="posn" select="1" as="xs:integer"/>             <xsl:with-param name="startposn" select="1" as="xs:integer"/>         </xsl:apply-templates>     </xsl:copy> </xsl:template>     <xsl:template match="/routes/route" mode="pointy">     <xsl:param name="posn" as="xs:integer"/>     <xsl:param name="startposn" as="xs:integer"/>     <xsl:variable name="grouptype" select="point[position()=$startposn]/@in"/>      <xsl:if test="$posn!=1 , $grouptype != point[$posn]/@in">         <group>             <xsl:attribute name="startpoint" select="point[$startposn]/@id"/>             <xsl:attribute name="endpoint" select="point[$posn - 1]/@id"/>         </group>     </xsl:if>      <xsl:if test="$posn = count(point)">         <group>             <xsl:attribute name="startpoint" select="point[$startposn]/@id"/>             <xsl:attribute name="endpoint" select="point[$posn]/@id"/>         </group>                 </xsl:if>      <xsl:if test="$grouptype = point[$posn]/@in , $posn != count(point)">         <xsl:apply-templates select="." mode="pointy">             <xsl:with-param name="posn" select="$posn + 1" as="xs:integer"/>             <xsl:with-param name="startposn" select="$startposn" as="xs:integer"/>         </xsl:apply-templates>                 </xsl:if>      <xsl:if test="$grouptype != point[$posn]/@in , $posn != count(point)">         <xsl:apply-templates select="." mode="pointy">             <xsl:with-param name="posn" select="$posn + 1" as="xs:integer"/>             <xsl:with-param name="startposn" select="$posn" as="xs:integer"/>         </xsl:apply-templates>                 </xsl:if>  </xsl:template>     </xsl:stylesheet> 

given format

<routes>     <route>         <point id="1" in="y"/>         <point id="2" in="y"/>         <point id="3" in="n"/>         <point id="4" in="n"/>         <point id="5" in="y"/>         <point id="6" in="y"/>         <point id="7" in="n"/>         <point id="8" in="n"/>         <point id="9" in="n"/>                     </route> </routes> 

you can use group-adjacent with

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/xsl/transform">  <xsl:output indent="yes"/>  <xsl:template match="@* | node()">   <xsl:copy>     <xsl:apply-templates select="@* , node()"/>   </xsl:copy> </xsl:template>  <xsl:template match="route">   <xsl:copy>     <xsl:for-each-group select="point" group-adjacent="@in">       <group startpoint="{@id}" endpoint="{current-group()[last()]/@id}" in="{@in}"/>     </xsl:for-each-group>   </xsl:copy> </xsl:template>  </xsl:stylesheet> 

to get

<routes>     <route>       <group startpoint="1" endpoint="2" in="y"/>       <group startpoint="3" endpoint="4" in="n"/>       <group startpoint="5" endpoint="6" in="y"/>       <group startpoint="7" endpoint="9" in="n"/>    </route> </routes> 

Comments

Popular posts from this blog

how to proxy from https to http with lighttpd -

android - Automated my builds -

python - Flask migration error -