Search code examples
xslt-2.0

Find and replace for the particular texts within same text() node, more than once


Please suggest to find replace the required text within one text() node, some times find-replace text repeated more than once.

Here, scripts should exclue the element '<p>'. Working fine when 'find' text occuring only once in a text node, if it occures more than once, then skipping the replace process (see first <p1>). Please suggest.

XML:

<article>
<p1>The text 1111, 2222, 3333 and 4444 are some values, 1111 another occurance.</p1>
<p1>The text 1111, 2222, 3333 and 4444 are some values</p1>
<p>The text 1111, 2222, 3333 and 4444 are some values</p>
<p1>The text aaaaa, bbbbb, ccccc and ddddd are another set of values</p1>
<p1>The text <i>aaaaa</i>, <b>bbbbb</b>  and <c>ccccc</c> are in different form</p1>
</article>

XSLT 2.0:

<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>

<xsl:template match="*/text()">
    <xsl:call-template name="tempFindReplace">
        <xsl:with-param name="pText1" select="."/>
    </xsl:call-template>
</xsl:template>

<xsl:template name="tempFindReplace">
    <xsl:param name="pText1"/>
    <xsl:if test="string-length($pText1) > 0">
    <xsl:choose>
        <xsl:when test="ancestor::p1">
            <xsl:choose>
                <xsl:when test="contains($pText1, '1111')">
                    <xsl:value-of select="substring-before($pText1,'1111')"/><xsl:text>Alpha1</xsl:text>
                    <xsl:call-template name="tempFindReplace"><xsl:with-param name="pText1" select="substring-after($pText1, '1111')"/></xsl:call-template></xsl:when>
                <xsl:when test="contains($pText1, '2222')">
                    <xsl:value-of select="substring-before($pText1,'2222')"/><xsl:text>Alpha2</xsl:text>
                    <xsl:call-template name="tempFindReplace"><xsl:with-param name="pText1" select="substring-after($pText1, '2222')"/></xsl:call-template></xsl:when>
                <xsl:when test="contains($pText1, '3333')">
                    <xsl:value-of select="substring-before($pText1,'3333')"/><xsl:text>Alpha3</xsl:text>
                    <xsl:call-template name="tempFindReplace"><xsl:with-param name="pText1" select="substring-after($pText1, '3333')"/></xsl:call-template></xsl:when>
                <xsl:when test="contains($pText1, '4444')">
                    <xsl:value-of select="substring-before($pText1,'4444')"/><xsl:text>Alpha4</xsl:text>
                    <xsl:call-template name="tempFindReplace"><xsl:with-param name="pText1" select="substring-after($pText1, '4444')"/></xsl:call-template></xsl:when>

                <xsl:when test="contains($pText1, 'aaaaa')">
                    <xsl:value-of select="substring-before($pText1,'aaaaa')"/><xsl:text>Beta1</xsl:text>
                    <xsl:call-template name="tempFindReplace"><xsl:with-param name="pText1" select="substring-after($pText1, 'aaaaa')"/></xsl:call-template></xsl:when>
                <xsl:when test="contains($pText1, 'bbbbb')">
                    <xsl:value-of select="substring-before($pText1,'bbbbb')"/><xsl:text>Beta2</xsl:text>
                    <xsl:call-template name="tempFindReplace"><xsl:with-param name="pText1" select="substring-after($pText1, 'bbbbb')"/></xsl:call-template></xsl:when>
                <xsl:when test="contains($pText1, 'ccccc')">
                    <xsl:value-of select="substring-before($pText1,'ccccc')"/><xsl:text>Beta3</xsl:text>
                    <xsl:call-template name="tempFindReplace"><xsl:with-param name="pText1" select="substring-after($pText1, 'ccccc')"/></xsl:call-template></xsl:when>
                <xsl:when test="contains($pText1, 'ddddd')">
                    <xsl:value-of select="substring-before($pText1,'ddddd')"/><xsl:text>Beta4</xsl:text>
                    <xsl:call-template name="tempFindReplace"><xsl:with-param name="pText1" select="substring-after($pText1, 'ddddd')"/></xsl:call-template></xsl:when>
                <xsl:otherwise>
                    <xsl:value-of select="substring($pText1,1,1)"/>
                    <xsl:call-template name="tempFindReplace">
                        <xsl:with-param name="pText1" select="substring($pText1, 2)"/>
                    </xsl:call-template>
                </xsl:otherwise>
            </xsl:choose>
    </xsl:when>
    <xsl:otherwise>
        <xsl:value-of select="."/>
    </xsl:otherwise>
    </xsl:choose>
    </xsl:if> 
</xsl:template>
</xsl:stylesheet>

