SyntaxStudy
Sign Up
XML XSD Complex Types, Keys, and References
XML Beginner 2 min read

XSD Complex Types, Keys, and References

Complex types in XSD describe elements that have child content, attributes, or both. A complex type with element-only content uses a compositor: xs:sequence (children in fixed order), xs:all (children in any order, each at most once), or xs:choice (exactly one of the listed children). These compositors can be nested and their minOccurs/maxOccurs can be controlled, providing great flexibility in expressing content models. Complex types support two forms of derivation. Extension adds new child elements or attributes to an existing base type, similar to inheritance in object-oriented programming. Restriction narrows a complex type by further constraining the allowed values of attributes or the cardinality of child elements. Both extension and restriction allow type hierarchies, and XSD validators enforce the Liskov-like principle that a derived type instance is also valid against the base type (for extension). XSD provides the xs:key, xs:unique, and xs:keyref constraints as more powerful alternatives to the ID/IDREF mechanism from DTDs. xs:key declares that a set of fields within a selector scope must be unique and non-null. xs:unique is like xs:key but allows null (missing) values. xs:keyref declares a foreign-key relationship: the value of a field must match a key or unique value in another part of the document. These constraints are checked by validating parsers across the entire document.
Example
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">

    <xs:element name="store">
        <xs:complexType>
            <xs:sequence>
                <xs:element name="products">
                    <xs:complexType>
                        <xs:sequence>
                            <xs:element name="product" type="ProductType"
                                        minOccurs="0" maxOccurs="unbounded"/>
                        </xs:sequence>
                    </xs:complexType>
                </xs:element>
                <xs:element name="orders">
                    <xs:complexType>
                        <xs:sequence>
                            <xs:element name="order" type="OrderType"
                                        minOccurs="0" maxOccurs="unbounded"/>
                        </xs:sequence>
                    </xs:complexType>
                </xs:element>
            </xs:sequence>
        </xs:complexType>

        <!-- Key: product/@id must be unique and non-null -->
        <xs:key name="productKey">
            <xs:selector xpath="products/product"/>
            <xs:field    xpath="@id"/>
        </xs:key>

        <!-- Keyref: order/item/@productId must reference a product key -->
        <xs:keyref name="orderItemRef" refer="productKey">
            <xs:selector xpath="orders/order/item"/>
            <xs:field    xpath="@productId"/>
        </xs:keyref>
    </xs:element>

    <xs:complexType name="ProductType">
        <xs:sequence>
            <xs:element name="name"  type="xs:string"/>
            <xs:element name="price" type="xs:decimal"/>
        </xs:sequence>
        <xs:attribute name="id" type="xs:string" use="required"/>
    </xs:complexType>

    <xs:complexType name="OrderType">
        <xs:sequence>
            <xs:element name="item" maxOccurs="unbounded">
                <xs:complexType>
                    <xs:attribute name="productId" type="xs:string" use="required"/>
                    <xs:attribute name="qty"        type="xs:positiveInteger" use="required"/>
                </xs:complexType>
            </xs:element>
        </xs:sequence>
        <xs:attribute name="orderId" type="xs:string" use="required"/>
    </xs:complexType>

</xs:schema>