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

Key

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

1. XML Schema - key

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

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>

Invalid document
The document is not valid, because the attribute "id" is missing (element /root/a[1]). The "key" requires the value to be unique and 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:key name="myId">
      <xsd:selector xpath="./a"/>
      <xsd:field xpath="@id"/>
    </xsd:key>
  </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>

Invalid document
We have not specified, that the attribute is optional, so it is required. Relax NG schema will report an error.


<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">
          <attribute name="id">
            <data type="NCName"/>
          </attribute>
          <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>