如何使用XSLT 2.0按条件修改指定XML字段的值
解决XSLT 2.0修改特定XML字段的问题
需求很明确:遍历XML中所有/message/object/struct/substruct2/ss2field2字段,只要字段值以字符"i"结尾,就在值前面加一个"0"。
源XML如下:
<message> <object> <meta> <field>text</field> </meta> <struct> <sfield1>text</sfield1> <sfield2>text</sfield2> <substruct1> <ss1field>text</ss1field> </substruct1> <substruct2> <ss2field1>text</ss2field1> <ss2field2>0001</ss2field2> </substruct2> <substruct2> <ss2field1>text</ss2field1> <ss2field2>002i</ss2field2> </substruct2> <substruct2> <ss2field1>text</ss2field1> <ss2field2>0003</ss2field2> </substruct2> </struct> </object> <object> <meta> <field>text</field> </meta> <struct> <sfield1>text</sfield1> <sfield2>text</sfield2> <substruct1> <ss1field>text</ss1field> </substruct1> <substruct2> <ss2field1>text</ss2field1> <ss2field2>004i</ss2field2> </substruct2> <substruct2> <ss2field1>text</ss2field1> <ss2field2>0005</ss2field2> </substruct2> </struct> </object> </message>
你写的XSLT代码报错了,错误信息是:
A sequence of more than one item is not allowed as the second argument of contains() ("0001", "002i", ...)
错误原因
你把问题复杂化了:
- 定义的
$condition变量把所有ss2field2的处理结果拼接成了一串文本,根本没法对应单个字段 - 调用模板时把所有
//substruct2/ss2field2节点序列传给param.target,而contains()的第二个参数只能是单个字符串,不能是节点序列,这直接触发了报错 - 整个自定义模板
value-to-replace完全没必要,完全可以直接在匹配节点的模板里处理逻辑
正确的XSLT写法
用XSLT的身份模板复制所有节点,然后专门匹配需要修改的ss2field2节点,直接判断处理即可:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0"> <xsl:output method="xml" omit-xml-declaration="yes" indent="yes"/> <!-- 身份模板:复制所有节点和属性 --> <xsl:template match="@*|node()"> <xsl:copy> <xsl:apply-templates select="@*|node()"/> </xsl:copy> </xsl:template> <!-- 匹配目标字段,处理逻辑 --> <xsl:template match="message/object/struct/substruct2/ss2field2"> <xsl:copy> <xsl:choose> <xsl:when test="ends-with(., 'i')"> <xsl:value-of select="concat('0', .)"/> </xsl:when> <xsl:otherwise> <xsl:value-of select="."/> </xsl:otherwise> </xsl:choose> </xsl:copy> </xsl:template> </xsl:stylesheet>
转换后的结果XML
<message> <object> <meta> <field>text</field> </meta> <struct> <sfield1>text</sfield1> <sfield2>text</sfield2> <substruct1> <ss1field>text</ss1field> </substruct1> <substruct2> <ss2field1>text</ss2field1> <ss2field2>0001</ss2field2> </substruct2> <substruct2> <ss2field1>text</ss2field1> <ss2field2>0002i</ss2field2> </substruct2> <substruct2> <ss2field1>text</ss2field1> <ss2field2>0003</ss2field2> </substruct2> </struct> </object> <object> <meta> <field>text</field> </meta> <struct> <sfield1>text</sfield1> <sfield2>text</sfield2> <substruct1> <ss1field>text</ss1field> </substruct1> <substruct2> <ss2field1>text</ss2field1> <ss2field2>0004i</ss2field2> </substruct2> <substruct2> <ss2field1>text</ss2field1> <ss2field2>0005</ss2field2> </substruct2> </struct> </object> </message>
内容的提问来源于stack exchange,提问作者juankinspain
相关产品推荐
相关产品推荐

