Renaming xml attribute value if another attribute has a specific value using XSLT

Viewed 21

I am trying to transform my input xml to output xml using XSLT based on certain conditions.

My input xml :

<top>
<type>Random value</type>
<attribute name="a"/>
<attribute name="b"/>
...
<attribute name="n"/>
  <attribute name="some value">
    <mapResponses>
      <entryMap name="value1">
        <section>
          <type>STATUS_RESPONSE</type>
          <attribute name="status_code" value="1001" />
          <attribute name="status_detail" value="OK" />
          <attribute name="type" value="Row Line" />
          <attribute name="abc" value="def" />
          ...
          <attribute name="hju" value="tyu" />
        </section>
      </entryMap>
      <entryMap name="value2">
        <section>
          <type>STATUS_RESPONSE</type>
          <attribute name="status_code" value="1001" />
          <attribute name="status_detail" value="OK" />
          <attribute name="type" value="Column value" />
          <attribute name="mno" value="pqr" />
          ...
          <attribute name="olp" value="tre" />
        </section>
      </entryMap>
      <entryMap name="value3">
        <section>
          <type>STATUS_RESPONSE</type>
          <attribute name="status_code" value="1001" />
          <attribute name="status_detail" value="OK" />
          <attribute name="type" value="Other random value" />
          <attribute name="oui" value="fry" />
          ...
          <attribute name="tgy" value="adr" />
        </section>
      </entryMap>
      <entryMap name="value4">
        <section>
         .....
        </section>
      </entryMap>
       <entryMap name="...">
        <section>
         .....
        </section>
      </entryMap>
    </mapResponses>
  </attribute>
</top>

to be transformed to this output xml :

<top>
<type>Random value</type>
<attribute name="a"/>
<attribute name="b"/>
...
<attribute name="n"/>
  <attribute name="some value">
    <mapResponses>
      <entryMap name="value1">
        <section>
          <type>CREATE_ROW</type>
          <attribute name="status_code" value="1001" />
          <attribute name="status_detail" value="OK" />
          <attribute name="type" value="Row Line" />
          <attribute name="abc" value="def" />
          ...
          <attribute name="hju" value="tyu" />
        </section>
      </entryMap>
      <entryMap name="value2">
        <section>
          <type>CREATE_COLUMN</type>
          <attribute name="status_code" value="1001" />
          <attribute name="status_detail" value="OK" />
          <attribute name="type" value="Column value" />
          <attribute name="mno" value="pqr" />
          ...
          <attribute name="olp" value="tre" />
        </section>
      </entryMap>
      <entryMap name="value3">
        <section>
          <type>CREATE_COLUMN</type>
          <attribute name="status_code" value="1001" />
          <attribute name="status_detail" value="OK" />
          <attribute name="type" value="Other random value" />
          <attribute name="oui" value="fry" />
          ...
          <attribute name="tgy" value="adr" />
        </section>
      </entryMap>
      <entryMap name="value4">
        <section>
         .....
        </section>
      </entryMap>
       <entryMap name="...">
        <section>
         .....
        </section>
      </entryMap>
    </mapResponses>
  </attribute>
</top>

So, when I have <attribute name="type" value="Row Line" /> the <type>STATUS_RESPONSE</type> needs to be changed to <type>CREATE_ROW</type>. And when I have <attribute name="type" value="Column value" /> or <attribute name="type" value="Other random value" /> or any <attribute name="type" value="..." /> where value is NOT Row Line, the <type>STATUS_RESPONSE</type> needs to be changed to <type>CREATE_COLUMN</type>. The ... are mentioned to generalize the xml that it can contain more content but in same levels. The <attribute name="type" value="..." /> is always at the 3rd position after STATUS_RESPONSE as mentioned in the input and output xml.

The current XSLT I have is this :

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>

  <xsl:template match="@*|node()">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
  </xsl:template>
  
    <xsl:template match="type">
      <xsl:for-each select="attribute[@name='type'][@value='Row Line']">
        <xsl:copy/>
        <xsl:value-of select="CREATE_ROW"/>
      </xsl:for-each>
    </xsl:template>
  
    <xsl:template match="type">
      <xsl:for-each select="attribute[@name='type'][@value!='Row Line']">
        <xsl:copy/>
        <xsl:value-of select="CREATE_COLUMN"/>
      </xsl:for-each>
    </xsl:template>  
</xsl:stylesheet>

I am not able to get my desired output from this XSLT. I am very new to XSLT and I just started working on it. Please kindly help me out with this. Thank You!

1 Answers

You had two templates both matching type (so last one in the stylesheet would "win"), then you had a for loop that was looking for attribute elements that were children of type (there are none, because they are siblings).

Move the criteria matching the type elements into a predicate, looking for the attribute elements on the following-sibling:: axis, and in the second template, no need to assert that the @value is not equal to 'Row Line' since the other one already matches when it does (and avoids any potential issues with != on sets where most people really mean not(@value='Row Line')).

<xsl:stylesheet version="1.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
    <xsl:strip-space elements="*"/>
    
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>
    
    <xsl:template match="type[following-sibling::attribute[@name='type' and @value='Row Line']]">
        <xsl:copy>CREATE_ROW</xsl:copy>
    </xsl:template>
    
    <xsl:template match="type[following-sibling::attribute[@name='type']]">
        <xsl:copy>CREATE_COLUMN</xsl:copy>
    </xsl:template>  

</xsl:stylesheet>
Related