多个键上的XSLT组

时间:2014-05-13 06:21:30

标签: xml xslt xslt-1.0 xslt-grouping muenchian-grouping

这是输入文件。

<XML>
<Box Price="541" Key="1">
<Leg Key="56T58T" Group="0"></Leg>
<Leg Key="177T179T" Group="1"></Leg>
</Box>
<Box Price="541" Key="2">
<Leg Key="128T130T" Group="0"></Leg>
<Leg Key="196T198T" Group="1"></Leg>
</Box>
<Box Price="541" Key="3">
<Leg Key="56T58T" Group="0"></Leg>
<Leg Key="196T198T" Group="1"></Leg>
</Box>
<Box Price="541" Key="4">
<Leg Key="128T130T" Group="0"></Leg>
<Leg Key="177T179T" Group="1"></Leg>
</Box>
<Box Price="541" Key="5">
<Leg Key="243T246T" Group="0"></Leg>
<Leg Key="60T63T" Group="1"></Leg>
</Box>
<Box Price="541" Key="6">
<Leg Key="243T246T" Group="0"></Leg>
<Leg Key="133T136T" Group="1"></Leg>
</Box>
<Box Price="700" Key="7">
<Leg Key="243T" Group="0"></Leg>
<Leg Key="133T136T" Group="1"></Leg>
</Box>
</XML>

输出结果为:

<Box Price="541">
<Leg Key="56T58T" Group="0"></Leg>
<Leg Key="128T130T" Group="0"></Leg>
<Leg Key="177T179T" Group="1"></Leg>
<Leg Key="196T198T" Group="1"></Leg>
</Box>
<Box Price="541">
<Leg Key="243T246T" Group="0"></Leg>
<Leg Key="133T136T" Group="1"></Leg>
<Leg Key="60T63T" Group="1"></Leg>
</Box>
<Box Price="700">
<Leg Key="243T" Group="0"></Leg>
<Leg Key="133T136T" Group="1"></Leg>
</Box>

