Search code examples
xsdfixedenumeration

distincting xs:choices in xsd by using fixed values for element with enumeration type


Is it possible to distinct xs:choices in xsd by using fixed values? I have a simple type:

<xs:simpleType name="datatypeCategory">
    <xs:restriction base="xs:string">
        <xs:enumeration value="SIMPLE"/>
        <xs:enumeration value="COMPLEX"/>
        <xs:enumeration value="COLLECTION"/>
    </xs:restriction>
</xs:simpleType>

And what I want to achieve is

<xs:element name="datatype">
    <xs:complexType>
        <xs:choice>
            <xs:sequence>
                <xs:element id="category" type="datatypeCategory" fixed="SIMPLE"/>
                <!-- some fields specific for SIMPLE -->
            </xs:sequence>
            <xs:sequence>
                <xs:element id="category" type="datatypeCategory" fixed="COMPLEX"/>
                <!-- some fields specific for COMPLEX -->
            </xs:sequence>
            <xs:sequence>
                <xs:element id="category" type="datatypeCategory" fixed="COLLECTION"/>
                <!-- some fields specific for COLLECTION -->
            </xs:sequence>
        </xs:choice>
    </xs:complexType>
</xs:element>

When I do this my XMLSpy tells me:

# The content model of complex type definition '{anonymous}' is ambiguous.
# Details: cos-nonambig: <xs:element name='category'> makes the content model non-deterministic against <xs:element name='category'>. Possible causes: name equality, overlapping occurrence or substitution groups.

Solution

  • You can't do exactly that. The error is because a simple validator that sees a <category> element won't immediately know which branch of the choice to take, and XML Schema 1.0 supports such simple validators.

    An alternative would be to name each element according to the category.

    <xs:element name="datatype">
        <xs:complexType>
            <xs:choice>
                <xs:sequence>
                    <xs:element name="simpleCategory" type="empty"/>
                    <!-- some fields specific for SIMPLE -->
                </xs:sequence>
                <xs:sequence>
                    <xs:element name="complexCategory" type="empty"/>
                    <!-- some fields specific for COMPLEX -->
                </xs:sequence>
                <xs:sequence>
                    <xs:element name="collectionCategory" type="empty"/>
                    <!-- some fields specific for COLLECTION -->
                </xs:sequence>
            </xs:choice>
        </xs:complexType>
    </xs:element>
    

    where empty is defined as an empty type. Or give them complex types to hold the "specific fields". There are other alternatives depending on your constraints, such as using substitution groups or derived complex types.

    In general though, XML Schema 1.0 is not good for constraints based on interrelated values. For that, you have to go to XML Schema 1.1 or an external tool.