如何编写XSLT实现Account_Number去重分组并关联Payment输出?
问题描述
需要编写XSLT将指定XML按Account_Number分组,相同账号仅输出一次账号标题,下方列出该账号关联的所有支付记录,转换为目标文本格式。
输入XML
<Data> <Payment> <PayeeName>Jim</PayeeName> <CheckNumber>1</CheckNumber> <Account_group> <Account_Number>123456789</Account_Number> </Account_group> </Payment> <Payment> <PayeeName>Alex</PayeeName> <CheckNumber>2</CheckNumber> <Account_group> <Account_Number>123456789</Account_Number> </Account_group> </Payment> <Payment> <PayeeName>Zach</PayeeName> <CheckNumber>3</CheckNumber> <Account_group> <Account_Number>555566666</Account_Number> </Account_group> </Payment> </Data>
期望输出
Account 123456789 CheckNumber 1 Jim CheckNumber 2 Alex Account 555566666 CheckNumber 3 Zach
现有代码问题
你当前的XSLT逻辑存在以下问题:
- 在
Data模板中循环每个Payment,导致每条支付记录都会单独调用账号标题和明细模板,重复输出账号标题 AccountHeader模板仅对单个Account_group分组,无法实现全局按账号聚合的效果DetailRecord模板中尝试循环Payment,但当前上下文是单个Payment节点,无法获取同账号的所有关联支付记录
正确实现方案
使用XSLT 2.0+的xsl:for-each-group对所有Payment节点按Account_group/Account_Number分组,即可实现相同账号只输出一次标题,再遍历分组内的支付记录输出明细:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <!-- 定义换行变量,适配不同系统换行符 --> <xsl:variable name="linefeed" select="' '"/> <xsl:template match="/Data"> <!-- 按Account_Number对Payment节点全局分组 --> <xsl:for-each-group select="Payment" group-by="Account_group/Account_Number"> <!-- 输出账号标题 --> <text>Account </text> <xsl:value-of select="current-grouping-key()"/> <xsl:value-of select="$linefeed"/> <!-- 遍历当前分组内的所有Payment,输出明细 --> <xsl:for-each select="current-group()"> <text>CheckNumber </text> <xsl:value-of select="CheckNumber"/> <text> </text> <xsl:value-of select="PayeeName"/> <xsl:value-of select="$linefeed"/> </xsl:for-each> <!-- 账号之间添加空行,避免末尾出现多余空行 --> <xsl:if test="position() != last()"> <xsl:value-of select="$linefeed"/> </xsl:if> </xsl:for-each-group> </xsl:template> </xsl:stylesheet>
代码说明
xsl:for-each-group select="Payment" group-by="Account_group/Account_Number":对所有Payment节点按账号值分组,相同账号的支付记录会被归为同一组current-grouping-key():获取当前分组的账号值,用于输出账号标题current-group():获取当前分组内的所有Payment节点,遍历输出每条记录的支票号和收款人名称- 通过
position() != last()控制仅在账号分组之间添加空行,避免最终输出末尾出现多余空行
内容的提问来源于stack exchange,提问作者XSLT_apprentice
相关产品推荐
相关产品推荐

