Reputation: 113
My sample xml :
<root>
<changeTag value="true"/>
<a_original> name ="foo"</a_original>
<b_original> name ="foo1"</b_original>
<changeTag value = "false"/>
<a_original> name ="foo1"</a_original>
<b_original> name ="foo1"</b_original>
</root>
I want a transformation in xslt which would convert the nodes which are after 'changeTag value = "true" ' but not after ' changeTag value = "false" '. I want all the nodes which are between changeValue value = " true " and changeValue value = " false " to be same as input xml and perform all the transformations after changeValue value = " false "
My sample XML output(Expected)
<root>
<changeTag value="true"/>
<a_original> name ="foo"</a_original>
<b_original> name ="foo1"</b_original>
<changeTag value = "false"/>
<a_changed> name ="foo1"</a_changed>
<b_changed> name ="foo1"</b_changed>
</root>
XSLT to change the 'a_original'
<xsl:template match = "a_original">
<a_changed>
<xsl:apply-templates select ="@* | node()">
</a_changed>
</xsl:template>
<xsl:template match = "b_original[@name='foo1']">
<b_changed>
<xsl:apply-templates select ="@* | node()">
</b_changed>
</xsl:template>
Need a solution for XSLT 1.0. There are a lot of different operations happening such as deletion and addition of attributes, deletion and addition of tags etc in my actual XSLT file, so its preferable if i can give a condition which mentions when to skip the nodes rather than the condition which mentions when to change.
Upvotes: 0
Views: 317
Reputation: 70638
Assuming your XML was well-formed. (i.e it was <a_original name="foo"></a_original>
and not <a_original> name ="foo"</a_original>
then the template match you want is
<xsl:template match="a_original[preceding-sibling::changeTag[1]/@value='false']">
Try this XSLT
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output method="xml" indent="yes" />
<xsl:template match="a_original[preceding-sibling::changeTag[1]/@value='false']">
<a_changed>
<xsl:apply-templates select ="@* | node()" />
</a_changed>
</xsl:template>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
If you want a more generic template, try something like this....
<xsl:template match="*[not(self::changeTag)][preceding-sibling::changeTag[1]/@value='false']">
<xsl:element name="{substring-before(local-name(), '_original')}_changed">
<xsl:apply-templates select ="@* | node()" />
</xsl:element>
</xsl:template>
This will rename any such element from _original
to _changed
. If your actual XML elements are not actually suffixed with _original
you may need to explain precisely what the rules are for renaming.
EDIT: If you can't come up with a generic rule for renaming, you might have to do something like this instead...
<xsl:template match="*[not(self::changeTag)][preceding-sibling::changeTag[1]/@value='false']">
<xsl:variable name="newName">
<xsl:choose>
<xsl:when test="self::a_original">a_changed</xsl:when>
<xsl:when test="self::b_original[@name='foo1']">b_changed</xsl:when>
<xsl:otherwise><xsl:value-of select="local-name()" /></xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:element name="{$newName}">
<xsl:apply-templates select ="@* | node()" />
</xsl:element>
</xsl:template>
Upvotes: 1