XSLT Transformation for XSD to FBS (Flatbuffers)
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 eg 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>; </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>
It shouldn't be very complicated to write one, eg:
<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> </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.
上一篇: 语音到iOS中的文本应用程序?