分组规则

  • 价格
  • 腿组= 0,gropup = 1是对。当leg Group = 0时,我们可以对leg进行分组,其中Key = in Group = 1。例如,组中的腿= 0具有键= 56T58T并且组中的两个键(177T179T和196T198T)= 1。相同的两个键(177T179T和196T198T)具有Leg in Group = 0 Key = 128T130T。所以我们可以将它分组

    <Box Price="541">
    <Leg Key="56T58T" Group="0"></Leg>
    <Leg Key="128T130T" Group="0"></Leg>
    <Leg Key="177T179T" Group="1"></Leg>
    <Leg Key="196T198T" Group="1"></Leg>
    </Box>
    

    我正在使用XSLT 1.0。任何帮助都会非常感激。



    我有xsl,但它只按价格分组

    <xsl:output method="xml" indent="yes" />
    
    <xsl:key name="price" match="Box" use="@Price" />
    
    
    <xsl:template match="XML">
            <xsl:apply-templates select="Box[generate-id(.)=generate-id(key('price',@Price)[1])]"/>
    </xsl:template>
    
    
    <xsl:template match="Box">
        <Group Price="{@Price}">
            <xsl:for-each select="key('price', @Price)"> 
          <xsl:for-each select="Leg">  
                <Leg Key="{@Key}" Group="{@Group}"></Leg>
             </xsl:for-each>
            </xsl:for-each>
        </Group>
    </xsl:template>
    

    和输出:

    <?xml version="1.0"?>
    <Group Price="541">
     <Leg Key="56T58T" Group="0"/>
     <Leg Key="177T179T" Group="1"/>
     <Leg Key="128T130T" Group="0"/>
     <Leg Key="196T198T" Group="1"/>
     <Leg Key="56T58T" Group="0"/>
     <Leg Key="196T198T" Group="1"/>
     <Leg Key="128T130T" Group="0"/>
     <Leg Key="177T179T" Group="1"/>
     <Leg Key="243T246T" Group="0"/>
     <Leg Key="60T63T" Group="1"/>
     <Leg Key="243T246T" Group="0"/>
     <Leg Key="133T136T" Group="1"/>
    </Group><Group Price="700">
      <Leg Key="243T" Group="0"/>
      <Leg Key="133T136T" Group="1"/>
    </Group>
    

    任何帮助都会非常感激。

    逐步分组。

    1. 按相同价格分组并且Leg Group的相同键= 0

      <Group Price="541"> <Leg Key="56T58T" Group="0"></Leg> <Leg Key="177T179T" Group="1"></Leg> <Leg Key="56T58T" Group="0"></Leg> <Leg Key="196T198T" Group="1"></Leg> </Group> <Group Price="541"> <Leg Key="128T130T" Group="0"></Leg> <Leg Key="196T198T" Group="1"></Leg> <Leg Key="128T130T" Group="0"></Leg> <Leg Key="177T179T" Group="1"></Leg> </Group> <Group Price="541"> <Leg Key="243T246T" Group="0"></Leg> <Leg Key="60T63T" Group="1"></Leg> <Leg Key="243T246T" Group="0"></Leg> <Leg Key="133T136T" Group="1"></Leg> </Group> <Group Price="700"> <Leg Key="243T" Group="0"></Leg> <Leg Key="133T136T" Group="1"></Leg> </Group>

    2. 在每个组中删除重复的Legs(相同的Key)

      <Group Price="541" > <Leg Key="56T58T" Group="0"></Leg> <Leg Key="177T179T" Group="1"></Leg> <Leg Key="196T198T" Group="1"></Leg> </Group> <Group Price="541"> <Leg Key="128T130T" Group="0"></Leg> <Leg Key="196T198T" Group="1"></Leg> <Leg Key="177T179T" Group="1"></Leg> </Group> <Group Price="541"> <Leg Key="243T246T" Group="0"></Leg> <Leg Key="60T63T" Group="1"></Leg> <Leg Key="133T136T" Group="1"></Leg> </Group> <Group Price="700"> <Leg Key="243T" Group="0"></Leg> <Leg Key="133T136T" Group="1"></Leg> </Group>

    3. 将Leg Group的相同价格和相同的密钥分组= 1(首先是第二组具有相同的Legs组= 1,所以我们可以Gruop)

      <Group Price="541"> <Leg Key="56T58T" Group="0"></Leg> <Leg Key="177T179T" Group="1"></Leg> <Leg Key="196T198T" Group="1"></Leg> <Leg Key="128T130T" Group="0"></Leg> <Leg Key="196T198T" Group="1"></Leg> <Leg Key="177T179T" Group="1"></Leg> </Group> <Group Price="541"> <Leg Key="243T246T" Group="0"></Leg> <Leg Key="60T63T" Group="1"></Leg> <Leg Key="133T136T" Group="1"></Leg> </Group> <Group Price="700"> <Leg Key="243T" Group="0"></Leg> <Leg Key="133T136T" Group="1"></Leg> </Group>

    4. 在每个组中删除重复的Legs(相同的Key)

      <Group Price="541"> <Leg Key="56T58T" Group="0"></Leg> <Leg Key="128T130T" Group="0"></Leg> <Leg Key="177T179T" Group="1"></Leg> <Leg Key="196T198T" Group="1"></Leg> </Group> <Group Price="541"> <Leg Key="243T246T" Group="0"></Leg> <Leg Key="60T63T" Group="1"></Leg> <Leg Key="133T136T" Group="1"></Leg> </Group> <Group Price="700"> <Leg Key="243T" Group="0"></Leg> <Leg Key="133T136T" Group="1"></Leg> </Group>

    5. 最终是它的输出。

  • 2 个答案:

    答案 0 :(得分:1)

    为了推动这一进展,我发布了这个试验性的样式表,可能与你想要的一样接近:

    XSLT 1.0

    <xsl:stylesheet version="1.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
    
    <xsl:key name="box-by-price" match="Box" use="@Price" />
    <xsl:key name="box-by-legs" match="Box" use="Leg/@Key" />
    <xsl:key name="leg-by-key" match="Leg" use="@Key" />
    
    <xsl:template match="XML">
        <root>
            <!-- (1) group by price -->
            <xsl:for-each select="Box[generate-id()=generate-id(key('box-by-price',@Price)[1])]">
                <!-- (2) within each price group, combine boxes that share a common leg (regardless of group) -->
                <xsl:for-each select="key('box-by-price',@Price)[generate-id()=generate-id(key('box-by-legs',Leg/@Key)[1])]">
                    <Group Price="{@Price}">
                        <!-- (3) in each group, list the unique legs of all the boxes in the group -->
                            <xsl:copy-of select="key('box-by-legs',Leg/@Key)/Leg[generate-id()=generate-id(key('leg-by-key',@Key)[1])]"/>
                    </Group>
                </xsl:for-each>
            </xsl:for-each>
        </root>
    </xsl:template>
    
    </xsl:stylesheet>
    

    当此功能应用于输入

    <?xml version="1.0" encoding="UTF-8"?>
    <XML>
       <Box Price="541" Key="1">
          <Leg Key="56T58T" Group="0"/>
          <Leg Key="177T179T" Group="1"/>
       </Box>
       <Box Price="541" Key="2">
          <Leg Key="128T130T" Group="0"/>
          <Leg Key="196T198T" Group="1"/>
       </Box>
       <Box Price="541" Key="3">
          <Leg Key="56T58T" Group="0"/>
          <Leg Key="196T198T" Group="1"/>
       </Box>
       <Box Price="541" Key="4">
          <Leg Key="128T130T" Group="0"/>
          <Leg Key="177T179T" Group="1"/>
       </Box>
       <Box Price="541" Key="5">
          <Leg Key="243T246T" Group="0"/>
          <Leg Key="60T63T" Group="1"/>
       </Box>
       <Box Price="541" Key="6">
          <Leg Key="243T246T" Group="0"/>
          <Leg Key="133T136T" Group="1"/>
       </Box>
       <Box Price="700" Key="7">
          <Leg Key="243T" Group="0"/>
          <Leg Key="133T136T" Group="1"/>
       </Box>
    </XML>
    

    结果是:

    <?xml version="1.0" encoding="UTF-8"?>
    <root>
       <Group Price="541">
          <Leg Key="56T58T" Group="0"/>
          <Leg Key="177T179T" Group="1"/>
       </Group>
       <Group Price="541">
          <Leg Key="128T130T" Group="0"/>
          <Leg Key="196T198T" Group="1"/>
       </Group>
       <Group Price="541">
          <Leg Key="243T246T" Group="0"/>
          <Leg Key="60T63T" Group="1"/>
          <Leg Key="133T136T" Group="1"/>
       </Group>
    </root>
    

    答案 1 :(得分:0)

    有趣的作业......

    我认为答案在Muenchian Grouping中并不像递归那样多。 您可以按照第一组的引用路径并注册所遵循的路径的键 在对该特定路径的所有Leg元素进行分组之后,您可以继续前进到尚未访问的下一个Box&#34;创建下一组

    <?xml version="1.0" encoding="UTF-8"?>
    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
        version="1.0">
    
        <xsl:key name="link" match="Leg" use="concat(parent::Box/@Price, '-', @Key, '-', @Group)"/>
    
        <xsl:output indent="yes"/>
    
        <xsl:template match="XML">
            <XML>
                <xsl:call-template name="process-group-node">
                    <xsl:with-param name="box" select="Box[1]"/>
                </xsl:call-template>
            </XML>
        </xsl:template>
    
        <xsl:template name="process-group-node">
            <xsl:param name="box"/>
            <xsl:param name="used-keys"/>
            <xsl:variable name="new-keys">
                <xsl:call-template name="search-path">
                    <xsl:with-param name="running-route" select="'#'"/>
                    <xsl:with-param name="current-leg" select="$box/Leg[1]"/>
                </xsl:call-template>
            </xsl:variable>
            <Box Price="{$box/@Price}">
                <xsl:for-each select="/XML/Box[contains($new-keys, concat('#', @Key, '#'))]/Leg[generate-id() = generate-id(key('link', concat(parent::Box/@Price, '-', @Key, '-', @Group) )[1])]">
                    <xsl:sort select="@Group" data-type="number" order="ascending"/>
                    <xsl:copy-of select="."/>
                </xsl:for-each>
            </Box>
            <xsl:variable name="new-concat-keys" select="concat($used-keys, $new-keys)"/>
            <xsl:if test="$box/following-sibling::Box[not(contains($new-concat-keys, concat('#', @Key, '#')))]">
                <xsl:call-template name="process-group-node">
                    <xsl:with-param name="box" select="$box/following-sibling::Box[not(contains($new-concat-keys, concat('#', @Key, '#')))]"/>
                    <xsl:with-param name="used-keys" select="$new-concat-keys"/>
                </xsl:call-template>
            </xsl:if>
        </xsl:template>
    
        <xsl:template name="search-path">
            <xsl:param name="running-route"/>
            <xsl:param name="current-leg"/>
            <xsl:choose>
                <xsl:when test="contains($running-route, concat('#', $current-leg/parent::Box/@Key, '#'))">
                    <xsl:value-of select="$running-route"/>
                </xsl:when>
                <xsl:otherwise>
                    <xsl:variable name="this-id" select="generate-id($current-leg)"/>
                    <xsl:variable name="this-key" select="concat($current-leg/parent::Box/@Price, '-', $current-leg/@Key, '-', $current-leg/@Group)"/>
                    <xsl:variable name="next-equivalent-leg" select="key('link', $this-key)[not(generate-id() = $this-id)]"/>
                    <xsl:variable name="next-equivalent-id" select="generate-id($next-equivalent-leg)"/>
                    <xsl:variable name="next-leg" select="$next-equivalent-leg/parent::Box/Leg[not(generate-id() = $next-equivalent-id)]"/>
                    <xsl:call-template name="search-path">
                        <xsl:with-param name="running-route" select="concat($running-route, $current-leg/parent::Box/@Key ,'#')"/>
                        <xsl:with-param name="current-leg" select="$next-leg"></xsl:with-param>
                    </xsl:call-template>
                </xsl:otherwise>
            </xsl:choose>
        </xsl:template>
    
    </xsl:stylesheet>