Please help, I’m an XSLT newbie and I’m trying to transform one XML format into another.
I need to extract unique attribute values and transform the values into a new format. The example XML below shows the original and new/target format.
I've spent ages trying to do this without any enjoy. Can anyone help out or give me some pointers?
Original format:
<base>
<level>
<level2 Name ="AA" value="1"/>
</level>
<level>
<level2 Name ="BB" value="2"/>
</level>
<level>
<level2 Name ="BB" value="3"/>
</level>
<level>
<level2 Name ="CC" value="4"/>
</level>
<level>
<level2 Name ="AA" value="5"/>
</level>
</base>
New format:
<base>
<levelNames>
<level level2Name ="AA"/>
<level level2Name ="BB"/>
<level level2Name ="CC"/>
</levelNames>
</base>
Thanks a lot.
XSLT Soln:
<?xml version="1.0" encoding="UTF-8"?>
<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:key name="LevelDistint" match="level2" use="@Name"/>
<xsl:template match="base">
<base>
<levelNames>
<xsl:for-each select="level/level2[generate-id() = generate-id(key('LevelDistint', @Name)[1])]">
<level>
<xsl:attribute name="level2Name"><xsl:value-of select="normalize-space(@Name)"/></xsl:attribute>
</level>
</xsl:for-each>
</levelNames>
</base>
</xsl:template>
</xsl:stylesheet>
XSLT O/P:
<?xml version="1.0" encoding="UTF-8"?>
<base>
<levelNames>
<level level2Name="AA"/>
<level level2Name="BB"/>
<level level2Name="CC"/>
</levelNames>
</base>
Once again the Muenchian grouping technique appears to be the missing piece.
Fairly trivial problem for it, so I'll let you do your own work to get to grips with Muench.
Please create first xsl:key then u can use below code easily.
xsl:key name="levelName" match="level2" use="@Name"
<xsl:template match="/">
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="base">
<xsl:element name="{local-name(.)}">
<xsl:element name="levelNames">
<xsl:apply-templates/>
</xsl:element>
</xsl:element>
</xsl:template>
<xsl:template match="level">
<xsl:for-each select="level2[count(.|key('levelName', @Name)[1]) = 1]">
<xsl:sort order="ascending" data-type="text" select="@Name"/>
<xsl:element name="{local-name(..)}">
<xsl:attribute name="level2Name">
<xsl:value-of select="@Name"/>
</xsl:attribute>
</xsl:element>
</xsl:for-each>
</xsl:template>