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

如何在XSLT中创建组合节点列表(无需for-each循环)

XSLT处理XML时补充缺失的process节点

输入XML

<all>
    <list1>
        <name>x</name>
        <name>y</name>
    </list1>
    <list2>
        <process>
            <value>1</value>
            <value>2</value>
        </process>
        <process>
            <value>1</value>
            <value>2</value>
            <value>3</value>
        </process>
        <process>
            <value>1</value>
        </process>
    </list2>
</all>

预期输出

<list3>
    <object>
        <process>
            <name>x</name>
            <value>1</value>
        </process>
        <process>
            <name>y</name>
            <value>2</value>
        </process>
    </object>
    
    <object>
        <process>
            <name>x</name>
            <value>1</value>
        </process>
        <process>
            <name>y</name>
            <value>2</value>
        </process>
        <process>
            <value>3</value>
        </process>
    </object>
    
    <object>
        <process>
            <name>x</name>
            <value>1</value>
        </process>
        <process>
            <value>2</value>
        </process>
        <process>
            <value>3</value>
        </process>
    </object>
    
</list3>

当前使用的XSLT代码

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xalan="xml.apache.org/xalan">
    <xsl:output method="xml" indent="yes" xalan:indent-amount="4"/>
    <xsl:strip-space elements="*"/>
    <!--Identity Trasnform -->
    <xsl:template match="node()|@*">
        <xsl:copy>
            <xsl:apply-templates select="node() |@*"/>
        </xsl:copy>
    </xsl:template>
    
    <xsl:template match="all">
        <list3>
            <xsl:apply-templates select="/all/list2/process"/>
        </list3>
    </xsl:template>
    
    <xsl:template match="process">
        <object>
            <xsl:apply-templates select="*"/>
        </object>
    </xsl:template>
    
    <xsl:template match="value">
        <xsl:variable name="pos" select="position()"/>
        <process>
            <xsl:if test="//list1/name[$pos]">
                <name><xsl:value-of select="//list1/name[$pos]"/></name>
            </xsl:if>
            <value><xsl:value-of select="."/></value>
        </process>
    </xsl:template>
</xsl:stylesheet>

实际输出

<list3>
    <object>
        <process>
            <name>x</name>
            <value>1</value>
        </process>
        <process>
            <name>y</name>
            <value>2</value>
        </process>
    </object>
    <object>
        <process>
            <name>x</name>
            <value>1</value>
        </process>
        <process>
            <name>y</name>
            <value>2</value>
        </process>
        <process>
            <value>3</value>
        </process>
    </object>
    <object>
        <process>
            <name>x</name>
            <value>1</value>
        </process>
    </object>
</list3>

问题分析

当前XSLT仅遍历process下已有的value节点生成process元素,当value数量少于list1/name的数量,或需要生成的process数量超过原value数量时,无法自动补充对应位置的节点,导致输出不符合预期。

修正后的XSLT代码

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xalan="xml.apache.org/xalan">
    <xsl:output method="xml" indent="yes" xalan:indent-amount="4"/>
    <xsl:strip-space elements="*"/>
    
    <!-- 全局变量存储list1的name列表和所有process的最大value数量 -->
    <xsl:variable name="name-list" select="/all/list1/name"/>
    <xsl:variable name="max-value-num" select="max(/all/list2/process/count(value))"/>
    
    <!-- 替换根节点all为list3 -->
    <xsl:template match="all">
        <list3>
            <xsl:apply-templates select="list2/process"/>
        </list3>
    </xsl:template>
    
    <!-- 每个process生成一个object -->
    <xsl:template match="process">
        <object>
            <!-- 遍历1到最大value数量的序号,生成对应process元素 -->
            <xsl:apply-templates select="1 to $max-value-num">
                <xsl:with-param name="current-process" select="."/>
            </xsl:apply-templates>
        </object>
    </xsl:template>
    
    <!-- 处理每个序号,生成对应的process节点 -->
    <xsl:template match=".[. instance of xs:integer]">
        <xsl:param name="current-process"/>
        <xsl:variable name="index" select="."/>
        
        <process>
            <!-- 若当前序号在name列表范围内,添加name元素 -->
            <xsl:if test="$name-list[$index]">
                <name><xsl:value-of select="$name-list[$index]"/></name>
            </xsl:if>
            <!-- 优先使用原process中对应位置的value,无则用序号填充 -->
            <value>
                <xsl:choose>
                    <xsl:when test="$current-process/value[$index]">
                        <xsl:value-of select="$current-process/value[$index]"/>
                    </xsl:when>
                    <xsl:otherwise>
                        <xsl:value-of select="$index"/>
                    </xsl:otherwise>
                </xsl:choose>
            </value>
        </process>
    </xsl:template>
    
    <!-- 禁用默认身份转换,避免处理无关节点 -->
    <xsl:template match="node()|@*"/>
</xsl:stylesheet>

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 20:15:53