Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Attribute/element co-occurrence constraint in XML Schema

Tags:

xml

schema

xsd

Is it possible to create an XML Schema which imposes a co-occurrence constraint to an attribute/element pair?

<primitive-list>
    <primitive name="P1">
        <definition><!-- primitive specification --></definition>
    </primitive>
    <primitive name="P2">
        <definition><!-- primitive specification --></definition>
    </primitive>

    <!-- other common primitives are specified here-->

<primitive-list>

<composite-list>
    <composite name="C1">
        <primitive ref="P1" />
        <primitive ref="P2" />
        <primitive>
            <definition><!-- inline primitive specification --></definition>
        </primitive>        
    </composite>

    <!-- Other compisites are specified here-->

</composite-list>

The schema should imply that:

  • 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.
  • 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.

I am pretty sure that it is possible since the element element in XML Schema itself behaves just like that. So anybody who is in possession of that sacred knowledge please share :-)

Thank you in advance.

like image 977
Maxim Vladimirsky Avatar asked Nov 26 '08 13:11

Maxim Vladimirsky


1 Answers

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.

like image 122
Maxim Vladimirsky Avatar answered Nov 15 '22 19:11

Maxim Vladimirsky