uncaged
uncaged

Reputation: 797

Simple XSLT Text Replacement

I'm looking for a simpler, more elegant way to replace text in XML. For a source XML like:

<A>
 <B>
  <Name>ThisOne</Name>
  <Target>abc</Target>
 </B>
 <B>
  <Name>NotThisOne</Name>
  <Target>abc</Target>
 </B>
 <B>
  <Name>ThisOne</Name>
  <Target>def</Target>
 </B>
</A>

I want to change the text of all Target elements that have the Name of "ThisOne" to "xyz".

The result would be:

<A>
 <B>
  <Name>ThisOne</Name>
  <Target>xyz</Target>     <--   Changed.
 </B>
 <B>
  <Name>NotThisOne</Name>
  <Target>abc</Target>
 </B>
 <B>
  <Name>ThisOne</Name>
  <Target>xyz</Target>     <--   Changed.
 </B>
</A>

I accomplished this with:

<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:template match="B/Target">
    <xsl:choose>
      <xsl:when test="../Name/text()='ThisOne'"><Target>xyz</Target></xsl:when>
      <xsl:otherwise><Target><xsl:value-of select="text()"/></Target></xsl:otherwise>
    </xsl:choose>
  </xsl:template>
</xsl:stylesheet>

I was thinking this could be done with <xsl:template match="B/Target/text()">, so I could just replace the text and not the whole element, but I couldn't figure out the rest.

Thanks in advance.

Upvotes: 2

Views: 840

Answers (3)

Kevan
Kevan

Reputation: 891

<?xml version="1.0" encoding="iso-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:cds="cds_dt" exclude-result-prefixes="cds">
    <!-- Identity transfrom - just copy what doesn't need changing -->
    <xsl:template match="@* | node()">
        <xsl:copy>
            <xsl:apply-templates select="@* | node()"/>
        </xsl:copy>
    </xsl:template>

    <!-- a rule for what does need changing -->
    <!-- Change all Target nodes whose parent has a child of Name equal to ThisOne -->
    <xsl:template match="/A/B[Name='ThisOne']/Target">
        <Target>xyz</Target>
    </xsl:template>
</xsl:stylesheet>

Upvotes: 1

Jim Garrison
Jim Garrison

Reputation: 86754

This is all you have to do:

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

 <xsl:template match="B/Target[../Name='ThisOne']">
  <xsl:copy>
    <xsl:apply-templates select="@*"/>
    <xsl:text>xyz</xsl:text>
  </xsl:copy>
 </xsl:template>

The first template is the "identity transform" and copies input to output unchanged. The second matches the specific targets you want to change, copies the tag and attributes, and substitutes the desired text.

Upvotes: 1

Daniel Haley
Daniel Haley

Reputation: 52858

This stylesheet:

<xsl:stylesheet version="1.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="B[Name='ThisOne']/Target/text()">
    <xsl:text>xyz</xsl:text>
  </xsl:template>

</xsl:stylesheet>

using your XML input produces:

<A>
  <B>
    <Name>ThisOne</Name>
    <Target>xyz</Target>
  </B>
  <B>
    <Name>NotThisOne</Name>
    <Target>abc</Target>
  </B>
  <B>
    <Name>ThisOne</Name>
    <Target>xyz</Target>
  </B>
</A>

Upvotes: 5

Related Questions