如何使用XSLT 3.0在递归循环中实现XML数值查找功能
解决方案
报错原因
xsl:template must be at top level报错是因为XSLT语法要求所有<xsl:template>节点必须作为<xsl:stylesheet>的直接子节点,不能嵌套在其他模板内部,你之前想在模板内部加递归逻辑的写法不符合语法规范。
实现思路
- 保留现有构建numMap的逻辑,把所有wd:num的值提前存入哈希表提高查找效率
- 在顶层单独声明一个递归模板,接收两个入参:当前要查找的数值
$currentNum、已经构建好的数值映射表$numMap - 递归逻辑:
- 若当前数值不存在于
$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
相关产品推荐
相关产品推荐

