XSLT is very a good solution for your problem. You can easily map your structure to individual templates which will be called recursively.
Here is an example of a XSLT 2.0 stylesheet with templates for just the the examples you provided. It should provide a good starting point.
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema" version="2.0">
<xsl:output method="xml" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="document">
<xs:schema elementFormDefault="qualified">
<xsl:apply-templates/>
</xs:schema>
</xsl:template>
<xsl:template match="primitive">
<xs:element name="{@name}" type="{@type}" minOccurs="{if(@mandatory eq 'true') then 1 else 0}" maxOccurs="1" />
</xsl:template>
<xsl:template match="structure">
<xs:element name="{@name}" minOccurs="{if(@mandatory eq 'true') then 1 else 0}" maxOccurs="1">
<xs:complexType>
<xs:all>
<xsl:apply-templates/>
</xs:all>
</xs:complexType>
</xs:element>
</xsl:template>
<xsl:template match="list">
<xs:element name="{@name}" minOccurs="{if(@mandatory eq 'true') then 1 else 0}">
<xs:complexType>
<xs:sequence maxOccurs="unbounded">
<xsl:apply-templates/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xsl:template>
</xsl:stylesheet>
There are many ways to achieve the same results. Look for a good XSLT tutorial that makes efficient use of XSLT templates. Avoid the ones that focus on single-template solutions using for-each
. You can achieve everything you need using templates (and not using <xsl:for-each>
which will make it excessively more complicated).
In case your support is limited to XSLT 1.0, you won't be able to use the (XPath 2.0) code in the minOccurs
attributes, but you can generate the attribute with a nested <xsl:attribute>
and use <xsl:choose>
to calculate its contents.
The stylesheet above could be rewritten in XSLT 1.0 as below:
<?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" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="document">
<xs:schema elementFormDefault="qualified">
<xsl:apply-templates/>
</xs:schema>
</xsl:template>
<xsl:template match="primitive">
<xs:element name="{@name}" type="{@type}" maxOccurs="1">
<xsl:attribute name="minOccurs">
<xsl:choose>
<xsl:when test="@mandatory = 'true'">1</xsl:when>
<xsl:otherwise>0</xsl:otherwise>
</xsl:choose>
</xsl:attribute>
</xs:element>
</xsl:template>
<xsl:template match="structure">
<xs:element name="{@name}" maxOccurs="1">
<xsl:attribute name="minOccurs">
<xsl:choose>
<xsl:when test="@mandatory = 'true'">1</xsl:when>
<xsl:otherwise>0</xsl:otherwise>
</xsl:choose>
</xsl:attribute>
<xs:complexType>
<xs:all>
<xsl:apply-templates/>
</xs:all>
</xs:complexType>
</xs:element>
</xsl:template>
<xsl:template match="list">
<xs:element name="{@name}">
<xsl:attribute name="minOccurs">
<xsl:choose>
<xsl:when test="@mandatory = 'true'">1</xsl:when>
<xsl:otherwise>0</xsl:otherwise>
</xsl:choose>
</xsl:attribute>
<xs:complexType>
<xs:sequence maxOccurs="unbounded">
<xsl:apply-templates/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xsl:template>
</xsl:stylesheet>