Search code examples
xmldatabase-designxsdreusabilitycomplextype

How to model database tables in XSD?


It seems simple to model a database table for, say, addresses, like this in an XSD:

  <xsd:complexType name="address_Type">
    <!-- the columns of the database table for addresses -->
    <xsd:sequence>
      <xsd:element name="street" type="xsd:string" />
      <xsd:element name="city" type="xsd:string" />
      <xsd:element name="state" type="xsd:string" />
    </xsd:sequence>
  </xsd:complexType>

Then you can define an XML format using this tabel plus some other unrelated data, say, a user name, like this:

  <xsd:element name="user" type="user" />
  <!-- =========================================== -->
  <xsd:complexType name="user">
    <xsd:sequence>
      <!-- username stands for all non-address fields -->
      <xsd:element name="username" type="xsd:string" />
      <!-- wrapper element for the address fields -->
      <xsd:element name="address" type="address_Type" />
    </xsd:sequence>
  </xsd:complexType>

and the XML could be like this:

<?xml version="1.0" encoding="utf-8"?>
<user>
  <username>Albert Einstein</username>
  <!-- with wrapper element for address -->
  <address>
    <street>Main Street</street>
    <city>Ghost Town</city>
    <state>Up State</state>
  </address>
</user>

This method is easily extensible to XML's with a list of addresses, or with an address record combined with records from other tables. One XSD could cover lots of XML formats this way.

However, what about someone who thinks, why do I need that stupid "address" wrapper element if I only include 1 instance of an address object, to arrive at this XML:

<?xml version="1.0" encoding="utf-8"?>
<user>
  <username>Albert Einstein</username>
  <!-- no wrapper element for address -->
  <street>Main Street</street>
  <city>Ghost Town</city>
  <state>Up State</state>
</user>

To me it seems that now we cannot use the same complexType for address as in the XSD above.

In my company, the IT organization is dispersed, and if I start yelling "you should add the wrapper element", I might just get a sore throat. Or a headache. So it is up to me to improve my XSD to cope with XML's with and without the wrapper element.

I tried to add an xsd:element without name, but that does not work:

<xsd:element type="address_Type" />

I could not find an xsd: entity with type attribute to point to the complexType other than xsd:element.

My question is if there still is a method to re-use the complexType for the last XML?


Solution

  • If you wish to compose new content models from existing content models without wrapper elements, consider using the xs:group mechanism:

    <?xml version="1.0" encoding="utf-8"?>
    <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    
      <xsd:element name="user" type="user" />
    
      <xsd:complexType name="user">
        <xsd:sequence>
          <xsd:element name="username" type="xsd:string" />
          <!-- 
             ...
             Many more xsd:element or xsd:groups might appear here.
             ...
          -->
          <xsd:group ref="address"/>
        </xsd:sequence>
      </xsd:complexType>
    
      <xsd:group name="address">
        <xsd:sequence>
          <xsd:element name="street" type="xsd:string" />
          <xsd:element name="city" type="xsd:string" />
          <xsd:element name="state" type="xsd:string" />
        </xsd:sequence>
      </xsd:group>  
    
    </xsd:schema>
    

    If you'd like to allow the wrapper optionally, you could use xsd:choice:

    <?xml version="1.0" encoding="utf-8"?>
    <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
      <xsd:element name="user" type="user" />
    
      <xsd:complexType name="user">
        <xsd:sequence>
          <xsd:element name="username" type="xsd:string" />
          <xsd:choice>
            <xsd:group ref="address"/>
            <xsd:element name="address">
              <xsd:complexType>
                <xsd:group ref="address"/>
              </xsd:complexType>
            </xsd:element>
          </xsd:choice>
        </xsd:sequence>
      </xsd:complexType>
    
      <xsd:group name="address">
        <xsd:sequence>
          <xsd:element name="street" type="xsd:string" />
          <xsd:element name="city" type="xsd:string" />
          <xsd:element name="state" type="xsd:string" />
        </xsd:sequence>
      </xsd:group>  
    
    </xsd:schema>