I have a XML file which looks roughly like this (actual file is much more complex, everything has been truncated in this example):
<?xml version="1.0" encoding="utf-8"?>
<root>
<element>
<tag1>1</tag1>
<tag2>stuff</tag2>
<type>String</type>
<tag3>stuff</tag3>
</element>
<element>
<tag1>2</tag1>
<tag2>stuff</tag2>
<type>String</type>
<type>Date</type>
<type>Float</type>
<tag3>stuff</tag3>
</element>
<element>
<tag1>3</tag1>
<tag2>stuff</tag2>
<type>DateTime</type>
<tag3>stuff</tag3>
</element>
<element>
<tag1>4</tag1>
<tag2>stuff</tag2>
<type>Float</type>
<type>String</type>
<type>Date</type>
<tag3>stuff</tag3>
</element>
</root>
I process it with the following XSLT:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xsl:template match="element">
<xsl:element name="xs:element">
<xsl:attribute name="type"><xsl:call-template name="type"/></xsl:attribute>
</xsl:element>
</xsl:template>
<xsl:template name="type">
<xsl:variable name="initialType" select="translate(type,' ','')"/>
<xsl:choose>
<xsl:when test="$initialType='String'">
<xsl:text>xs:string</xsl:text>
</xsl:when>
<xsl:when test="$initialType='Date'">
<xsl:text>xs:date</xsl:text>
</xsl:when>
<xsl:when test="$initialType='DateTime'">
<xsl:text>xs:dateTime</xsl:text>
</xsl:when>
<xsl:when test="$initialType='Float'">
<xsl:text>xs:float</xsl:text>
</xsl:when>
<xsl:when test="$initialType='Integer'">
<xsl:text>xs:int</xsl:text>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$initialType"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
And I get this resulting file:
<?xml version="1.0" encoding="UTF-8"?>
<xs:element xmlns:xs="http://www.w3.org/2001/XMLSchema" type="xs:string"/>
<xs:element xmlns:xs="http://www.w3.org/2001/XMLSchema" type="xs:string"/>
<xs:element xmlns:xs="http://www.w3.org/2001/XMLSchema" type="xs:dateTime"/>
<xs:element xmlns:xs="http://www.w3.org/2001/XMLSchema" type="xs:float"/>
My problem here is that only the first <type>
tag is taken into account. What I would like is to concatenate all the type tag contents into the type tag of the output, preceded by a sign indicating that the tag is an agglomerate if applicable.
However, to avoid creating artificially numerous types, the content of the tags must be alphabetically sorted first. In this example, the <element>
number 2 and 4 are both made of only Float, String, and Date, albeit in a different order. They need to have the same type in the output.
The following output would be acceptable:
<?xml version="1.0" encoding="UTF-8"?>
<xs:element xmlns:xs="http://www.w3.org/2001/XMLSchema" type="xs:string"/>
<xs:element xmlns:xs="http://www.w3.org/2001/XMLSchema" type="unionxs:datexs:floatxs:string"/>
<xs:element xmlns:xs="http://www.w3.org/2001/XMLSchema" type="xs:dateTime"/>
<xs:element xmlns:xs="http://www.w3.org/2001/XMLSchema" type="unionxs:datexs:floatxs:string"/>
I am very new to XLST, and I have not managed to get anywhere close to the desired output so far. The code I have tried is just below, and fails horribly, notably because I failed to understand how to get <xsl:sort>
working:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xsl:template match="element">
<xsl:element name="xs:element">
<xsl:attribute name="type">
<xsl:apply-templates>
<xsl:sort select="."/>
</xsl:apply-templates>
<xsl:call-template name="type"/>
</xsl:attribute>
</xsl:element>
</xsl:template>
<xsl:template name="type">
<xsl:choose>
<xsl:when test="following-sibling::type">
<xs:text>union</xs:text>
<xsl:for-each select="following-sibling::type">
<xs:text>translate(type,' ','')</xs:text>
</xsl:for-each>
</xsl:when>
<xsl:otherwise>
<xsl:variable name="initialType" select="translate(type,' ','')"/>
<xsl:choose>
<xsl:when test="$initialType='String'">
<xsl:text>xs:string</xsl:text>
</xsl:when>
<xsl:when test="$initialType='Date'">
<xsl:text>xs:date</xsl:text>
</xsl:when>
<xsl:when test="$initialType='DateTime'">
<xsl:text>xs:dateTime</xsl:text>
</xsl:when>
<xsl:when test="$initialType='Float'">
<xsl:text>xs:float</xsl:text>
</xsl:when>
<xsl:when test="$initialType='Integer'">
<xsl:text>xs:int</xsl:text>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$initialType"/>
</xsl:otherwise>
</xsl:choose>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>