如何实现XSLT 2.0样式表:type属性为WILD时给指定标签追加字符w
解决XSLT 2.0中根据
<name>的type属性修改<Identity>文本的问题 需求说明
当XML文档中存在type="WILD"的<name>标签时,给<farm>和<Site>下的<Identity>标签文本末尾追加字符"w"。
输入XML
<root> <Header> <farm> <Identity>0123</Identity> </farm> <Site> <Identity>0123</Identity> </Site> </Header> <body> <animal> <name place="ocean" type="WILD"> <species>Tortoise</species> </name> </animal> </body> </root>
期望输出
<root> <Header> <farm> <Identity>0123w</Identity> </farm> <Site> <Identity>0123w</Identity> </Site> </Header> <body> <animal> <name place="ocean" type="WILD"> <species>Tortoise</species> </name> </animal> </body> </root>
错误的尝试及问题分析
我尝试了以下XSLT,但将type属性改为"XXX"时,结果仍错误地追加了"w":
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <!-- identity template --> <xsl:template match="@* | node()"> <xsl:copy> <xsl:apply-templates select="@* | node()"/> </xsl:copy> </xsl:template> <!-- add 'w' to Identity elements inside <farm> and <Site> --> <xsl:template match="farm/Identity | Site/Identity"> <xsl:copy> <xsl:value-of select="if (../name/@type='WILD') then . else concat(., 'w')"/> </xsl:copy> </xsl:template> <!-- add 'w' to Identity elements inside <name> with attribute 'type' = 'WILD' --> <xsl:template match="name[@type='WILD']/Identity"> <xsl:copy> <xsl:value-of select="concat(., 'w')"/> </xsl:copy> </xsl:template> </xsl:stylesheet>
问题根源
- 逻辑完全写反:第一个模板的条件
if (../name/@type='WILD') then . else concat(., 'w'),意思是"当<farm>/<Site>的同级存在type为WILD的<name>时,保持原文本;否则追加w",和需求完全相反。 - 路径错误:
../name是查找<farm>/<Site>的同级节点,但实际<name>在<body>/<animal>下,和<Header>下的<farm>/<Site>层级完全无关,这个条件永远不成立,导致一直执行else分支追加w。 - 无用模板:第三个模板匹配
name[@type='WILD']/Identity,但输入XML中<name>下根本没有<Identity>节点,这个模板不会触发。
正确的XSLT实现
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <!-- 身份模板:默认复制所有节点和属性 --> <xsl:template match="@* | node()"> <xsl:copy> <xsl:apply-templates select="@* | node()"/> </xsl:copy> </xsl:template> <!-- 全局检查是否存在type为WILD的name,存在则给farm/Site下的Identity追加w --> <xsl:template match="farm/Identity | Site/Identity"> <xsl:copy> <xsl:value-of select="if (//name[@type='WILD']) then concat(., 'w') else ."/> </xsl:copy> </xsl:template> </xsl:stylesheet>
实现说明
- 使用
//name[@type='WILD']全局查找文档中是否存在符合条件的<name>节点,确保判断逻辑准确。 - 修正条件逻辑:当存在目标
<name>时,给<Identity>追加"w";否则保持原文本。 - 移除无用的第三个模板,精简代码。
内容的提问来源于stack exchange,提问作者TulioVargas
相关产品推荐
相关产品推荐

