After searching on the Internet and digging in some books I figured out how to implement that.
First of all we need to define a generic type which accommodates all attributes and elements from both kinds of the primitive element. It is assumed that the definition element is defined somewhere else.
<xs:complexType name="primitive" abstract="true">
<xs:sequence>
<xs:element ref="definition" minOccurs="0" maxOccurs="unbounded" />
</xs:sequence>
<xs:attribute name="name" type="xs:Name" />
<xs:attribute name="ref" type="xs:Name" />
</xs:complexType>
Then we define two primitive subtypes to be used in the primitive-list and
composite respectively.
<xs:complexType name="public-primitive">
<xs:complexContent>
<xs:restriction base="primitive">
<xs:sequence>
<xs:element ref="definition" minOccurs="1" maxOccurs="unbounded" />
</xs:sequence>
<xs:attribute name="name" type="xs:Name" use="required" />
<xs:attribute name="ref" use="prohibited" />
</xs:restriction>
</xs:complexContent>
</xs:complexType>
<xs:complexType name="private-primitive">
<xs:complexContent>
<xs:restriction base="primitive">
<xs:sequence>
<xs:element ref="definition" minOccurs="0" maxOccurs="unbounded" />
</xs:sequence>
<xs:attribute name="name" use="prohibited" />
</xs:restriction>
</xs:complexContent>
</xs:complexType>
Now we can define the primitive-list and composite elements in terms of these complex types as follows:
<xs:element name="primitive-list">
<xs:complexType>
<xs:sequence>
<xs:element name="primitive" type="public-primitive" maxOccurs="unbounded" />
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="composite">
<xs:complexType>
<xs:sequence>
<xs:element name="primitive" type="private-primitive" maxOccurs="unbounded">
<xs:key name="definition-ref--co-occurrence--constraint">
<xs:selector xpath="." />
<xs:field xpath="definition|@ref" />
</xs:key>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
Let's take a look at the original schema requirements and see how they are enforced:
- If a primitive element is specified inside a primitive-list element, then it should contain the name attribute and the embedded definition element, but not the ref attribute.
This requirement is enforced by the definition of the public-primitive type alone.
- If a primitive element is specified in the composite element, then it should contain either the ref attribute or the definition element. The name is allowed in neither cases.
This requirement is enforced by the definition of the private-primitive type and by the xs:key element specified in the primitive element defined inside of the composite element. The xs:key guaranties that either ref or definition is present but not both.