XSLT如何通过for-each循环修改节点值并完成XML节点编号
XSLT节点编号问题解决方案
方案可行性说明
xsl:for-each完全可以实现该需求,你出现多值重复的问题,核心原因是没有正确绑定循环上下文,取值时误匹配了所有ID/dummy节点而非当前循环内的对应节点。
实现代码
1. xsl:for-each实现
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="xml" indent="yes"/> <!-- 通用复制模板,原样保留不需要修改的节点 --> <xsl:template match="@* | node()"> <xsl:copy> <xsl:apply-templates select="@* | node()"/> </xsl:copy> </xsl:template> <xsl:template match="/"> <!-- 遍历所有body节点,position()获取当前遍历的序号 --> <xsl:for-each select="*[local-name()='root']/body"> <xsl:copy> <ID> <xsl:value-of select="position()"/> </ID> <xsl:apply-templates select="foo | foo2"/> <sample> <dummy> <xsl:value-of select="position()"/> </dummy> <xsl:apply-templates select="sample/dummy2"/> </sample> </xsl:copy> </xsl:for-each> </xsl:template> </xsl:stylesheet>
注意:请将代码中
*[local-name()='root']替换为你实际XML中body节点的父节点路径。
2. 更优方案:模板匹配实现
该方案更符合XSLT声明式语法的设计思想,扩展性更强,后续需要修改其他节点规则时不需要调整已有逻辑:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="xml" indent="yes"/> <!-- 通用复制模板 --> <xsl:template match="@* | node()"> <xsl:copy> <xsl:apply-templates select="@* | node()"/> </xsl:copy> </xsl:template> <!-- 重写body节点下ID的取值逻辑 --> <xsl:template match="body/ID"> <xsl:copy> <xsl:value-of select="count(../preceding-sibling::body) + 1"/> </xsl:copy> </xsl:template> <!-- 重写dummy节点的取值逻辑 --> <xsl:template match="body/sample/dummy"> <xsl:copy> <xsl:value-of select="count(../../../preceding-sibling::body) + 1"/> </xsl:copy> </xsl:template> </xsl:stylesheet>
方案对比
- for-each方案逻辑直观,适合临时处理、后续不需要扩展节点规则的场景
- 模板匹配方案维护成本更低,适合业务逻辑复杂、后续可能新增节点修改规则的场景
内容的提问来源于stack exchange,提问作者David
相关产品推荐
相关产品推荐

