1

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

4
  • Could you please specify what you're trying to achive. If you give us some sample code with input and desired output this would be easier to answer. Also, is it possible for you to use XSLT 2.0? In that case might be able to use fn:replace() Commented Dec 14, 2010 at 7:40
  • Excellent question, +1. See my answer for a complete XSLT 1.0 solution that accepts multiple rep-targets in a parameter and performs multiple replacements in any attribute or text node. Also, the difference using an XSLT 2.0 solution is specified. Commented Dec 14, 2010 at 7:59
  • @Per T , thank you , i am using XSLT 1.0 . The output is pretty straight forward , For any input XML , i Need to replace text without specifying element name. So that it should apply replacement for all child elements only if Text is matched. Commented Dec 14, 2010 at 8:24
  • @Per T, 've edited question with example. thanks Commented Dec 14, 2010 at 8:35

1 Answer 1

4

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.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.