Reputation: 797
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
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
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
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