2

I have many XML-schematas written in xsd to define the structure of xml documents. Now I want to substitute the format with flatbuffers. When looking at the fbs format it looks possible to convert the XSD Schema definition automatically into a FBS file using XSLT. As there might be other people that have the same problem I am asking here if there are already some approaches to solve the automatic conversion of XSD Schematas to FBS.

XSD-Schema example:

<xs:complexType name="Configuration">
  <xs:sequence>
    <xs:element name="MandatoryDetail" 
                type="ComplexConfigDetail" 
                minOccurs="1" 
                maxOccurs="1"/>
    <xs:element name="OptionalDetail" 
                type="ComplexConfigDetail" 
                minOccurs="0" 
                maxOccurs="1"/>
    <xs:element name="UnboundedDetail" 
                type="ComplexConfigDetail" 
                minOccurs="0" 
                maxOccurs="unbounded"/>
  </xs:sequence>
  <xs:attribute name="MandatoryInt" 
                use="required" 
                type="xs:unsignedInt"/>
  <xs:attribute name="OptionalInt" 
                use="optional" 
                type="xs:unsignedInt"/>
</xs:complexType>

<xs:complexType name="ComplexConfigDetail">
  <xs:sequence maxOccurs="1">
  <xs:element name="Frame" 
              type="xs:int" 
              minOccurs="0" 
              maxOccurs="1"/>
  </xs:sequence>
</xs:complexType>

Expected FBS-Schema:

namespace http_www_demo_com_config

table ComplexConfigDetail {
    DetailElement : int;
}

table Configuration {
    MandatoryInt : uint (required);
    OptionalInt : uint;
    MandatoryDetail : ComplexConfigDetail (required);
    OptionalDetail : ComplexConfigDetail;
    UnboundedDetail : [ComplexConfigDetail];
}

Is there such a transformation available as e.g. XSLT.

EDIT: Thanks to Dan I extended his XSLT to this one also handling xs:extensions (inheritance)

<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="text" omit-xml-declaration="yes" />

  <xsl:template match="/xs:schema">namespace http_www_demo_com_config;
    <xsl:apply-templates select="//xs:simpleType" />
    <xsl:apply-templates select="//xs:complexType" />
</xsl:template>

  <xsl:template match="xs:simpleType[xs:restriction/@base='xs:string' and count(xs:restriction/xs:enumeration) > 0]">
enum <xsl:value-of select="@name"/> : byte {
  <xsl:for-each select="xs:restriction/xs:enumeration" >
    <xsl:value-of select="@value"/>
      <xsl:if test="position() != last()">
        <xsl:text>,
  </xsl:text>
      </xsl:if>
    </xsl:for-each>
 }</xsl:template>

<xsl:template name="complexTypeMatch" match="xs:complexType">
table <xsl:value-of select="@name" /> {
<xsl:apply-templates select="xs:complexContent" />
  <xsl:apply-templates select="xs:sequence/xs:element" />
  <xsl:apply-templates select="xs:attribute" />  }
</xsl:template>

  <xsl:template match="xs:complexContent">
    <xsl:apply-templates  select="xs:extension"/>
  </xsl:template>

<xsl:template name="extensionType" match="xs:extension">
<xsl:apply-templates select="//xs:complexType[@name=current()/@base]/xs:complexContent" />
<xsl:apply-templates select="//xs:complexType[@name=current()/@base]/xs:sequence/xs:element"/>
<xsl:apply-templates select="//xs:complexType[@name=current()/@base]/xs:attribute"/>
</xsl:template>

<xsl:template match="xs:element | xs:attribute">
  <xsl:text>  </xsl:text>
  <xsl:value-of select="@name" /> : <xsl:if test="@maxOccurs != 1">[</xsl:if>
  <xsl:call-template name="typeTransformer">
    <xsl:with-param name="type" select="@type" />
  </xsl:call-template>
<xsl:if test="@maxOccurs != 1">]</xsl:if>
<xsl:if test="@minOccurs > 0"> (required)</xsl:if>
<xsl:text>;&#13;&#10;</xsl:text>
</xsl:template>

<xsl:template name="typeTransformer">
  <xsl:param name="type" />
  <xsl:choose>
      <xsl:when test="$type = 'xs:unsignedInt'"><xsl:text>uint</xsl:text></xsl:when>
      <xsl:when test="$type = 'xs:unsignedByte'"><xsl:text>ubyte</xsl:text></xsl:when>
      <xsl:when test="starts-with($type, 'xs:')"><xsl:value-of select="substring-after($type, 'xs:')" /></xsl:when>
  <xsl:otherwise>
    <xsl:value-of select="$type" />
  </xsl:otherwise>
</xsl:choose>

</xsl:template>
</xsl:stylesheet>
schoetbi
  • 12,009
  • 10
  • 54
  • 72
  • I've not heard of such an available converter, but given that the input is XML also, it should be easy to create one. – Aardappel Mar 24 '17 at 16:00

1 Answers1

1

It shouldn't be very complicated to write one, e.g.:

<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="text" omit-xml-declaration="yes" />
  <xsl:template match="/xs:schema">
namespace http_www_demo_com_config
    <xsl:apply-templates />
  </xsl:template>
  <xsl:template match="xs:complexType">
table <xsl:value-of select="@name" /> {
    <xsl:apply-templates />
}
  </xsl:template>

  <xsl:template match="xs:element | xs:attribute">
    <xsl:value-of select="@name" /> : 
    <xsl:if test="@maxOccurs != 1">[</xsl:if>
    <xsl:call-template name="typeTransformer">
      <xsl:with-param name="type" select="@type" />
    </xsl:call-template>
    <xsl:if test="@maxOccurs != 1">]</xsl:if>
    <xsl:if test="@minOccurs > 0"> (required)</xsl:if>
    <xsl:text>&#13;&#10;</xsl:text>
  </xsl:template>

  <xsl:template name="typeTransformer">
    <xsl:param name="type" />
    <xsl:choose>
      <xsl:when test="$type = 'xs:unsignedInt'">
         <xsl:text>uint</xsl:text>
      </xsl:when>
      <xsl:when test="starts-with($type, 'xs:')">
         <xsl:value-of select="substring-after($type, 'xs:')" />
      </xsl:when>
      <xsl:otherwise>
         <xsl:value-of select="$type" />  
      </xsl:otherwise>
    </xsl:choose>

  </xsl:template>
</xsl:stylesheet>

Just expand that choice to transform your other specific attribute values that won't line up correctly.

Dan Field
  • 20,885
  • 5
  • 55
  • 71
  • I tried it and it converts most basic types. However some parts as xs:extensions are not handeled. This transformation is not trivial and XSLT is not my language ;-). After some tests I came up with the version in my question. If you see an improvement please let me know :-) – schoetbi Mar 27 '17 at 07:45
  • Yeah, I'd say jus tkeep working through it and if you're facing a particular challenge feel free to post another question. There's some very talented people with XSLT (far moreso than me) that tend to respond pretty quickly to well formed questions on here – Dan Field Mar 27 '17 at 12:09