Madhu CM
Madhu CM

Reputation: 2556

replacing text in xml using xslt

I have an XML file which has some values in child Element aswell in attributes. If i want to replace some text when specific value is matched how can i achieve it? I tried using xlst:translate() function. But i cant use this function for each element or attribute in xml. So is there anyway to replace/translate value at one shot?

<?xml version="1.0" encoding="UTF-8"?>
<Employee>
 <Name>Emp1</Name>
 <Age>40</Age>
 <sex>M</sex>
 <Address>Canada</Address> 
 <PersonalInformation>
   <Country>Canada</country>
   <Street1>KO 92</Street1>   
 </PersonalInformation>
</Employee>

Output :

<?xml version="1.0" encoding="UTF-8"?>
<Employee>
 <Name>Emp1</Name>
 <Age>40</Age>
 <sex>M</sex>
 <Address>UnitedStates</Address> 
 <PersonalInformation>
   <Country>UnitedStates</country>
   <Street1>KO 92</Street1>   
 </PersonalInformation>
</Employee>

in the output, replaced text from Canada to UnitedStates. so, without using xslt:transform() functions on any element , i should be able to replace text Canada to UnitedStates irrespective of level nodes. Where ever i find 'Canada' i should be able to replace to 'UnitedStates' in entire xml. So how can i achieve this.?

Upvotes: 1

Views: 5011

Answers (1)

Dimitre Novatchev
Dimitre Novatchev

Reputation: 243569

I. XSLT 1.0 solution:

This transformation:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:my="my:my" >
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>
 <my:Reps>
  <rep>
    <old>replace this</old>
    <new>replaced</new>
  </rep>
  <rep>
    <old>cat</old>
    <new>tiger</new>
  </rep>
 </my:Reps>

 <xsl:variable name="vReps" select=
  "document('')/*/my:Reps/*"/>

 <xsl:template match="node()|@*" name="identity">
  <xsl:copy>
   <xsl:apply-templates select="node()|@*"/>
  </xsl:copy>
 </xsl:template>

 <xsl:template match="@*">
  <xsl:attribute name="{name()}">
   <xsl:call-template name="replace">
    <xsl:with-param name="pText" select="."/>
   </xsl:call-template>
  </xsl:attribute>
 </xsl:template>

 <xsl:template match="text()" name="replace">
  <xsl:param name="pText" select="."/>
   <xsl:if test="string-length($pText)">
     <xsl:choose>
       <xsl:when test=
        "not($vReps/old[contains($pText, .)])">
         <xsl:copy-of select="$pText"/>
       </xsl:when>
       <xsl:otherwise>
         <xsl:variable name="vthisRep" select=
         "$vReps/old[contains($pText, .)][1]
         "/>

         <xsl:variable name="vNewText">
           <xsl:value-of
            select="substring-before($pText, $vthisRep)"/>
           <xsl:value-of select="$vthisRep/../new"/>
           <xsl:value-of select=
            "substring-after($pText, $vthisRep)"/>
         </xsl:variable>

         <xsl:call-template name="replace">
           <xsl:with-param name="pText"
            select="$vNewText"/>
         </xsl:call-template>
       </xsl:otherwise>
     </xsl:choose>
   </xsl:if>
 </xsl:template>
</xsl:stylesheet>

when applied on this XML document:

<t>
 <a attr1="X replace this Y">
   <b>cat mouse replace this cat dog</b>
 </a>
 <c/>
</t>

produces the wanted, correct result:

<t>
   <a attr1="X replaced Y">
      <b>tiger mouse replaced tiger dog</b>
   </a>
   <c/>
</t>

Explanation:

  1. The identity rule is used to copy "as-is" some nodes.

  2. We perform multiple replacements, parameterized in my:Reps

  3. If a text node or an attribute doesn't contain any rep-target, it is copied as-is.

  4. If a text node or an attribute contains text to be replaced (rep target), then the replacements are done in the order specified in my:Reps

  5. If the string contains more than one string target, then all targets are replaced: first all occurences of the first rep target, then all occurences of the second rep target, ..., last all occurences of the last rep target.

II. XSLT 2.0 solution:

In XSLT 2.0 one can simply use the standard XPath 2.0 function replace(). However, for multiple replacements the solution would be still very similar to the XSLT 1.0 solution specified above.

Upvotes: 4

Related Questions