You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用XSLT for-each循环处理数量可变的多实体XML转换?

没问题,这个动态分组的XML转换需求完全可以用XSLT搞定!我给你两种方案,分别适配不同版本的XSLT环境,都能完美处理SubData节点数量不固定的场景。

方案一:XSLT 1.0 兼容版(Muenchian分组)

这个方案用经典的Muenchian分组技巧,几乎所有XSLT处理器都支持:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <!-- 定义分组键:提取节点名末尾的数字作为分组依据 -->
    <xsl:key name="group-by-number" 
             match="*[starts-with(local-name(), 'Name') or starts-with(local-name(), 'Weight') or starts-with(local-name(), 'Size')]" 
             use="substring-after(local-name(), translate(local-name(), '0123456789', ''))"/>

    <!-- 匹配根xml节点 -->
    <xsl:template match="/xml">
        <xml>
            <!-- 原样保留所有Header开头的节点 -->
            <xsl:copy-of select="*[starts-with(local-name(), 'Header')]"/>
            
            <!-- 遍历所有唯一的数字分组(以Name节点为锚点) -->
            <xsl:for-each select="*[starts-with(local-name(), 'Name')][count(. | key('group-by-number', substring-after(local-name(), 'Name'))[1]) = 1]">
                <!-- 提取当前分组的数字后缀 -->
                <xsl:variable name="num" select="substring-after(local-name(), 'Name')"/>
                <!-- 动态生成SubDataN节点 -->
                <xsl:element name="SubData{$num}">
                    <!-- 重命名并复制Name节点内容 -->
                    <Name><xsl:value-of select="."/></Name>
                    <!-- 匹配对应数字的Weight节点并重命名 -->
                    <Weight><xsl:value-of select="../*[local-name() = concat('Weight', $num)]"/></Weight>
                    <!-- 匹配对应数字的Size节点并重命名 -->
                    <Size><xsl:value-of select="../*[local-name() = concat('Size', $num)]"/></Size>
                </xsl:element>
            </xsl:for-each>
        </xml>
    </xsl:template>
</xsl:stylesheet>

核心逻辑说明:

  • 分组规则:通过<xsl:key>提取节点名里的数字部分(比如Name1里的1),把同数字的NameN/WeightN/SizeN分到一组。
  • 动态节点名:用<xsl:element name="SubData{$num}"/>自动生成SubData1、SubData2这类节点,不管数字是多少都能适配。
  • 通配符匹配:用starts-with()和concat()组合,不用硬编码数字,完美支持数量不固定的SubData节点。

方案二:XSLT 2.0+ 简洁版(正则分组)

如果你的环境支持XSLT 2.0及以上(比如Saxon处理器),可以用正则表达式简化代码:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="/xml">
        <xml>
            <!-- 保留所有Header节点 -->
            <xsl:copy-of select="*[starts-with(local-name(), 'Header')]"/>
            
            <!-- 按节点名的数字后缀分组 -->
            <xsl:for-each-group select="*[matches(local-name(), '^(Name|Weight|Size)\d+$')]" 
                                group-by="replace(local-name(), '^(Name|Weight|Size)(\d+)$', '$2')">
                <!-- 生成对应SubData节点 -->
                <xsl:element name="SubData{current-grouping-key()}">
                    <Name><xsl:value-of select="current-group()[local-name() = concat('Name', current-grouping-key())]"/></Name>
                    <Weight><xsl:value-of select="current-group()[local-name() = concat('Weight', current-grouping-key())]"/></Weight>
                    <Size><xsl:value-of select="current-group()[local-name() = concat('Size', current-grouping-key())]"/></Size>
                </xsl:element>
            </xsl:for-each-group>
        </xml>
    </xsl:template>
</xsl:stylesheet>

核心逻辑说明:

  • 正则匹配:用matches()筛选出带数字后缀的目标节点,replace()直接提取数字作为分组键。
  • 分组简化:for-each-group直接按数字分组,代码更简洁易读。

这两种方案都能自动适配任意数量的SubData节点,不用修改代码就能处理新增的Name4/Weight4/Size4这类节点。

内容的提问来源于stack exchange,提问作者bluefox

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.29 04:27:50