xslt - 动态分组
问题描述
我试图通过将节点相加来将数据组合在一起。例子
<root>
<row id="AAA" val="2"/>
<row id="BBB" val="3"/>
<row id="CCC" val="1"/>
<row id="DDD" val="4"/>
<row id="EEE" val="6"/>
<row id="FFF" val="3"/>
<row id="GGG" val="6"/>
<row id="HHH" val="8"/>
<row id="III" val="3"/>
<row id="JJJ" val="4"/>
<row id="KKK" val="2"/>
<row id="LLL" val="1"/>
</root>
假设我有一个 10 的参数,那么每次值总和为 10 或小于 10 时,它们应该组合在一起。结果应该是
<root>
<grouped>
<row id="AAA" val="2"/>
<row id="BBB" val="3"/>
<row id="CCC" val="1"/>
<row id="DDD" val="4"/>
</grouped>
<grouped>
<row id="EEE" val="6"/>
<row id="FFF" val="3"/>
</grouped>
<grouped>
<row id="GGG" val="6"/>
</grouped>
<grouped>
<row id="HHH" val="8"/>
</grouped>
<grouped>
<row id="III" val="3"/>
<row id="JJJ" val="4"/>
<row id="KKK" val="2"/>
<row id="LLL" val="1"/>
</grouped>
</root>
我尝试使用 group-adjacent 和 sum(current/@val + following-sibling::row/@val le 10) 然后尝试 group-by(sum(@val)) 但我可以看到我的基本方法不正确。现在我想知道,这是否可能。所以我想我会问专家!
谢谢!
解决方案
在 XSLT 1 中,您可以使用兄弟递归,在 XSLT 3 中使用起来更容易但有点冗长xsl:iterate
:
<xsl:template match="root">
<xsl:copy>
<xsl:iterate select="row">
<xsl:param name="sum" as="xs:integer" select="0"/>
<xsl:param name="group" as="element(row)*" select="()"/>
<xsl:on-completion>
<xsl:if test="$group">
<group>
<xsl:copy-of select="$group"/>
</group>
</xsl:if>
</xsl:on-completion>
<xsl:variable name="current-sum" select="$sum + xs:integer(@val)"/>
<xsl:if test="$current-sum > 10">
<group>
<xsl:copy-of select="$group"/>
</group>
</xsl:if>
<xsl:next-iteration>
<xsl:with-param name="sum" select="if ($current-sum > 10) then xs:integer(@val) else $current-sum"/>
<xsl:with-param name="group" select="if ($current-sum > 10) then . else ($group, .)"/>
</xsl:next-iteration>
</xsl:iterate>
</xsl:copy>
</xsl:template>
https://xsltfiddle.liberty-development.net/6pS2B6o
作为替代方案,您可以使用累加器对@val
值求和并在“组”建立时“记住”,然后在分组中您可以使用group-starting-with
来检查累加器:
<xsl:param name="max" as="xs:integer" select="10"/>
<xsl:mode on-no-match="shallow-copy" use-accumulators="#all"/>
<xsl:output method="xml" indent="yes"/>
<xsl:accumulator name="window" as="item()*" initial-value="()">
<xsl:accumulator-rule match="root" select="(0, true())"/>
<xsl:accumulator-rule match="root/row"
select="let $val := xs:integer(@val),
$sum := $value[1],
$window-start := $value[2],
$current-sum := $sum + $val
return
if ($current-sum gt $max)
then ($val, true())
else ($current-sum, false())"/>
</xsl:accumulator>
<xsl:template match="root">
<xsl:copy>
<xsl:for-each-group select="row" group-starting-with="*[accumulator-before('window')[2]]">
<grouped>
<xsl:apply-templates select="current-group()"/>
</grouped>
</xsl:for-each-group>
</xsl:copy>
</xsl:template>
https://xsltfiddle.liberty-development.net/6pS2B6o/1
您甚至可以使该流式传输(在 Michael Kay 的帮助下):
<?xml version="1.0" encoding="UTF-8"?>
<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:param name="max" as="xs:integer" select="10"/>
<xsl:mode on-no-match="shallow-copy" use-accumulators="#all" streamable="yes"/>
<xsl:output method="xml" indent="yes"/>
<xsl:accumulator name="window" as="item()*" initial-value="()" streamable="yes">
<xsl:accumulator-rule match="root" select="(0, true())"/>
<xsl:accumulator-rule match="root/row"
select="
let $val := xs:integer(@val),
$sum := $value[1],
$window-start := $value[2],
$current-sum := $sum + $val
return
if ($current-sum gt $max)
then
($val, true())
else
($current-sum, false())"
/>
</xsl:accumulator>
<xsl:template match="root">
<xsl:copy>
<xsl:for-each-group select="row"
group-starting-with="*[boolean(accumulator-before('window')[2])]">
<grouped>
<xsl:apply-templates select="current-group()"/>
</grouped>
</xsl:for-each-group>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
推荐阅读
- javascript - 如何根据数字和字符串(阿拉伯语名称)对对象数组进行排序?
- c - C - 将全局复制到本地数组,而不是分配索引
- java - Twofish encryption decryption Algorithm
- spring-boot - Spring Boot RestController DELETE 请求失败,没有 .csrf().disable()
- excel - VBA Excel 将日期单元格与 Outlook 日历事件同步
- csv - IMPORTDATA() 不提取最新数据
- c++ - 将较大的整数写入二进制并将它们读回会产生不好的结果
- python - PyEDA:将文本字符串转换为 DNF 形式
- maven - Jenkins Pipeline - Maven 编译失败
- tensorflow - 如何在tensorflow中从单独的特征和标签csv中加载、随机播放、批处理?