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

如何使用XSLT 3.0在递归循环中实现XML数值查找功能

解决方案

报错原因

xsl:template must be at top level报错是因为XSLT语法要求所有<xsl:template>节点必须作为<xsl:stylesheet>的直接子节点,不能嵌套在其他模板内部,你之前想在模板内部加递归逻辑的写法不符合语法规范。

实现思路

  1. 保留现有构建numMap的逻辑,把所有wd:num的值提前存入哈希表提高查找效率
  2. 在顶层单独声明一个递归模板,接收两个入参:当前要查找的数值$currentNum、已经构建好的数值映射表$numMap
  3. 递归逻辑:
  • 若当前数值不存在于$numMap中,直接返回Not found: {当前数值}
  • 若存在,将数值减1后重新调用递归模板,直到匹配失败为止

完整修正代码

<?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"
    xmlns:wd="urn:com.workday/bsvc"
    xmlns:map="http://www.w3.org/2005/xpath-functions/map"
    exclude-result-prefixes="xs wd map"
    version="3.0">

    <!-- 顶层递归模板,不能写在其他模板内部 -->
    <xsl:template name="findMissingNum">
        <xsl:param name="currentNum" as="xs:integer"/>
        <xsl:param name="numMap" as="map(xs:integer,element(wd:Report_Entry))"/>
        <xsl:choose>
            <xsl:when test="map:contains($numMap, $currentNum)">
                <xsl:next-iteration>
                    <xsl:with-param name="currentNum" select="$currentNum - 1"/>
                    <xsl:with-param name="numMap" select="$numMap"/>
                </xsl:next-iteration>
            </xsl:when>
            <xsl:otherwise>
                <xsl:value-of select="concat('Not found: ', $currentNum)"/>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template>

    <xsl:template match="AggregatedData">
        <FinalData>
            <xsl:iterate select="*">
                <xsl:param name="numMap" as="map(xs:integer,element(wd:Report_Entry))" select="map{}"/>
                
                <xsl:choose>
                    <xsl:when test="self::wd:Report_Data">
                        <xsl:next-iteration>
                            <xsl:with-param name="numMap"
                                select="fold-left(
                                wd:Report_Entry/copy-of(),
                                map{},
                                function($map,$entry) {
                                let $key:=xs:integer($entry/wd:num) return
                                if ($key)
                                then map:put($map,$key,$entry)
                                else
                                $map})"
                            />  
                        </xsl:next-iteration>
                    </xsl:when>                  
                    
                    <xsl:when test="self::root">
                        <xsl:for-each select="row/copy-of()">
                            <rows>
                                <xsl:copy-of select="*"/>
                                <splitExistFlag>
                                    <!-- 初始调用递归模板,入参为my_num-1和构建好的numMap -->
                                    <xsl:call-template name="findMissingNum">
                                        <xsl:with-param name="currentNum" select="xs:integer(my_num) - 1"/>
                                        <xsl:with-param name="numMap" select="$numMap"/>
                                    </xsl:call-template>
                                </splitExistFlag>                                
                            </rows>
                        </xsl:for-each>
                    </xsl:when>
                </xsl:choose>
            </xsl:iterate>
        </FinalData>
    </xsl:template>

</xsl:stylesheet>

输出效果

针对提供的示例XML,my_num值为6时,输出的<splitExistFlag>节点内容为:Not found: 3,和预期结果一致。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.25 12:15:02