2014-05-17 262 views
2

这是一个很长很长的问题。道歉。比较两个列表

我的XSLT并不算太糟,正如您从我的声誉中看到的那样。我一整天都在努力解决一个编码问题,并最终提出了一个解决方案,但我不喜欢它。

在我看来,我已经设法使用函数式语言编写过程式解决方案,并且我希望更多XSLT精神的更优雅,更清洁的解决方案。

我正在做两个拥有非常类似数据的计算机系统之间的数据和解练习。

有问题的数据是公共交通路线,每条路线由点列表组成,例如,

<Routes> 
    <Route Id="1"> 
      <Point Id="1"/>   
      <Point Id="2"/>   
      <Point Id="3"/>   
      <Point Id="4"/>   
      <Point Id="5"/>   
    </Route> 
</Routes> 

没有一个Id很简单,当然在递增整数。

对于“商业原因”这个路线可能会在其他系统出现

<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> 

我们可以假设点号的系统往往不够之间的匹配现在

,我有一个比较路由代码1在一个系统和路由与1中的其他系统启动并可以产生类似:

<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> 

在哪里=“Y”表示一点也是SYSTE m B为此路线

这种输出对企业来说有点难以理解。他们可以处理以下更容易

<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> 

很明显,我并没有真正向他们展示任何这样的事情。我向他们展示了带有文字描述的Excel工作表,但我希望减少列表中不会将状态更改为开始和结束部分的点数,因为这在商业术语中更容易理解。

换句话说,他们希望看到这条路线与其他路线的前半部分相同,然后跳过一堆点然后再次匹配。

所以....

如何减少说我们这里开始到这里说Y Y的序列和N元素,元素那么我们该N从这里到这里,然后N代表过去的几年。希望这是有道理

我的测试数据:

<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> 

我的解决办法:

<?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 and $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 and $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 and $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> 

回答

2

提供的格式

<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> 

可以使用group-adjacent

<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> 

得到

<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>