Gaurav Bipul
Gaurav Bipul

Reputation: 113

Partial xslt transformation on the xml

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

Answers (1)

Tim C
Tim C

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

Related Questions