输入:
<root><element>
<small>a</small>
<Large>B</Large>
<Time>301</Time></element><element>
<small>a</small>
<Large>B</Large>
<Time>322</Time></element><element>
<small>b</small>
<Large>A</Large>
<Time>274</Time></element><element>
<small>c</small>
<Large>B</Large>
<Time>325</Time></element><element>
<small>b</small>
<Large>A</Large>
<Time>301</Time></element></root>
需要编写一个xslt,查看small和Large元素成对的次数,并列出smallnum标记中的计数,并将多次迭代的时间添加到totsmalltime标记。
输出:
<root><element>
<small>a</small>
<Large>B</Large>
<smallnum>2</smallnum>
<totsmalltime>623</totsmalltime></element><element>
<small>b</small>
<Large>A</Large>
<smallnum>2</smallnum>
<totsmalltime>575</totsmalltime></element><element>
<small>c</small>
<Large>B</Large>
<smallnum>1</smallnum>
<totsmalltime>325</totsmalltime></element></root>
答案 0 :(得分:2)
要在XSLT1.0中执行此操作,您将使用Muenchian Grouping。在您的情况下,您通过前面的第一个大和小元素的组合对时间元素进行分组。这意味着您将首先定义以下键
<xsl:key
name="pairs"
match="Time"
use="concat(preceding-sibling::Large[1], '|', preceding-sibling::small[1])" />
然后,您需要首先出现在组中的时间元素作为其特定键。你可以这样做:
<xsl:apply-templates
select="element/Time[
generate-id()
= generate-id(
key(
'pairs',
concat(preceding-sibling::Large[1], '|', preceding-sibling::small[1])
)[1])]" />
然后,例如,要获取 smallnum 值,即组中所有元素的值,您只需执行此操作,其中 $ key 为定义为concat(preceding-sibling::Large[1], '|', preceding-sibling::small[1])
<xsl:value-of select="count(key('pairs', $key))" />
对于 totsmalltime 元素,只需使用sum而不是count。
这是完整的XSLT
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:key name="pairs" match="Time" use="concat(preceding-sibling::Large[1], '|', preceding-sibling::small[1])"/>
<xsl:template match="/root">
<root>
<xsl:apply-templates select="element/Time[generate-id() = generate-id(key('pairs', concat(preceding-sibling::Large[1], '|', preceding-sibling::small[1]))[1])]"/>
</root>
</xsl:template>
<xsl:template match="Time">
<xsl:variable name="small" select="preceding-sibling::small[1]"/>
<xsl:variable name="Large" select="preceding-sibling::Large[1]"/>
<xsl:variable name="key" select="concat($Large, '|', $small)"/>
<element>
<xsl:copy-of select="$small"/>
<xsl:copy-of select="$Large"/>
<smallnum>
<xsl:value-of select="count(key('pairs', $key))"/>
</smallnum>
<totsmalltime>
<xsl:value-of select="sum(key('pairs', $key))"/>
</totsmalltime>
</element>
</xsl:template>
</xsl:stylesheet>
应用于XML时,输出以下内容
<root>
<element>
<small>a</small>
<Large>B</Large>
<smallnum>2</smallnum>
<totsmalltime>623</totsmalltime>
</element>
<element>
<small>b</small>
<Large>A</Large>
<smallnum>2</smallnum>
<totsmalltime>575</totsmalltime>
</element>
<element>
<small>c</small>
<Large>B</Large>
<smallnum>1</smallnum>
<totsmalltime>325</totsmalltime>
</element>
</root>
编辑:在XSLT2.0中,您可以在执行计数时使用 xsl:for-each-group 元素以及 current-group()总和。
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/root">
<root>
<xsl:for-each-group select="element/Time" group-by="concat(preceding-sibling::Large[1], '|', preceding-sibling::small[1])">
<element>
<xsl:copy-of select="preceding-sibling::small[1]"/>
<xsl:copy-of select="preceding-sibling::Large[1]"/>
<smallnum>
<xsl:value-of select="count(current-group())"/>
</smallnum>
<totsmalltime>
<xsl:value-of select="sum(current-group())"/>
</totsmalltime>
</element>
</xsl:for-each-group>
</root>
</xsl:template>
</xsl:stylesheet>
这也应该输出相同的XML。
答案 1 :(得分:0)
您所追求的技术称为 Muenchian分组,您希望通过element
和small
值的组合对Large
元素进行分组:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:key name="smallLarge" match="element"
use="concat(small, '_', Large)" />
<xsl:template match="/">
<root>
<xsl:apply-templates select="root/element[generate-id() = generate-id(
key('smallLarge', concat(small, '_', Large)[1])]" />
</root>
</xsl:template>
<xsl:template match="element">
<element>
<small><xsl:value-of select="small" /></small>
<Large><xsl:value-of select="Large" /></Large>
<smallnum><xsl:value-of select="count(key('smallLarge',
concat(small, '_', Large)))" /></smallnum>
<totsmalltime><xsl:value-of select="sum(key('smallLarge',
concat(small, '_', Large))/Time)" /></totsmalltime>
</element>
</xsl:template>
</xsl:stylesheet>
有趣的一行是
<xsl:apply-templates select="root/element[generate-id() = generate-id(
key('smallLarge', concat(small, '_', Large)[1])]" />
使用generate-id
为每个键值仅选择第一个 element
元素。因此,element
模板将针对每个small
/ Large
组合调用一次,该模板可以使用该键来计算和总结该特定键值的所有时间。
P.S。原始XML示例上的缩进很糟糕,我花了几个读数来注意element
元素,起初它看起来像一个small
,Large
和{{1}的长序列兄弟姐妹......
答案 2 :(得分:0)
<强>予。 XSLT 1.0解决方案:
这是一个完全“推动式”的简短解决方案:)
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:key name="kElem" match="element"
use="concat(small, '+', Large)"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match=
"element[generate-id()=generate-id(key('kElem',concat(small, '+', Large))[1])]">
<xsl:variable name="vGroup" select="key('kElem',concat(small, '+', Large))"/>
<element>
<xsl:apply-templates/>
<smallnum><xsl:value-of select="count($vGroup)"/></smallnum>
<totsmalltime><xsl:value-of select="sum($vGroup/Time)"/></totsmalltime>
</element>
</xsl:template>
<xsl:template match="element|Time"/>
</xsl:stylesheet>
在提供的XML文档上应用此转换时:
<root>
<element>
<small>a</small>
<Large>B</Large>
<Time>301</Time>
</element>
<element>
<small>a</small>
<Large>B</Large>
<Time>322</Time>
</element>
<element>
<small>b</small>
<Large>A</Large>
<Time>274</Time>
</element>
<element>
<small>c</small>
<Large>B</Large>
<Time>325</Time>
</element>
<element>
<small>b</small>
<Large>A</Large>
<Time>301</Time>
</element>
</root>
产生了想要的正确结果:
<root>
<element>
<small>a</small>
<Large>B</Large>
<smallnum>2</smallnum>
<totsmalltime>623</totsmalltime>
</element>
<element>
<small>b</small>
<Large>A</Large>
<smallnum>2</smallnum>
<totsmalltime>575</totsmalltime>
</element>
<element>
<small>c</small>
<Large>B</Large>
<smallnum>1</smallnum>
<totsmalltime>325</totsmalltime>
</element>
</root>
<强>解释强>:
正确使用和覆盖 identity rule 。
正确使用 Muenchian Grouping Method 。
<强> II。 XSLT 2.0解决方案:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="/*">
<root>
<xsl:for-each-group select="*" group-by="concat(small, '+', Large)">
<element>
<xsl:sequence select="small, Large"/>
<smallnum>
<xsl:sequence select="count(current-group())"/>
</smallnum>
<totsmalltime>
<xsl:sequence select="sum(current-group()/Time)"/>
</totsmalltime>
</element>
</xsl:for-each-group>
</root>
</xsl:template>
</xsl:stylesheet>
当此转换应用于同一XML文档(上图)时,会产生相同的正确结果:
<root>
<element>
<small>a</small>
<Large>B</Large>
<smallnum>2</smallnum>
<totsmalltime>623</totsmalltime>
</element>
<element>
<small>b</small>
<Large>A</Large>
<smallnum>2</smallnum>
<totsmalltime>575</totsmalltime>
</element>
<element>
<small>c</small>
<Large>B</Large>
<smallnum>1</smallnum>
<totsmalltime>325</totsmalltime>
</element>
</root>
<强>解释强>:
正确使用带有group-by
属性的 <xsl:for-each-group>
。
正确使用 current-group()
功能。