Removing Redundant Complex Types in XML Schema Using XSLT

I got a bunch of XML schemas that contain "extra" complex types, and I'm looking for a way to remove them using XSLT.

Schemas (see below) have several tags <xsd:element name="ElementX" type="ComplexTypeX">

, each of which refers to a complex type. Each complex type inherits from a base type in a different schema (Datatypes.xsd), but does nothing to extend or constrain the type - hence it's pretty pointless!

<?xml version="1.0" encoding="utf-8"?>
<xsd:schema targetNamespace="..." xmlns:xsd="..." xmlns="...">
  <xsd:include schemaLocation="Datatypes.xsd" />

  <xsd:complexType name="ComplexType1">
    <xsd:simpleContent>
      <xsd:extension base="ActualType1" />
    </xsd:simpleContent>
  </xsd:complexType>
  <xsd:element name="ElementName1" type="ComplexType1" />

  <xsd:complexType name="ComplexType2">
    <xsd:simpleContent>
      <xsd:extension base="ActualType2" />
    </xsd:simpleContent>
  </xsd:complexType>
  <xsd:element name="ElementName2" type="ComplexType2" />

  ...
 </xsd:schema>

      

I'm trying (but not very far ...) to write an XSLT transformation:

  • Replace the type of each element with the corresponding base type of the base type. For example. the ElementName1 type above would be ActualType1.

  • Remove the entire complex type from the output.

Output signal:

<?xml version="1.0" encoding="utf-8"?>
<xsd:schema targetNamespace="..." xmlns:xsd="..." xmlns="...">
  <xsd:include schemaLocation="Datatypes.xsd" />

  <xsd:element name="ElementName1" type="ActualType1" />

  <xsd:element name="ElementName2" type="ActualType2" />
  .
  .
  .
 </xsd:schema>

      

Currently, all of the complexType members do not change the underlying type in any way, so it is safe to perform the replacement. However, if, in the future, some of the complexType elements have been changed to restrict or extend their base type (and have meaningful use), I would like to simply replace / remove the remaining redundant types. Although I understand that this will add some complexity to the XSLT.

Reference Information. The schematics come from a third party and unfortunately I have no control over their production. I suspect that an extra layer of complex types is present due to the rigging used to create the schematics.

Thank!

+3


source to share


2 answers


I'm trying (but not very far ...) to write an XSLT transformation to:

  • Replace the type of each element with the corresponding base type of the base type. For example. the ElementName1 type above would be ActualType1.

  • Remove the entire complex type from the output.

These two can be achieved by:

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>

<xsl:key name="complex" match="xsd:complexType" use="@name" />

<!-- identity transform -->
<xsl:template match="@*|node()">
    <xsl:copy>
        <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
</xsl:template>

<!-- replace element type -->
<xsl:template match="xsd:element">
    <xsl:copy>
        <xsl:copy-of select="@*"/>
        <xsl:attribute name="type">
            <xsl:value-of select="key('complex', @type)/xsd:simpleContent/xsd:extension/@base"/>
        </xsl:attribute>
        <xsl:apply-templates select="node()"/>
    </xsl:copy>
</xsl:template>

<!-- remove complexType -->
<xsl:template match="xsd:complexType"/>

</xsl:stylesheet>

      



I'm afraid I didn't understand this part:

However, in the event that some of the complexType elements have been changed to restrict or extend their base type (and have some meaningful use), I would like to add a check for that before doing the replacement / removal.

+1


source


You seem to want something like this:

<?xml version="1.0" ?>
<xsl:stylesheet version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:xsd="http://www.w3.org/2001/XMLSchema">

  <!-- anything not otherwise matched gets copied -->

  <xsl:template match="@*|node()">
    <xsl:apply-templates select="." mode="literal"/>
  </xsl:template>

  <xsl:template match="@*|node()" mode="attribute-filter">
    <xsl:apply-templates select="." mode="literal"/>
  </xsl:template>

  <xsl:template match="@*|node()" mode="literal">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
  </xsl:template>

  <!-- in mode 'attribute-filter', 'name' and 'type' attributes transform to nothing -->
  <xsl:template match="@name|@type" mode="attribute-filter">
    <!-- transforms to nothing -->
  </xsl:template>

  <!-- keep only meaningful extension types -->
  <xsl:template match="/xsd:schema/xsd:complexType[./xsd:simpleContent/xsd:extension]">
    <xsl:if test="boolean(./xsd:simpleContent/xsd:extension/node())">
      <!-- a bona fide extension -->
      <xsl:apply-templates select="." mode="literal"/>
    </xsl:if>
    <!-- else it transforms to nothing -->
  </xsl:template>

  <!-- patch up element declarations where necessary -->
  <xsl:template match="xsd:element[@type]">
    <xsl:variable name="typename" select="@type" />
    <xsl:choose>
      <xsl:when test="not(/xsd:schema/xsd:complexType[@name = $typename]/xsd:simpleContent)">
        <xsl:apply-templates select="." mode="literal"/>
      </xsl:when>
      <xsl:when test="boolean(/xsd:schema/xsd:complexType[@name = $typename]/xsd:simpleContent/xsd:restriction)">
        <xsl:apply-templates select="." mode="literal"/>
      </xsl:when>
      <xsl:when test="boolean(/xsd:schema/xsd:complexType[@name = $typename]/xsd:simpleContent/xsd:extension/node())">
        <xsl:apply-templates select="." mode="literal"/>
      </xsl:when>
      <xsl:otherwise>
        <xsl:element name="xsd:element">
          <xsl:copy-of select="@name" />
          <xsl:attribute name="type">
            <xsl:value-of select="/xsd:schema/xsd:complexType[@name = $typename]/xsd:simpleContent/xsd:extension/@base"/>
          </xsl:attribute>
          <xsl:apply-templates select="@*|node()" mode="attribute-filter"/>
        </xsl:element>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>

</xsl:stylesheet>

      



This assumes that in declarations of unwanted complexTypes, everyone uses the extension alternative for plain content as in the example, but it can be extended to handle other unwanted types as well.

+1


source







All Articles