How to use unique and keyref properly in XML schema?
keyref, unique, xml, xsd
Solution
Unique constraints and keys are scoped at the `element` level - you need to put the constraint not inside each individual element, but inside the `access` element that is a common ancestor of them all.
<xs:element name="access" type="myaccess">
<xs:key name="user_id">
<xs:selector xpath="user" />
<xs:field xpath="@id" />
</xs:key>
<xs:key name="access_id">
<xs:selector xpath="building | building/door | building/door/gate" />
<xs:field xpath="@id" />
</xs:key>
<xs:keyref name="user_ref" refer="user_id">
<xs:selector xpath="authorization" />
<xs:field xpath="@idu" />
</xs:keyref>
<xs:keyref name="access_ref" refer="access_id">
<xs:selector xpath="authorization" />
<xs:field xpath="@idao" />
</xs:keyref>
</xs:element>
Problem
I have this XML schema but I don't know how to complete it in order to achieve what I need. I searched a lot online about unique and keyref usage, but all I can find are basic examples. This is my schema: ``` <xs:element name="access" type="myaccess" /> <xs:complexType name="myaccess"> <xs:sequence> <xs:element name="user" type="myuser" minOccurs="0" maxOccurs="unbounded"> <xs:unique name="u_idunique"> <xs:selector xpath="user" /> <xs:field xpath="@id" /> </xs:unique> </xs:element> <xs:element name="authorization" type="myauthorization" minOccurs="0" maxOccurs="unbounded"> <!-- HERE I WANT A KEYREF TO id attribute of user element --> <!-- HERE I WANT A KEYREF TO id attribute of building element OR door element --> </xs:element> <xs:element name="building" type="mybuilding" minOccurs="0" maxOccurs="unbounded" > <!-- I DON'T KNOW HOW TO SPECIFY THAT id of building, id of door and id of gate are in the same scope --> <xs:unique name="b_idunique"> <xs:selector xpath="building" /> <xs:field xpath="@id" /> </xs:unique> </xs:element> </xs:sequence> </xs:complexType> <xs:complexType name="myuser"> <xs:attribute name="id" type="my_id" use="required" /> <xs:attribute name="name" type="xs:string" use="required" /> <xs:attribute name="phone" type="my_string_numeric" use="required" /> </xs:complexType> <xs:complexType name="mybuilding"> <xs:sequence> <xs:element name="door" type="mydoor" minOccurs="0" maxOccurs="unbounded"> <!-- I DON'T KNOW HOW TO SPECIFY THAT id of building, id of door and id of gate are in the same scope --> <xs:unique name="d_idunique"> <xs:selector xpath="door" /> <xs:field xpath="@id" /> </xs:unique> </xs:element> </xs:sequence> <xs:attribute name="id" type="my_id" use="required" /> <xs:attribute name="name" type="xs:string" use="required" /> <xs:attribute name="country" type="xs:string" use="required" /> </xs:complexType> <xs:complexType name="mydoor"> <xs:sequence> <xs:element name="gate" type="mygate" maxOccurs="unbounded"> <!-- I DON'T KNOW HOW TO SPECIFY THAT id of building, id of door and id of gate are in the same scope --> <xs:unique name="g_idunique"> <xs:selector xpath="gate" /> <xs:field xpath="@id" /> </xs:unique> </xs:element> </xs:sequence> <xs:attribute name="id" type="my_id" use="required" /> <xs:attribute name="address" type="xs:string" use="required" /> <xs:attribute name="status" type="mystatus" default="DISABLED" /> </xs:complexType> <xs:complexType name="mygate"> <xs:attribute name="id" type="my_id" use="required" /> <xs:attribute name="type" type="mytype" use="required" /> <xs:attribute name="status" type="mystatus" default="DISABLED" /> </xs:complexType> <xs:complexType name="myauthorization"> <xs:sequence> <xs:element name="validityperiod" type="myvalidityperiod" /> </xs:sequence> <xs:attribute name="idu" type="my_id" use="required" /> <xs:attribute name="idao" type="my_id" use="required" /> </xs:complexType> <!-- OMITTED USELESS PART OF THE SCHEMA --> </xs:schema> ``` I have two problems: - I don't know how to specify that the id field of building, the id field of door and the id field of gate are in the same scope and I can't have 2 id equals (two building can't have the same id, but also a door and a building can't share the same id) - I don't know how to use correctly the keyref element. - I'd like that idu filed of authorization element is an id that is present in one of the user elements (see [*] below). - I'd like that the idao field of authorization element is an id that is present in one of the building elements OR one of the door elements. [*] I tried to write this, but it's not working: ``` <xs:keyref name="useridkeyref" refer="u_idunique"> <xs:selector xpath="authorization" /> <xs:field xpath="@idu" /> </xs:keyref> ``` I know this is not a short question and I thanks everyone in advance for reading it. I hope I can get some help. Thank you!