Reputation: 298828
I have an XML structure similar to this:
<root>
<hierarchy1>
<foo id="foo1" /> <!-- id is of type id -->
<bar id="bar1" /> <!-- id is of type id -->
</hierarchy1>
<hierarchy2>
<foohandler ref="foo1" /> <!-- ref is of type idref -->
<barhandler ref="bar1" /> <!-- ref is of type idref -->
</hierarchy2>
</root>
I.e. I have different types of Objects that have ids and I have different types of target Objects that need to reference these IDs using IDREF.
Is there a way to ensure that the IDREF is of the correct expected type, i.e.
<foohandler ref="foo1" />
is valid whereas<foohandler ref="bar1" />
isn't?Upvotes: 2
Views: 749
Reputation: 10121
I've almost posted an answer which used pattern based restrictions (foo[0-9]+, etc.) to achieve what the OP asked. However before posting I found out about keys and keyrefs, which seemed to be the solution. So I came up with the following schema; but, at first it didn't work because of a silly namespace declaration issue. I'm posting it primarily, because I didn't know how to do this before either and I was going crazy, because I knew I'm almost there.
<?xml version="1.0" encoding="UTF-8" ?>
<xs:schema xmlns="http://stackoverflow.com"
xmlns:so="http://stackoverflow.com"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://stackoverflow.com"
attributeFormDefault="qualified"
elementFormDefault="qualified">
<xs:element name="root" type="rootType">
<xs:key name="fooKey">
<xs:selector xpath="so:hierarchy1/so:foo"/>
<xs:field xpath="@so:key"/>
</xs:key>
<xs:key name="barKey">
<xs:selector xpath="so:hierarchy1/so:bar"/>
<xs:field xpath="@so:key"/>
</xs:key>
<xs:keyref name="fooKeyref" refer="fooKey">
<xs:selector xpath="so:hierarchy2/so:foohandler"/>
<xs:field xpath="@so:keyref"/>
</xs:keyref>
<xs:keyref name="barKeyref" refer="barKey">
<xs:selector xpath="so:hierarchy2/so:barhandler"/>
<xs:field xpath="@so:keyref"/>
</xs:keyref>
</xs:element>
<xs:complexType name="rootType">
<xs:sequence>
<xs:element name="hierarchy1" type="hierarchy1Type"/>
<xs:element name="hierarchy2" type="hierarchy2Type"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="hierarchy1Type">
<xs:sequence>
<xs:element name="foo" type="fooType"/>
<xs:element name="bar" type="barType"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="hierarchy2Type">
<xs:sequence>
<xs:element name="foohandler" type="foohandlerType"/>
<xs:element name="barhandler" type="barhandlerType"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="fooType">
<xs:attribute name="key" type="xs:integer"/>
</xs:complexType>
<xs:complexType name="barType">
<xs:attribute name="key" type="xs:integer"/>
</xs:complexType>
<xs:complexType name="foohandlerType">
<xs:attribute name="keyref" type="xs:integer"/>
</xs:complexType>
<xs:complexType name="barhandlerType">
<xs:attribute name="keyref" type="xs:integer"/>
</xs:complexType>
</xs:schema>
The schema above validates the XML document below.
<?xml version="1.0" encoding="UTF-8"?>
<so:root xmlns:so="http://stackoverflow.com"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://stackoverflow.com a.xsd">
<so:hierarchy1>
<so:foo so:key="1"/>
<so:bar so:key="2"/>
</so:hierarchy1>
<so:hierarchy2>
<so:foohandler so:keyref="1"/>
<so:barhandler so:keyref="2"/>
</so:hierarchy2>
</so:root>
If <so:barhandler so:keyref="2"/>
is changed to <so:barhandler so:keyref="1"/>
or <so:barhandler so:keyref="3"/>
the document becomes invalid.
The catch here is that without specifying the namespace xmlns:so="http://stackoverflow.com"
and using this same namepsace in the xpath
attribute of xs:selector
and xs:field
some parsers won't care about the integrity of the document.
Eclipse's XML parser/validator and this online tool didn't give a crap about my key, keyref declarations until I specified which namespace should the XPath expressions refer.
The bottom lime could be use namespaces everyhwere?
This answer lead me to my relevation.
Upvotes: 2
Reputation: 163272
Instead of ID/IDREF use xs:key/xs:keyref. I'll leave you to look up the details; ask again if you get stuck.
Upvotes: 2