如何用XSLT 1.0拆分支付历史字符串?解决XML节点重复问题
解决XSLT 1.0支付历史字符串分组去重问题
我来帮你搞定这个重复节点的问题!在XSLT 1.0里处理这种按年份分组的需求,Muenchian分组法是最靠谱的方案——这正是解决你当前重复节点问题的核心。
先明确需求场景
假设你的输入字符串是这样的(模拟示例):Apr:2013,1200/STD|Mar:2013,900/STD|Dec:2012,800/STD|Mar:2012,750/STD|
我们需要输出的XML结构应该是:
<Periods> <Period year="2013"> <Months month="Apr" value="1200/STD"/> <Months month="Mar" value="900/STD"/> </Period> <Period year="2012"> <Months month="Dec" value="800/STD"/> <Months month="Mar" value="750/STD"/> </Period> </Periods>
问题根源:未正确分组
你之前的实现出现重复节点,大概率是因为每次处理单个月份条目时都生成了<Period>节点,而没有先按年份去重,再将同一年的月份归到同一个<Period>下。
解决方案:Muenchian分组+字符串拆分
下面是完整的XSLT 1.0代码,包含字符串拆分、分组逻辑,完全解决重复问题:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="xml" indent="yes"/> <!-- 定义Muenchian分组的键:按年份分组 --> <xsl:key name="year-group" match="entry" use="@year"/> <xsl:template match="/"> <Periods> <!-- 先拆分输入字符串为单个条目节点 --> <xsl:call-template name="split-entries"> <xsl:with-param name="input" select="'Apr:2013,1200/STD|Mar:2013,900/STD|Dec:2012,800/STD|Mar:2012,750/STD|'"/> </xsl:call-template> <!-- 处理分组:获取所有唯一的年份 --> <xsl:for-each select="entry[generate-id() = generate-id(key('year-group', @year)[1])]"> <!-- 按年份排序(可选,让输出更规整) --> <xsl:sort select="@year" order="descending"/> <Period year="{@year}"> <!-- 遍历当前年份下的所有条目 --> <xsl:for-each select="key('year-group', @year)"> <!-- 按月份排序(可选) --> <xsl:sort select="translate(@month, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', '0123456789ABCDEFGHIJKLMNOPQRSTUV')"/> <Months month="{@month}" value="{@value}"/> </xsl:for-each> </Period> </xsl:for-each> </Periods> </xsl:template> <!-- 递归模板:拆分|分隔的条目 --> <xsl:template name="split-entries"> <xsl:param name="input"/> <xsl:if test="$input != ''"> <!-- 获取第一个|之前的条目 --> <xsl:variable name="entry" select="substring-before($input, '|')"/> <xsl:if test="$entry != ''"> <!-- 拆分条目为月份年份和值 --> <xsl:call-template name="parse-entry"> <xsl:with-param name="entry" select="$entry"/> </xsl:call-template> </xsl:if> <!-- 递归处理剩余部分 --> <xsl:call-template name="split-entries"> <xsl:with-param name="input" select="substring-after($input, '|')"/> </xsl:call-template> </xsl:if> </xsl:template> <!-- 解析单个条目:拆分月份年份和值 --> <xsl:template name="parse-entry"> <xsl:param name="entry"/> <xsl:variable name="month-year" select="substring-before($entry, ',')"/> <xsl:variable name="value" select="substring-after($entry, ',')"/> <entry month="{substring-before($month-year, ':')}" year="{substring-after($month-year, ':')}" value="{$value}"/> </xsl:template> </xsl:stylesheet>
代码解释
- Muenchian分组键:
key('year-group', @year)用来将所有同一年的entry节点归为一组,通过generate-id()判断是否是组内第一个节点,从而实现去重。 - 字符串拆分:通过两个递归模板,先拆分
|分隔的条目,再拆分每个条目中的,分隔部分,提取月份、年份和值,生成临时的entry节点。 - 排序逻辑:可选的排序模板让年份从新到旧,月份按自然顺序排列,让输出结构更规整。
- 避免重复:先遍历唯一的年份,再为每个年份生成单个
<Period>,然后将该年份下的所有月份条目作为子节点,彻底解决重复问题。
输出结果
运行上述XSLT后,会生成开头展示的规整XML结构,完全没有重复的<Period>节点。
内容的提问来源于stack exchange,提问作者Nikhil Karande
相关产品推荐
相关产品推荐

