我找到了一个similar问题,但我无法找到解决问题的方法。
我有一个XML如下
<name>
<text class="002. AB vs BC"> Sample</text>
<text class="003. DC vs BC"> Sample</text>
<text class="004. CD vs BC"> Sample</text>
<text class="005. AB vs BC"> Sample</text>
<text class="006. AB vs BC"> Sample</text>
<text class="007. EF vs BC"> Sample</text>
<text class="008. CD vs BC"> Sample</text>
<text class="009. DC vs BC"> Sample</text>
<text class="010. AB vs BC"> Sample</text>
<text class="011. EF vs BC"> Sample</text>
<text class="012. AB vs BC"> Sample</text>
</name>
我需要将类属性中类似第一个单词的所有节点分组如下
<name>
<group name="AB">
<text class="002. AB vs BC"> Sample</text>
<text class="005. AB vs BC"> Sample</text>
<text class="006. AB vs BC"> Sample</text>
<text class="010. AB vs BC"> Sample</text>
<text class="012. AB vs BC"> Sample</text>
</group>
<group name="EF">
<text class="007. EF vs BC"> Sample</text>
<text class="011. EF vs BC"> Sample</text>
</group>
<group name="CD">
<text class="008. CD vs BC"> Sample</text>
<text class="004. CD vs BC"> Sample</text>
</group>
<group name="DC">
<text class="003. DC vs BC"> Sample</text>
<text class="009. DC vs BC"> Sample</text>
</group>
</name>
如何实现这一目标?
答案 0 :(得分:1)
这是一个非常简单的分组问题。
如果您仅限于XSLT 1.0,则需要使用Muenchian Grouping。
如果您使用的是XSLT 2.0+,则可以使用xsl:for-each-group。
...实例
XSLT 1.0
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:key name="class" match="text"
use="substring-before(substring-after(normalize-space(@class), ' '),' ')"/>
<!--identity template-->
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/name">
<xsl:copy>
<xsl:apply-templates select="@*"/>
<xsl:for-each select="text[count(.|key('class', substring-before(substring-after(normalize-space(@class), ' '),' '))[1])=1]">
<xsl:variable name="key" select="substring-before(substring-after(normalize-space(@class), ' '),' ')"/>
<group name="{$key}">
<xsl:apply-templates select="key('class',$key)"/>
</group>
</xsl:for-each>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
小提琴:http://xsltfiddle.liberty-development.net/94hvTyR
XSLT 3.0 (如果使用1.0样式表中的标识模板替换xsl:mode
,则可以使此有效2.0)
<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:mode on-no-match="shallow-copy"/>
<xsl:template match="name">
<xsl:copy>
<xsl:apply-templates select="@*"/>
<xsl:for-each-group select="text"
group-by="tokenize(normalize-space(@class),'\s+')[2]">
<group name="{current-grouping-key()}">
<xsl:apply-templates select="current-group()"/>
</group>
</xsl:for-each-group>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
小提琴:http://xsltfiddle.liberty-development.net/94hvTyR/1
注意:输出与您的示例的顺序不同,但我没有看到任何订购逻辑。
答案 1 :(得分:1)
使用XSLT-2.0,您可以将xsl:for-each-group
与这些模板一起使用:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="text()" />
<!-- identity template -->
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*" />
</xsl:copy>
</xsl:template>
<xsl:template match="name">
<xsl:copy>
<xsl:for-each-group select="text" group-by="tokenize(@class,' ')[2]">
<group name="{current-grouping-key()}">
<xsl:for-each select="current-group()">
<xsl:copy-of select="." />
</xsl:for-each>
</group>
</xsl:for-each-group>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
输出为:
<name>
<group name="AB">
<text class="002. AB vs BC"> Sample</text>
<text class="005. AB vs BC"> Sample</text>
<text class="006. AB vs BC"> Sample</text>
<text class="010. AB vs BC"> Sample</text>
<text class="012. AB vs BC"> Sample</text>
</group>
<group name="DC">
<text class="003. DC vs BC"> Sample</text>
<text class="009. DC vs BC"> Sample</text>
</group>
<group name="CD">
<text class="004. CD vs BC"> Sample</text>
<text class="008. CD vs BC"> Sample</text>
</group>
<group name="EF">
<text class="007. EF vs BC"> Sample</text>
<text class="011. EF vs BC"> Sample</text>
</group>
</name>