使用 XSLT 进行分组和计数
Grouping and Counting with XSLT
我正在尝试使用 XSLT 1.0 对节点进行评估、分组和计数,需要一点帮助。我需要做的是评估一个节点集并创建字符串,然后在输出任何内容之前对其进行分组和计数。
这是我的 XML
<?xml version="1.0" encoding="UTF-8"?>
<DATA>
<WIDGETS>
<ITEM>
<CODE>FX1</CODE>
</ITEM>
<ITEM>
<CODE>SP2</CODE>
</ITEM>
<ITEM>
<CODE>FX1</CODE>
</ITEM>
<ITEM>
<CODE>P4</CODE>
</ITEM>
<ITEM>
<CODE>WT</CODE>
</ITEM>
<ITEM>
<CODE>XQ</CODE>
</ITEM>
</WIDGETS>
</DATA>
还有我的样式表
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="html" indent="yes" />
<xsl:template match="DATA/WIDGETS">
<xsl:for-each select="ITEM">
<xsl:choose>
<xsl:when test="CODE = 'FX1'">Performance Series </xsl:when>
<xsl:when test="CODE = 'XQ'">Performance Series </xsl:when>
<xsl:when test="CODE = 'SP2'">Sports Series </xsl:when>
<xsl:when test="CODE = 'P4'">Sports Series </xsl:when>
<xsl:when test="CODE = 'WT'">Classic Series </xsl:when>
</xsl:choose>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
当前输出如下所示
Performance Series Sports Series Performance Series Sports Series Classic Series Performance Series
不过我想要的是这个
Performance Series(x3) Sports Series(x2) Classic Series
有人能帮忙吗?
一种方法是将第一个转换存储在一个变量中,在该转换中,您将所有代码转换为它们各自的系列,然后再次处理该变量以计算重复系列:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:exslt="http://exslt.org/common" version="1.0">
<xsl:output method="html" indent="yes" />
<!-- key declaration to select NEWCODE using its value -->
<xsl:key name="item" match="NEWCODE" use="."/>
<xsl:template match="DATA/WIDGETS">
<!-- variable TEMP, a temporary document containing NEWCODE
for every ITEM with respective series as its value -->
<xsl:variable name="TEMP">
<xsl:for-each select="ITEM">
<NEWCODE>
<xsl:choose>
<xsl:when test="CODE = 'FX1'">Performance Series </xsl:when>
<xsl:when test="CODE = 'XQ'">Performance Series </xsl:when>
<xsl:when test="CODE = 'SP2'">Sports Series </xsl:when>
<xsl:when test="CODE = 'P4'">Sports Series </xsl:when>
<xsl:when test="CODE = 'WT'">Classic Series </xsl:when>
</xsl:choose>
</NEWCODE>
</xsl:for-each>
</xsl:variable>
<!-- iterating on every first NEWCODE(of its series) in variable TEMP,
and creating the desired string with count of its series -->
<xsl:for-each select="exslt:node-set($TEMP)/NEWCODE[count(. | key('item', .)[1]) = 1]">
<xsl:value-of select="concat(., '(x', count(key('item', .)),') ')"/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
变量 TEMP 的处理是使用 Muenchian 的分组 完成的,它使用 key()
对元素进行分组。
在这个答案中,在文档的顶部声明了一个 xsl:key
,稍后在 xsl:for-each
到 select NEWCODE
中使用它们的值。
xsl:for-each
迭代第一次出现的 NEWCODE
(首先是它们在 $TEMP 中的值)。在 xsl:for-each
中,count(key('item', .))
将计算所有 NEWCODE
的值与您正在迭代的当前 NEWCODE
相同。
作为替代方案,您可以通过匹配每个 class 的第一项并将其转换为提供 class:
的项目总数来实现此目的
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="html" indent="yes" />
<xsl:template match="DATA/WIDGETS">
<xsl:apply-templates select="ITEM" />
</xsl:template>
<xsl:template match="ITEM"/>
<xsl:template match="ITEM[CODE = 'FX1' or CODE = 'XQ'][1]">
<xsl:variable name="count" select="count(following-sibling::ITEM[CODE = 'FX1' or CODE = 'XQ']) + 1"/>
<xsl:text>Performance Series</xsl:text>
<xsl:if test="$count > 1">(x<xsl:value-of select="$count"/>)</xsl:if>
<xsl:text> </xsl:text>
</xsl:template>
<xsl:template match="ITEM[CODE = 'SP2' or CODE = 'P4'][1]">
<xsl:variable name="count" select="count(following-sibling::ITEM[CODE = 'SP2' or CODE = 'P4']) + 1"/>
<xsl:text>Sports Series</xsl:text>
<xsl:if test="$count > 1">(x<xsl:value-of select="$count"/>)</xsl:if>
<xsl:text> </xsl:text>
</xsl:template>
<xsl:template match="ITEM[CODE = 'WT'][1]">
<xsl:variable name="count" select="count(following-sibling::ITEM[CODE = 'WT']) + 1"/>
<xsl:text>Classic Series</xsl:text>
<xsl:if test="$count > 1">(x<xsl:value-of select="$count"/>)</xsl:if>
<xsl:text> </xsl:text>
</xsl:template>
</xsl:stylesheet>
这确实存在一些选择器的重复部分,但对我来说,它比其他答案更符合习惯。它还避免依赖扩展功能,无论多么广泛支持。 YMMV.
我正在尝试使用 XSLT 1.0 对节点进行评估、分组和计数,需要一点帮助。我需要做的是评估一个节点集并创建字符串,然后在输出任何内容之前对其进行分组和计数。
这是我的 XML
<?xml version="1.0" encoding="UTF-8"?>
<DATA>
<WIDGETS>
<ITEM>
<CODE>FX1</CODE>
</ITEM>
<ITEM>
<CODE>SP2</CODE>
</ITEM>
<ITEM>
<CODE>FX1</CODE>
</ITEM>
<ITEM>
<CODE>P4</CODE>
</ITEM>
<ITEM>
<CODE>WT</CODE>
</ITEM>
<ITEM>
<CODE>XQ</CODE>
</ITEM>
</WIDGETS>
</DATA>
还有我的样式表
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="html" indent="yes" />
<xsl:template match="DATA/WIDGETS">
<xsl:for-each select="ITEM">
<xsl:choose>
<xsl:when test="CODE = 'FX1'">Performance Series </xsl:when>
<xsl:when test="CODE = 'XQ'">Performance Series </xsl:when>
<xsl:when test="CODE = 'SP2'">Sports Series </xsl:when>
<xsl:when test="CODE = 'P4'">Sports Series </xsl:when>
<xsl:when test="CODE = 'WT'">Classic Series </xsl:when>
</xsl:choose>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
当前输出如下所示
Performance Series Sports Series Performance Series Sports Series Classic Series Performance Series
不过我想要的是这个
Performance Series(x3) Sports Series(x2) Classic Series
有人能帮忙吗?
一种方法是将第一个转换存储在一个变量中,在该转换中,您将所有代码转换为它们各自的系列,然后再次处理该变量以计算重复系列:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:exslt="http://exslt.org/common" version="1.0">
<xsl:output method="html" indent="yes" />
<!-- key declaration to select NEWCODE using its value -->
<xsl:key name="item" match="NEWCODE" use="."/>
<xsl:template match="DATA/WIDGETS">
<!-- variable TEMP, a temporary document containing NEWCODE
for every ITEM with respective series as its value -->
<xsl:variable name="TEMP">
<xsl:for-each select="ITEM">
<NEWCODE>
<xsl:choose>
<xsl:when test="CODE = 'FX1'">Performance Series </xsl:when>
<xsl:when test="CODE = 'XQ'">Performance Series </xsl:when>
<xsl:when test="CODE = 'SP2'">Sports Series </xsl:when>
<xsl:when test="CODE = 'P4'">Sports Series </xsl:when>
<xsl:when test="CODE = 'WT'">Classic Series </xsl:when>
</xsl:choose>
</NEWCODE>
</xsl:for-each>
</xsl:variable>
<!-- iterating on every first NEWCODE(of its series) in variable TEMP,
and creating the desired string with count of its series -->
<xsl:for-each select="exslt:node-set($TEMP)/NEWCODE[count(. | key('item', .)[1]) = 1]">
<xsl:value-of select="concat(., '(x', count(key('item', .)),') ')"/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
变量 TEMP 的处理是使用 Muenchian 的分组 完成的,它使用 key()
对元素进行分组。
在这个答案中,在文档的顶部声明了一个 xsl:key
,稍后在 xsl:for-each
到 select NEWCODE
中使用它们的值。
xsl:for-each
迭代第一次出现的 NEWCODE
(首先是它们在 $TEMP 中的值)。在 xsl:for-each
中,count(key('item', .))
将计算所有 NEWCODE
的值与您正在迭代的当前 NEWCODE
相同。
作为替代方案,您可以通过匹配每个 class 的第一项并将其转换为提供 class:
的项目总数来实现此目的<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="html" indent="yes" />
<xsl:template match="DATA/WIDGETS">
<xsl:apply-templates select="ITEM" />
</xsl:template>
<xsl:template match="ITEM"/>
<xsl:template match="ITEM[CODE = 'FX1' or CODE = 'XQ'][1]">
<xsl:variable name="count" select="count(following-sibling::ITEM[CODE = 'FX1' or CODE = 'XQ']) + 1"/>
<xsl:text>Performance Series</xsl:text>
<xsl:if test="$count > 1">(x<xsl:value-of select="$count"/>)</xsl:if>
<xsl:text> </xsl:text>
</xsl:template>
<xsl:template match="ITEM[CODE = 'SP2' or CODE = 'P4'][1]">
<xsl:variable name="count" select="count(following-sibling::ITEM[CODE = 'SP2' or CODE = 'P4']) + 1"/>
<xsl:text>Sports Series</xsl:text>
<xsl:if test="$count > 1">(x<xsl:value-of select="$count"/>)</xsl:if>
<xsl:text> </xsl:text>
</xsl:template>
<xsl:template match="ITEM[CODE = 'WT'][1]">
<xsl:variable name="count" select="count(following-sibling::ITEM[CODE = 'WT']) + 1"/>
<xsl:text>Classic Series</xsl:text>
<xsl:if test="$count > 1">(x<xsl:value-of select="$count"/>)</xsl:if>
<xsl:text> </xsl:text>
</xsl:template>
</xsl:stylesheet>
这确实存在一些选择器的重复部分,但对我来说,它比其他答案更符合习惯。它还避免依赖扩展功能,无论多么广泛支持。 YMMV.