这是输入文件。
<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>
分组规则
<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,但它只按Price
分组<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>
任何帮助都将非常感激。
Step by Step分组
按相同的Price和Key为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>
在每个组中删除重复的腿(相同的键)
<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>
组相同的价格和相同的键为Leg Group=1(第一组和第二组有相同的Leg Group=1,所以我们可以称之为Group)
<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>
在每个组中删除重复的腿(相同的键)
<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>
最后是输出
为了推进这一进程,我发布了这个暂定的样式表,它可能接近也可能不接近你想要的:
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>
有趣的分配…
我认为答案在Muenchian Grouping中并不像在递归中那么多。您可以遵循第一个组的引用路径,并注册所遵循路径的key在对特定路径的所有Leg元素进行分组之后,您可以移动到下一个尚未"访问"的Box,以创建下一个组
<?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>