Required Result:

<article>
<p1>The text Alpha1, Alpha2, Alpha3 and Alpha4 are some values, Alpha1 another occurance.</p1><!-- Alpha1 only replacing, but other texts also required change, I assume here failing because of 1111 appearing twice-->
<p1>The text Alpha1, Alpha2, Alpha3 and Alpha4 are some values</p1>
<p>The text 1111, 2222, 3333 and 4444 are some values</p>
<p1>The text Beta1, Beta2, Beta3 and Beta4 are another set of values</p1>
<p1>The text <i>Beta1</i>, <b>Beta2</b>  and <c>Beta3</c> are in different form</p1>
</article>

Solution

  • XSLT 2:

    called template twice, and got the result.

    <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>
    
    <xsl:template match="*[ancestor-or-self::*[matches(name(), '^(p1|p2|p3)$')]]/text()">
        <xsl:variable name="var1">
        <xsl:call-template name="tempFindReplace">
            <xsl:with-param name="pText1" select="."/>
        </xsl:call-template>
        </xsl:variable>
        <xsl:call-template name="tempFindReplace">
            <xsl:with-param name="pText1" select="$var1"/>
        </xsl:call-template>
    </xsl:template>
    
    <xsl:template name="tempFindReplace">
        <xsl:param name="pText1"/>
        <xsl:if test="string-length($pText1) > 0">
                <xsl:choose>
                    <xsl:when test="contains($pText1, '1111')">
                        <xsl:value-of select="substring-before($pText1,'1111')"/><xsl:text>Alpha1</xsl:text>
                        <xsl:call-template name="tempFindReplace"><xsl:with-param name="pText1" select="substring-after($pText1, '1111')"/></xsl:call-template></xsl:when>
                    <xsl:when test="contains($pText1, '2222')">
                        <xsl:value-of select="substring-before($pText1,'2222')"/><xsl:text>Alpha2</xsl:text>
                        <xsl:call-template name="tempFindReplace"><xsl:with-param name="pText1" select="substring-after($pText1, '2222')"/></xsl:call-template></xsl:when>
                    <xsl:when test="contains($pText1, '3333')">
                        <xsl:value-of select="substring-before($pText1,'3333')"/><xsl:text>Alpha3</xsl:text>
                        <xsl:call-template name="tempFindReplace"><xsl:with-param name="pText1" select="substring-after($pText1, '3333')"/></xsl:call-template></xsl:when>
                    <xsl:when test="contains($pText1, '4444')">
                        <xsl:value-of select="substring-before($pText1,'4444')"/><xsl:text>Alpha4</xsl:text>
                        <xsl:call-template name="tempFindReplace"><xsl:with-param name="pText1" select="substring-after($pText1, '4444')"/></xsl:call-template></xsl:when>
    
                    <xsl:when test="contains($pText1, 'aaaaa')">
                        <xsl:value-of select="substring-before($pText1,'aaaaa')"/><xsl:text>Beta1</xsl:text>
                        <xsl:call-template name="tempFindReplace"><xsl:with-param name="pText1" select="substring-after($pText1, 'aaaaa')"/></xsl:call-template></xsl:when>
                    <xsl:when test="contains($pText1, 'bbbbb')">
                        <xsl:value-of select="substring-before($pText1,'bbbbb')"/><xsl:text>Beta2</xsl:text>
                        <xsl:call-template name="tempFindReplace"><xsl:with-param name="pText1" select="substring-after($pText1, 'bbbbb')"/></xsl:call-template></xsl:when>
                    <xsl:when test="contains($pText1, 'ccccc')">
                        <xsl:value-of select="substring-before($pText1,'ccccc')"/><xsl:text>Beta3</xsl:text>
                        <xsl:call-template name="tempFindReplace"><xsl:with-param name="pText1" select="substring-after($pText1, 'ccccc')"/></xsl:call-template></xsl:when>
                    <xsl:when test="contains($pText1, 'ddddd')">
                        <xsl:value-of select="substring-before($pText1,'ddddd')"/><xsl:text>Beta4</xsl:text>
                        <xsl:call-template name="tempFindReplace"><xsl:with-param name="pText1" select="substring-after($pText1, 'ddddd')"/></xsl:call-template></xsl:when>
                    <xsl:otherwise>
                        <xsl:value-of select="substring($pText1,1,1)"/>
                        <xsl:call-template name="tempFindReplace">
                            <xsl:with-param name="pText1" select="substring($pText1, 2)"/>
                        </xsl:call-template>
                    </xsl:otherwise>
                </xsl:choose>
        </xsl:if> 
    </xsl:template>
    </xsl:stylesheet>