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>