XSLT 3.0实现按occurrences值复制XML记录并添加自增ID
XSLT 3.0 实现按指定次数复制记录并生成连续自增ID
直接用XSLT 3.0的序列映射特性就能实现,不需要递归或者复杂的计数逻辑,完整代码如下:
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="3.0" xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="xs"> <xsl:template match="breakfast_menu"> <xsl:copy> <xsl:for-each select="food ! ( let $current-food := ., $repeat-times := xs:integer($current-food/occurrences) return for $i in 1 to $repeat-times return $current-food )"> <xsl:copy> <!-- 插入连续自增ID --> <id><xsl:value-of select="position()"/></id> <!-- 复制原记录全部子节点 --> <xsl:copy-of select="child::node()"/> </xsl:copy> </xsl:for-each> </xsl:copy> </xsl:template> </xsl:stylesheet>
关键实现说明
- 复制逻辑:用XSLT 3.0的映射运算符
!遍历每个food节点,读取occurrences转为整数后,生成对应长度的节点序列——occurrences值是几,序列里就包含几个当前food节点,自动完成复制,不需要手写递归循环。 - 自增ID:
xsl:for-each遍历的是所有复制完成后的完整节点序列,直接调用内置函数position()就能拿到从1开始的连续序号,不需要额外维护计数变量,也能保证ID不会断号。 - 兼容性:这段代码直接复制原节点下的所有子元素,后续原XML结构新增字段时不需要修改XSLT逻辑,自动适配。
如果偏好更精简的写法,也可以把循环部分简化成:
<xsl:for-each select="food ! (xs:integer(occurrences) => (1 to .) ! ../)">运行效果完全一致,只是可读性稍差。
用提供的示例XML运行这段代码,输出结果和预期结果完全匹配:occurrences为1的 Belgian Waffles 仅输出1次,occurrences为2的Strawberry Belgian Waffles输出2次,ID从1到3连续递增。
内容的提问来源于stack exchange,提问作者cadet
相关产品推荐
相关产品推荐

