如何基于@rid属性值为@id属性设置正确的序号值
XSLT实现:基于规则修正
<a>元素的@id属性 需求规则
- 当父节点下的
<a>元素数量>1,且**<au>节点下的<cu>元素数量=1**时,需为<a>的@id属性值添加序号(如原id="a"依次改为id="a1"、id="a2")。 - 仅允许通过匹配
<a>元素的XSLT模板完成修改。
输入示例
<root> <t>Title</t> <au> <cu> <x rid="a1 a2"/> </cu> </au> <a id="a">Centre</a> <a id="a">Westmead</a> <n>notes</n> </root>
现有XSLT代码问题
现有模板存在以下缺陷:
- 仅处理符合条件的
<a>元素,不符合条件的会被直接丢弃; xsl:for-each-group选择范围错误,无法遍历所有同级<a>元素实现序号递增;- 硬编码
id前缀为a,未复用原@id的真实值。
<xsl:template match="@*|node()"> <xsl:copy> <xsl:apply-templates select="@*|node()"/> </xsl:copy> </xsl:template> <xsl:template match="a"> <xsl:if test="count(../a) > 1 and count(../au/cu[x]) = 1 and @id"> <xsl:for-each-group select="self::node()" group-adjacent="self::a"> <xsl:variable name="pos" select="position()"/> <xsl:element name="a"> <xsl:attribute name="id"> <xsl:value-of select="concat('a',$pos)"/> </xsl:attribute> <xsl:apply-templates/> </xsl:element> <!--</xsl:for-each>--> </xsl:for-each-group> </xsl:if> </xsl:template>
修正后的XSLT代码
<xsl:template match="@*|node()"> <xsl:copy> <xsl:apply-templates select="@*|node()"/> </xsl:copy> </xsl:template> <xsl:template match="a"> <xsl:copy> <xsl:choose> <!-- 匹配规则条件:同级a数量>1 + au下cu数量=1 + 存在id属性 --> <xsl:when test="count(../a) > 1 and count(../au/cu) = 1 and @id"> <xsl:variable name="current-pos" select="position()"/> <xsl:attribute name="id"> <xsl:value-of select="concat(@id, $current-pos)"/> </xsl:attribute> <xsl:apply-templates/> </xsl:when> <!-- 不符合规则时,保留原属性与内容 --> <xsl:otherwise> <xsl:apply-templates select="@*|node()"/> </xsl:otherwise> </xsl:choose> </xsl:copy> </xsl:template>
代码说明
- 保留默认身份模板,确保所有未匹配的节点、属性原样复制;
- 针对
<a>元素的模板优化:- 用
xsl:copy保留原元素结构,避免元素丢失; - 通过
xsl:choose分支处理两种场景,保证兼容性; - 符合规则时,通过
position()获取当前<a>在同级中的位置,拼接原@id生成新属性值; - 不符合规则时直接复用原属性与内容,不做额外修改。
- 用
期望输出
<root> <t>Title</t> <au> <cu> <x rid="a1 a2"/> </cu> </au> <a id="a1">Centre</a> <a id="a2">Westmead</a> <n>notes</n> </root>
内容的提问来源于stack exchange,提问作者Sam
相关产品推荐
相关产品推荐

