Home > front end >  Transforming (removing and renaming) xml file tags using xslt
Transforming (removing and renaming) xml file tags using xslt

Time:03-29

I have just started learning xslt and I am very new to this. Which is why I am here to ask this after retrying it multiple times and not getting the desired output. I have this input xml :

<root>
<type>sometype</type>
<attribute name="1st" value="val1"/>
<attribute name="2nd" value="val2"/>
<attribute name="nth" value="valn"/>
  <attribute name="first">
    <tagvalue>
      <entryMap name="mapvalue1">
        <new>
          <type>TypeA</type>
          <attribute name="attr1" value="aaa" />
        </new>
      </entryMap>
    </tagvalue>
  </attribute>
  <attribute name="second">
    <tagvalue>
      <entryMap name="mapvalue2">
        <new>
          <type>TypeB</type>
          <attribute name="attr2" value="bbb" />
        </new>
      </entryMap>
    </tagvalue>
  </attribute>
  <attribute name="third">
    <tagvalue>
      <entryMap name="mapvalue3">
        <new>
          <type>TypeC</type>
          <attribute name="attr3" value="ccc" />
        </new>
      </entryMap>
    </tagvalue>
  </attribute>
</root>

which needs to be transformed to this output xml :

<root>
<type>sometype</type>
<attribute name="1st" value="val1"/>
<attribute name="2nd" value="val2"/>
<attribute name="nth" value="valn"/>
  <attribute name="common">
    <tagvalue>
      <entryMap name="mapvalue1">
        <new>
          <type>TypeA</type>
          <attribute name="attr1" value="aaa" />
        </new>
      </entryMap>
    </tagvalue>
    <tagvalue>
      <entryMap name="mapvalue2">
        <new>
          <type>TypeB</type>
          <attribute name="attr2" value="bbb" />
        </new>
      </entryMap>
    </tagvalue>
    <tagvalue>
      <entryMap name="mapvalue3">
        <new>
          <type>TypeC</type>
          <attribute name="attr3" value="ccc" />
        </new>
      </entryMap>
    </tagvalue>
  </attribute>
</root>

That is, there are 3 occurrences of this tag : <attribute name="first"> <attribute name="second"> <attribute name="third">. I need to have just one occurrence of this at the beginning and rename the name value to "common" i.e. <attribute name="common">. I tried using <xsl:template match="@value">for the renaming logic but I am not able to successfully incorporate it.

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:param name="removeElementsNamed" select="'attribute'"/>

<!-- identity transform -->
<xsl:template match="@*|node()" name="identity">
    <xsl:copy>
        <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
</xsl:template>
<xsl:template match="*">
  <xsl:if test="not(name() = $removeElementsNamed)">
   <xsl:call-template name="identity"/>
  </xsl:if>
 </xsl:template>
</xsl:stylesheet>

But I know I am doing it wrong somewhere. I tried using multiple templates but I am not getting the desired output. I would be very thankful if someone could help me out with this. Thank you!

CodePudding user response:

Here's one way this could be done :

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    version="1.0">
  
  <xsl:output method="xml"/>
  
  <xsl:template match="attribute[1]">
    <xsl:copy>
      <xsl:attribute name="name">common</xsl:attribute>
      <xsl:apply-templates select="//attribute/tagvalue"/>
    </xsl:copy>
  </xsl:template>
  
  <xsl:template match="attribute[position()>1]"/>

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

Here's one way this could be done : https://xsltfiddle.liberty-development.net/nbspVbv/2

CodePudding user response:

Why don't you do simply:

XSLT 1.0

<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="/root">
    <xsl:copy>
        <attribute name="common">
            <xsl:copy-of select="attribute/tagvalue"/>
        </attribute>
    </xsl:copy>
</xsl:template>

</xsl:stylesheet>

Added:

To copy the other elements that are not included in the "common" group, you could do:

    <xsl:template match="/root">
        <xsl:copy>
            <xsl:copy-of select="type | attribute[not(@name='first' or @name='second' or @name='third')]"/>
            <attribute name="common">
                <xsl:copy-of select="attribute[@name='first' or @name='second' or @name='third']/tagvalue"/>
            </attribute>
        </xsl:copy>
    </xsl:template>

Or, a little more elegantly (to avoid testing the same thing twice):

<xsl:template match="/root">
    <xsl:variable name="common" select="attribute[@name='first' or @name='second' or @name='third']" />
    <xsl:copy>
        <xsl:copy-of select="*[count(.|$common) != count($common)]"/>
        <attribute name="common">
            <xsl:copy-of select="$common/tagvalue"/>
        </attribute>
    </xsl:copy>
</xsl:template>
  • Related