I'm trying to define some foreign key constraints on an XML schema using xs:key and xs:keyref definitions. I want the structure of the document to be hierarchical in the following way:
<?xml version="1.0" encoding="UTF-8"?>
<tns:root xmlns:tns="http://www.example.org/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.example.org/ SampleSchema.xsd ">
<parent parentKey="parent1">
<child childKey="child1"/>
<child childKey="child2"/>
</parent>
<parent parentKey="parent2">
<child childKey="child1"/>
<child childKey="child2"/>
</parent>
<referrer parentRef="parent1" childRef="child2"/>
</tns:root>
A each parent has a (globally) unique key, defined by parentKey. Each child has key defined by childKey, but childKey is only unique within the scope of its containing parent.
There is then a list of referrers with foreign key references to a particular parent and child.
I'm able to define the keys as I want, simply by putting them on the correct element: the parentKey constraint on the root element, and the childKey constraint on the parent element. I can also define the keyref to parentKey without difficulty.
The problems arise when trying to define a keyref to childKey. I tried defining a simple keyref on the root element to childKey, but that doesn't work since I see no way to select only the child elements under the proper parent subtree. (The Eclipse validator, at least, always simply validates against the content of the last parent subtree in the document...).
I then tried defining a composite key (on root), with:
- selector = parent
- field = @parentKey
- field = child/@childKey
This fails if there is more than one child defined under the parent. That is the correct behavior based on the XSD 1.1 spec, section 3.11.4, item 3, which states that the key has to match at most one node per field definition.
Just to reiterate: if I force childKeys to be globally unique, this is easy to implement; the difficulty is around referencing locally unique childKeys.
Any XSD masters out there have an idea?
For reference, here is a sample XSD, with a failed childKey keyref commented out:
<?xml version="1.0" encoding="UTF-8"?>
<schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.example.org/" xmlns:tns="http://www.example.org/" elementFormDefault="unqualified">
<element name="root">
<complexType>
<sequence>
<element name="parent" maxOccurs="unbounded" minOccurs="1">
<complexType>
<sequence>
<element name="child" maxOccurs="unbounded" minOccurs="1">
<complexType>
<attribute name="childKey" type="string" use="required"/>
</complexType>
</element>
</sequence>
<attribute name="parentKey" type="string" use="required"/>
</complexType>
<key name="childKeyDef">
<selector xpath="child"/>
<field xpath="@childKey"/>
</key>
</element>
<element name="referrer" maxOccurs="unbounded" minOccurs="1">
<complexType>
<attribute name="parentRef" type="string"/>
<attribute name="childRef" type="string"/>
</complexType>
</element>
</sequence>
</complexType>
<key name="parentKeyDef">
<selector xpath="parent"/>
<field xpath="@parentKey"/>
</key>
<keyref name="parentKeyRef" refer="tns:parentKeyDef">
<selector xpath="referrers"/>
<field xpath="@parentRef"/>
</keyref>
<!-- <keyref name="childKeyRef" refer="tns:childKeyDef">-->
<!-- <selector xpath="referrers"/>-->
<!-- <field xpath="@childRef"/>-->
<!-- </keyref>-->
</element>
</schema>
See Question&Answers more detail:os