Optional key in XSD
key, xsd
Solution
Use xsd:unique; unlike a key, its matched value is either unique or nil (nil or not present).
Example:
<?xml version="1.0" encoding="utf-8" ?>
<!-- XML Schema generated by QTAssistant/XSD Module (http://www.paschidev.com) -->
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:element name="root">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="uk" maxOccurs="unbounded">
<xsd:complexType>
<xsd:attribute name="name" type="xsd:string"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="fk" maxOccurs="unbounded">
<xsd:complexType>
<xsd:attribute name="name" type="xsd:string"/>
</xsd:complexType>
</xsd:element>
</xsd:sequence>
</xsd:complexType>
<xsd:unique name="uq">
<xsd:selector xpath="uk"/>
<xsd:field xpath="@name"/>
</xsd:unique>
<xsd:keyref name="fk" refer="uq">
<xsd:selector xpath="fk"/>
<xsd:field xpath="@name"/>
</xsd:keyref>
</xsd:element>
</xsd:schema>
Sample (valid) XML:
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<!-- Sample XML generated by QTAssistant (http://www.paschidev.com) -->
<root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<uk name="name1"/>
<uk />
<fk/>
<fk name="name1"/>
</root>
Problem
I've created a `key`/`keyref` on the root element in order to create document-wide uniqueness based on the specified element. Therefore, via `.//foo/@name` every occurrence of `@name` across all instances of `foo` must be unique; likewise for `.//bar/@name`. This seems to be working fine. These are referenced by `.//foo-ref/@name-ref` and `.//bar-ref/@name-ref` respectively, also defined at the root node. However, I've gathered that one cannot create an optional key, and this is presenting a bit of a problem. Semantically, by the nature of the conforming documents, a key is not required on every single instance of `foo` or `bar`. The instances of `foo-ref/@name-ref` would obviously need to target an existing `foo/@name`, but it isn't semantically invalid for a `foo` to be without a `@name`. Is there any work-around for this? I don't like the idea of consumers having to define a key for every single element, when reasonably only a handful will need them. Here's the example schema (of course, I'm not deploying some `foobar` schema, but the structure is identical; this is just a testing schema I've been toying with) ``` <xs:schema elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:complexType name="ref"> <xs:attribute name="name-ref" type="xs:string" use="required" /> </xs:complexType> <xs:complexType name="obj"> <xs:attribute name="name" type="xs:string" use="optional" /> </xs:complexType> <xs:complexType name="foo"> <xs:complexContent> <xs:extension base="obj"> <xs:sequence> <xs:choice maxOccurs="unbounded"> <xs:element name="foo" type="foo" /> <xs:element name="bar" type="bar" /> <xs:element name="foo-ref" type="foo-ref" /> <xs:element name="bar-ref" type="bar-ref" /> </xs:choice> </xs:sequence> </xs:extension> </xs:complexContent> </xs:complexType> <xs:complexType name="foo-ref"> <xs:complexContent> <xs:extension base="ref" /> </xs:complexContent> </xs:complexType> <xs:complexType name="bar"> <xs:complexContent> <xs:extension base="obj"> <xs:sequence> <xs:choice maxOccurs="unbounded"> <xs:element name="bar" type="bar" /> <xs:element name="qux" type="qux" /> <xs:element name="bar-ref" type="bar-ref" /> </xs:choice> </xs:sequence> </xs:extension> </xs:complexContent> </xs:complexType> <xs:complexType name="bar-ref"> <xs:complexContent> <xs:extension base="ref" /> </xs:complexContent> </xs:complexType> <xs:complexType name="qux"> <xs:simpleContent> <xs:extension base="xs:string" /> </xs:simpleContent> </xs:complexType> <xs:element name="root"> <xs:complexType> <xs:sequence> <xs:element name="foo" type="foo" maxOccurs="unbounded" /> </xs:sequence> </xs:complexType> <xs:key name="foo"> <xs:selector xpath=".//foo" /> <xs:field xpath="@name" /> </xs:key> <xs:key name="bar"> <xs:selector xpath=".//bar" /> <xs:field xpath="@name" /> </xs:key> <xs:keyref name="foo-ref" refer="foo"> <xs:selector xpath=".//foo-ref" /> <xs:field xpath="@name-ref" /> </xs:keyref> <xs:keyref name="bar-ref" refer="bar"> <xs:selector xpath=".//bar-ref" /> <xs:field xpath="@name-ref" /> </xs:keyref> </xs:element> </xs:schema> ``` Addendum Just following up with my revisions thanks to @PetruGardea. So `unique` can be referenced by a `keyref`, who knew? (not me apparently) ``` <xs:element name="root"> <xs:complexType> <xs:sequence> <xs:element name="foo" type="foo" maxOccurs="unbounded" /> </xs:sequence> </xs:complexType> <xs:keyref name="foo-ref" refer="foo"> <xs:selector xpath=".//foo-ref" /> <xs:field xpath="@name-ref" /> </xs:keyref> <xs:keyref name="bar-ref" refer="bar"> <xs:selector xpath=".//bar-ref" /> <xs:field xpath="@name-ref" /> </xs:keyref> <!-- the use of xs:unique here, in lieu of xs:key allows for nullable "keys", retaining referential integrity with the above defined keyrefs. awesome possum. --> <xs:unique name="foo"> <xs:selector xpath=".//foo" /> <xs:field xpath="@name" /> </xs:unique> <xs:unique name="bar"> <xs:selector xpath=".//bar" /> <xs:field xpath="@name" /> </xs:unique> </xs:element> ```