ZVON > Tutorials > XML Schema and Relax NG Tutorial
Index | >> Example 1 / 6 << | Prev | Next |
Contents > Unique and key > Uniqueness

Uniqueness

  1. XML Schema - unique
  2. Relax NG + Schematron
XML Schema keys: unique

1. XML Schema - unique

We will use "unique" element to define, that the elements "a" under "root" element must have unique value of "id" attribute.

Valid document


<root xsi:noNamespaceSchemaLocation="correct_0.xsd" xmlns="" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" >
  <a id="x"/>
  <a id="y"/>
  <a id="z"/>
</root>

Valid document
The document is valid too, because "id" attribute is not required (default minOccurs for attributes is 0) and the "unique" requires the value to be unique, but not necessarily present.


<root xsi:noNamespaceSchemaLocation="correct_0.xsd" xmlns="" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" >
  <a/>
  <a id="y"/>
  <a id="z"/>
</root>

Invalid document
The id "y" is not unique.


<root xsi:noNamespaceSchemaLocation="correct_0.xsd" xmlns="" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" >
  <a id="x"/>
  <a id="y"/>
  <a id="y"/>
</root>

Correct XML Schema (correct_0.xsd)
The "xpath" attribute of "selector" and "field" elements is a restricted XPath relative to the element in which it is declared (here it is relative to the "root" element).


<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" >

  <xsd:element name="root" type="myList">
    <xsd:unique name="myId">
      <xsd:selector xpath="./a"/>
      <xsd:field xpath="@id"/>
    </xsd:unique>
  </xsd:element>

  <xsd:complexType name="myList">
    <xsd:sequence minOccurs="1">
      <xsd:element name="a" minOccurs="1" maxOccurs="unbounded">
        <xsd:complexType>
          <xsd:attribute name="id" type="xsd:NCName"/>
        </xsd:complexType>
      </xsd:element>
    </xsd:sequence>
  </xsd:complexType>
</xsd:schema>

2. Relax NG + Schematron

There is no such mechanism in Relax NG, but we can combine Relax NG and Schematron schemas.

Valid document


<root xmlns="">
  <a id="x"/>
  <a id="y"/>
  <a id="z"/>
</root>

Valid document
We have specified, that the attribute is optional (if not, it would be required). Thus both Relax NG and Schematron schemas will accept this file ("id" is not unique).


<root xmlns="">
  <a/>
  <a id="y"/>
  <a id="z"/>
</root>

Invalid document
The id "y" is not unique. This won't be reported by the Relax NG schema, but by the Schematron schema.


<root xmlns="">
  <a id="x"/>
  <a id="y"/>
  <a id="y"/>
</root>

Correct Relax NG schema (correctRelax_0.rng)
This Relax NG will check tree structure, and verify the datatypes.


<grammar datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes" ns="" xmlns="http://relaxng.org/ns/structure/1.0" >

  <start>
    <element name="root">
      <oneOrMore>
        <element name="a">
          <optional>
            <attribute name="id">
              <data type="NCName"/>
            </attribute>
          </optional>
          <empty/>
        </element>
      </oneOrMore>
    </element>
  </start>
</grammar>

Correct Schematron schema
The Schematron rule below will check the uniqueness of the "a/@id" attribute. Warning - not all Schematron implementations might support function "current()" (it's XSLT, not XPath function).


<schema xmlns="http://www.ascc.net/xml/schematron" >
  <pattern name="Element 'a' must have unique 'id' attribute">
    <rule context="root/a/@id">
      <assert test="count(//@id[. = current()]) = 1"> Id not unique! </assert>
    </rule>
  </pattern>
</schema>