Re: [xsl] multiple replace

Subject: Re: [xsl] multiple replace
From: "Sam Byland" <shbyland@xxxxxxxxxxx>
Date: Tue, 12 Aug 2008 09:51:18 -0400
Jim,

I remember doing something similar with XSLT 1.0, and it should work fine under 2.0 too. I created a new mode and passed the string to perform the multiple replace as a parameter; then applied templates changing the context to the "database" of find/replace characters. The template for that new mode performed the replace for that "record", then applied templates on the following sibling passing the new string along... Something like this:

Say you use the following variable for the various characters:

<xsl:variable name="ReplaceDb">
           <ReplaceTable>
                       <replacements>
                                   <replace>&lt;&lt;</replace>
                                   <with>&ldquo;</with>
                       </replacements>
                       <replacements>
                                   <replace>&gt;&gt;</replace>
                                   <with>&rdquo;</with>
                       </replacements>
etc
</xsl:variable>

Then if the string to perform the multiple replacements on is $String, I used something like this:

<xsl:apply-templates select="$ReplaceDb/*/*[1]" mode="DbStringReplace">
<xsl:with-param name="InputString" select=" $String "/>
<xsl:with-param name="SearchCharacterName" select=" 'replace' "/>
<xsl:with-param name="ReplaceCharacterName" select=" 'with' "/>
</xsl:apply-templates>


The XSLT 1.0 template rule I had hanging around for the "DbSringReplace" mode is pasted below. Note that it also calls a "StringSubstitute" template, but you can just use the replace() function for that... Also note I haven't used or testing this thing in a while :-)

Hope that helps!

Cheers,

...sam


<xsl:template match="*" mode="DbStringReplace"> <xsl:param name="InputString"/> <xsl:param name="SearchCharacterName"/> <xsl:param name="ReplaceCharacterName"/>

<xsl:choose>
<!-- first confirm strings aren't empty -->
<xsl:when test="$InputString = '' or $SearchCharacterName = '' or $ReplaceCharacterName = ''">
<xsl:message>ERROR!!!</xsl:message>
</xsl:when>
<xsl:otherwise>


<xsl:variable name="SearchString" select="*[local-name()=$SearchCharacterName]"/>
<xsl:variable name="ReplaceString" select="*[local-name()=$ReplaceCharacterName]"/>


<xsl:variable name="UpdatedInputString">

<xsl:choose>

<xsl:when test="not(contains($InputString[1], $SearchString))">

<xsl:value-of select="$InputString"/>

</xsl:when>
<xsl:otherwise> <!-- output string before SearchString, then output ReplaceString, then check is more in remaining part of InputString -->


<xsl:value-of select="concat(substring-before($InputString,$SearchString),$ReplaceString)"/>

<xsl:variable name="RemString" select="substring-after($InputString,$SearchString)"/>

<xsl:choose>
<xsl:when test="contains($RemString, $SearchString)"> <!-- if so, call recursively to finish replacing -->


<xsl:call-template name="StringSubstitute">
<xsl:with-param name="InputString" select="$RemString"/>
<xsl:with-param name="SearchString" select="$SearchString"/>
<xsl:with-param name="ReplaceString" select="$ReplaceString"/>
</xsl:call-template>


</xsl:when>

<xsl:otherwise> <!-- output remainder of the string -->

<xsl:value-of select="substring-after($InputString,$SearchString)"/>

</xsl:otherwise>
</xsl:choose>


                                                           </xsl:otherwise>
                                               </xsl:choose>

</xsl:variable>

<xsl:choose>
<xsl:when test="following-sibling::*"> <!-- now process the next in line -->


<xsl:apply-templates select="following-sibling::*[1]" mode="DbStringReplace">
<xsl:with-param name="InputString" select="$UpdatedInputString"/>
<xsl:with-param name="SearchCharacterName" select="$SearchCharacterName"/>
<xsl:with-param name="ReplaceCharacterName" select="$ReplaceCharacterName"/>
</xsl:apply-templates>


</xsl:when>
<xsl:otherwise><xsl:value-of select="$UpdatedInputString"/></xsl:otherwise>
</xsl:choose>


                       </xsl:otherwise>
           </xsl:choose>

</xsl:template>

Current Thread