Search code examples
xmlxsdxsd-validationxml-validationxsd-1.0

Unique value across elements in XSD


I'm trying to enforce a unique value across an element used in multiple complexType elements.

For example :

<xs:element name="lmt">
    <xs:complexType>
        <xs:choice maxOccurs="unbounded">
            <xs:element ref="lf" maxOccurs="unbounded"/>
            <xs:element ref="cdl" maxOccurs="unbounded"/>
        </xs:choice>
    </xs:complexType>
    <xs:unique name="uniquePos">
        <xs:selector xpath="./*/pos"/>
        <xs:field xpath="."/>
    </xs:unique>
</xs:element>

<xs:element name="pos">
    <xs:simpleType>
        <xs:restriction base="xs:integer">
            <xs:pattern value="\d{1}"/>
        </xs:restriction>
    </xs:simpleType>
</xs:element>

<xs:element name="lf">
    <xs:complexType>
        <xs:sequence>
            <xs:element ref="pos"/>
            ... more elements ... 
        </xs:sequence>
    </xs:complexType>
</xs:element>

<xs:element name="cdl">
    <xs:complexType>
        <xs:sequence>
            <xs:element ref="pos"/>
            ... more elements ... 
        </xs:sequence>
    </xs:complexType>
</xs:element>

I'd like this to fail if I have something like :

<lmt>
    <lf>
        <pos>1</pos>
        ... more elements ... 
    </lf>
    <cdl>
        <pos>1</pos>
        ... more elements ... 
    </cdl>
</lmt>

but validate

<lmt>
    <lf>
        <pos>1</pos>
        ... more elements ... 
    </lf>
    <cdl>
        <pos>2</pos>
        ... more elements ... 
    </cdl>
</lmt>

currently both seem to validate. I've tried both ./*/pos and .//pos for the selector, but either cause the first example to fail validation.


Solution

  • If you want every B within an element A to have a unique value for C then your uniqueness constraint should be defined on element A, the selector expression should select B from A, and the field expression should select C from B.

    So in your case the constraint should be defined on the container element that you haven't shown us, which has lf and cdl as its children. The selection should be .//pos or perhaps ./*/pos, and the field should then be .