将transaction 元素按number 和for-each-group 分组,然后将current-group() 推送到apply-templates,然后在transaction 的模板中,您可以使用@987654332 的值填充line 元素@:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="#all"
version="3.0">
<xsl:output indent="yes"/>
<xsl:mode on-no-match="shallow-copy"/>
<xsl:template match="transactions">
<xsl:copy>
<xsl:for-each-group select="transaction" group-by="number">
<xsl:apply-templates select="current-group()"/>
</xsl:for-each-group>
</xsl:copy>
</xsl:template>
<xsl:template match="transaction">
<xsl:copy>
<xsl:apply-templates select="@* , node()"/>
<line>
<xsl:value-of select="position()"/>
</line>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
https://xsltfiddle.liberty-development.net/jyRYYjm
上面将在结果中将具有相同 number 值的 transaction 元素组合在一起,如果不需要,那么在 XSLT 3 中另一个选项是使用累加器来记录 transaction 元素number 的值并输出transaction 的模板中的累加器值:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:map="http://www.w3.org/2005/xpath-functions/map"
exclude-result-prefixes="#all"
version="3.0">
<xsl:output indent="yes"/>
<xsl:mode on-no-match="shallow-copy" use-accumulators="trans-count"/>
<xsl:accumulator name="trans-count" as="map(xs:integer, xs:integer)" initial-value="map{}">
<xsl:accumulator-rule match="transaction"
select="let $number := xs:integer(number)
return if (map:contains($value, $number))
then map:put($value, $number, $value($number) + 1)
else map:put($value, $number, 1)"/>
</xsl:accumulator>
<xsl:template match="transaction">
<xsl:copy>
<xsl:apply-templates select="@* , node()"/>
<line>
<xsl:value-of select="accumulator-before('trans-count')(xs:integer(number))"/>
</line>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
https://xsltfiddle.liberty-development.net/jyRYYjm/1
两个完整示例都使用 <xsl:mode on-no-match="shallow-copy"/> 的 XSLT 3 方式将身份转换声明为转换的基础,对于 XSLT 2 处理器,您需要将其拼写为
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
改为。
对于使用键和 Muenchian 分组的 XSLT 1 解决方案,您可以使用
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:key name="trans-group"
match="transaction" use="number"/>
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="transactions">
<xsl:copy>
<xsl:for-each select="transaction[generate-id() = generate-id(key('trans-group', number)[1])]">
<xsl:apply-templates select="key('trans-group', number)"/>
</xsl:for-each>
</xsl:copy>
</xsl:template>
<xsl:template match="transaction">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
<line>
<xsl:value-of select="position()"/>
</line>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
https://xsltfiddle.liberty-development.net/jyRYYjm/4