Search code examples
xmlxsd

Choice between primitive and complex type within same element name in xml schema?


Consider following XML:

<CLIENTS>
<CLIENT ID="18">
    <NAME>Tim</NAME>
    <MIDDLE_NAME>Billy</MIDDLE_NAME>
    <SURNAME>Riggins</SURNAME>
    <ADDRESS>
        <STREET>
            Eight St
        </STREET>
        <NUMBER>3</NUMBER>
    </ADDRESS>
    <EMAIL>tim_riggins@fnl.com</EMAIL>
    <PHONE_NUMBER>756-2222</PHONE_NUMBER>
</CLIENT>


<CLIENT ID="19">
    <BASIC_INFO>
        <NAME>James</NAME>
        <MIDDLE_NAME>Morgan</MIDDLE_NAME>
        <SURNAME>McGill</SURNAME>
        <ADDRESS>Ninth St.1</ADDRESS>
    </BASIC_INFO>
    <EMAIL>james_mcgill@bcs.com</EMAIL>
    <PHONE_NUMBER>756-3333</PHONE_NUMBER>
</CLIENT>
</CLIENTS>

I need to write XML Schema. Everything went smoothly until I reached ADDRESS part which can be simple string or complex type composed of 2 elements.

What I have tried:

<xsd:simpleType name="STREET-SIMPLE-TYPE">
    <xsd:restriction base="xsd:string">
        <xsd:pattern value="[A-Za-z]+ St\.[0-9]{1,2}"/>
    </xsd:restriction>
</xsd:simpleType>

<xsd:complexType name="STREET-COMPLEX-TYPE">
    <xsd:sequence>
        <xsd:element name="STREET" type="xsd:string"/>
        <xsd:element name="NUMBER" type="xsd:integer"/>
    </xsd:sequence>
</xsd:complexType>

<xsd:complexType name="STREET-TYPE" mixed="true">
    <xsd:choice>
        <xsd:element name="STREETSIMPLE" type="STREET-SIMPLE-TYPE"/>
        <xsd:element name="STREETCOMPLEX" type="STREET-COMPLEX-TYPE"/>
    </xsd:choice>
</xsd:complexType>

but then, I get the following error:

Cvc-complex-type.2.4.b: The Content Of Element 'ADDRESS' Is Not Complete. One Of '{STREETSIMPLE, STREETCOMPLEX}' Is Expected


Solution

  • The reason you are getting the error is that the way you defined it first expect a node called ADDRESS (which you are assigning the type to) and then below it either a STREETSIMPLE or STREETCOMPLEX as illustrated below.

    Shema with ADDRESS using type

    If you put the Choice one level further up it works, and will also prevent having a complex address under the BASIC_INFO address, which the way are your trying it won't do. Schema with choice at a higher level

    <?xml version="1.0" encoding="utf-16"?>
    <xsd:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
      <xsd:element name="CLIENTS">
        <xsd:complexType>
          <xsd:sequence>
            <xsd:element maxOccurs="unbounded" name="CLIENT">
              <xsd:complexType>
                <xsd:sequence>
                  <xsd:choice minOccurs="0">
                    <xsd:element minOccurs="0" name="BASIC_INFO">
                      <xsd:complexType>
                        <xsd:sequence>
                          <xsd:element name="NAME" type="xsd:string" />
                          <xsd:element name="MIDDLE_NAME" type="xsd:string" />
                          <xsd:element name="SURNAME" type="xsd:string" />
                          <xsd:element name="ADDRESS">
                            <xsd:simpleType>
                              <xsd:restriction base="STREET-SIMPLE-TYPE" />
                            </xsd:simpleType>
                          </xsd:element>
                        </xsd:sequence>
                      </xsd:complexType>
                    </xsd:element>
                    <xsd:sequence>
                      <xsd:element name="NAME" type="xsd:string" />
                      <xsd:element name="MIDDLE_NAME" type="xsd:string" />
                      <xsd:element name="SURNAME" type="xsd:string" />
                      <xsd:element name="ADDRESS">
                        <xsd:complexType>
                          <xsd:complexContent mixed="false">
                            <xsd:extension base="STREET-COMPLEX-TYPE" />
                          </xsd:complexContent>
                        </xsd:complexType>
                      </xsd:element>
                    </xsd:sequence>
                  </xsd:choice>
                  <xsd:element name="EMAIL" type="xsd:string" />
                  <xsd:element name="PHONE_NUMBER" type="xsd:string" />
                </xsd:sequence>
                <xsd:attribute name="ID" type="xsd:unsignedByte" use="required" />
              </xsd:complexType>
            </xsd:element>
          </xsd:sequence>
        </xsd:complexType>
      </xsd:element>
      <xsd:simpleType name="STREET-SIMPLE-TYPE">
        <xsd:restriction base="xsd:string">
          <xsd:pattern value="[A-Za-z]+ St\.[0-9]{1,2}" />
        </xsd:restriction>
      </xsd:simpleType>
      <xsd:complexType name="STREET-COMPLEX-TYPE">
        <xsd:sequence>
          <xsd:element name="STREET" type="xsd:string" />
          <xsd:element name="NUMBER" type="xsd:integer" />
        </xsd:sequence>
      </xsd:complexType>
    </xsd:schema>