I'm trying to change the value of an specific XML field using XSLT 2.0 if the value ends with "i". The change consists of adding a "0" (zero) before the value.
XML field of interst would be '/message/object/struct/substruct2/ss2field2'. Change should occur for every 'ssfield2' ending with "i", in every 'object'.
The source XML is as follows:
<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>
Based in this other post: Xslt change element value based on when condition rule with reference to another element
I tried to build my own stylesheet:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output method="xml" omit-xml-declaration="yes"/>
<xsl:variable name="condition">
<xsl:for-each select="//substruct2">
<xsl:choose>
<xsl:when test="ends-with(ss2field2,'i')">
<xsl:value-of select="concat('0',ss2field2)"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="ss2field2"/>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</xsl:variable>
<xsl:template name="value-to-replace">
<xsl:param name="param.str"/>
<xsl:param name="param.target"/>
<xsl:param name="param.replacement"/>
<xsl:choose>
<xsl:when test="contains($param.str, $param.target)">
<xsl:value-of select="concat(substring-before($param.str, $param.target), $param.replacement, substring-after($param.str, $param.target))"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$param.str"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="ss2field2[parent::substruct2]">
<xsl:element name="{name()}">
<xsl:call-template name="value-to-replace">
<xsl:with-param name="param.str" select="."/>
<xsl:with-param name="param.target" select="//substruct2/ss2field2"/>
<xsl:with-param name="param.replacement" select="$condition"/>
</xsl:call-template>
</xsl:element>
</xsl:template>
<!--copy all nodes-->
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
But it does not work, I'm getting the following error:
A sequence of more than one item is not allowed as the second argument of contains() ("0001", "002i", ...)
Any help would be very much appreciated.
Nevermind, I was over complicating the solution, the following XSLT did the trick:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes" method="xml" omit-xml-declaration="yes"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="//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>
I have now another problem but I will save it for another question.