Sean Patrick Floyd
Sean Patrick Floyd

Reputation: 298828

In XSD schema, how to distinguish between different types of IDREFs

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.

Upvotes: 2

Views: 749

Answers (2)

Koh&#225;nyi R&#243;bert
Koh&#225;nyi R&#243;bert

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

Michael Kay
Michael Kay

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

Related Questions