XSLT 3如何在Device节点后、Release节点前插入Production节点
问题根因
- 原有脚本的插入逻辑绑定了所有
config节点的通用匹配规则:只要识别到同设备前缀的第一个config节点,就先输出Production节点,再输出当前config本身。 - 输入中同前缀的第一个config是标记为
abstract="true"的Device基础节点,因此Production会被输出到Device节点之前,完全不符合插入位置要求。 - 原逻辑使用全局路径
//configs/config做判断,多设备场景下容易出现匹配串扰,也没有锚定真正的插入位置参考点。
修正方案
核心调整逻辑:
- 移除通用config模板中前置插入Production节点的逻辑,所有非Release节点默认走恒等复制规则,完全保留原有位置、格式、内容。
- 以
*_release后缀的config节点作为精准插入锚点:处理Release节点前,先判断同设备前缀的Production节点是否存在,不存在则先输出Production节点,再输出Release节点本身——天然实现「Device节点之后、Release节点之前」的位置要求。 - 简化节点生成逻辑,适配多设备块场景,自动跳过已存在Production节点的设备,避免重复生成。
修正后完整XSLT 3代码
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="3.0"> <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="no" /> <!-- 恒等模板:复制所有原有节点、属性、注释,保留原格式 --> <xsl:template match="@*|node()"> <xsl:copy> <xsl:apply-templates select="@*|node()" /> </xsl:copy> </xsl:template> <!-- 锚定Release节点作为插入位置参考 --> <xsl:template match="config[ends-with(@name, '_release')]"> <xsl:variable name="namePrefix" select="substring-before(@name, '_release')"/> <xsl:variable name="productionName" select="concat($namePrefix, '_production')"/> <!-- 不存在对应Production节点时才生成 --> <xsl:if test="not(preceding-sibling::config[@name=$productionName] | following-sibling::config[@name=$productionName])"> <config name="{$productionName}" extension="{$namePrefix}" version="" stage="PRODUCTION"> <title><xsl:value-of select="concat($namePrefix, ' (Production)')"/></title> </config> </xsl:if> <!-- 正常复制当前Release节点 --> <xsl:copy> <xsl:apply-templates select="@*|node()"/> </xsl:copy> </xsl:template> </xsl:stylesheet>
效果说明
- 原有Device节点、Test节点、注释、其他自定义配置的位置、内容、格式完全保留,不会被改动。
- 生成的Production节点内容与需求完全一致,位置固定在对应设备的Device节点之后、Release节点之前。
- 自动适配后续新增的同结构设备块,无需手动修改脚本枚举设备名。
- 自动去重,若输入XML中已经存在对应Production节点,不会重复生成。
内容的提问来源于stack exchange,提问作者Nox
相关产品推荐
相关产品推荐

