XML.com: XML From the Inside Out
oreilly.comSafari Bookshelf.Conferences.

advertisement

Relax NG, Compared
by Eric van der Vlist | Pages: 1, 2, 3, 4, 5

Slicing the Schema

[ Corresponding chapter for W3C XML Schema]

Table of Contents

Introducing Our First Schema

Slicing the Schema

Defining Named Types

Groups, Compositors and Derivation

Content Types

Building Usable -- and Reusable -- Schemas

Namespaces

With W3C XML Schema, we saw how we could slice the schema using references to global elements and attributes. The way to do it with RELAX NG is similar, yet different: RELAX NG does not have the notion of global or local elements but allows the definition and referencing of implicit containers that act like the W3C XML Schema element and attribute groups, while being more flexible.

Definitions are made using "define" elements and references with "ref" elements. These constructs are almost semantically neutral: you can include almost anything in a define and the reference will be replaced by stuff which you included in the "define". There is still just enough semantics to allow recursive constructions, but a "define" can be used indiscriminately to include an element, an attribute, a group of elements, a group of attributes, a group of elements and attributes, and so on.

If we want to mimic the slicing of our schema into elements and attributes, we can use this mechanism to create a definition isolating each element and attribute, such as:

 <define name="isbn">
  <attribute name="isbn">
   <data type="nonNegativeInteger"/>
  </attribute>
 </define>

 <define name="title">
  <element name="title">
  <data type="token"/>
  </element>
 </define>

And we can use these definitions to construct elements, such as

 <define name="character">
  <element name="character">
   <ref name="name"/>
    <optional>
     <ref name="friend-of"/>
    </optional>
    <ref name="since"/>
    <ref name="qualification"/>
  </element>
 </define>

 <element name="book">
  <ref name="isbn"/>
  <ref name="title"/>
  <ref name="author"/>
  <zeroOrMore>
   <ref name="character"/>
  </zeroOrMore>
 </element>
Comment on this article Comments or questions for the author? Share them in our forum.
Post your comments

It is important to note that although this construction can be used to imitate the behavior of W3C XML Schema global elements and attributes, RELAX NG's define and ref are not element and attribute definitions, but named patterns, making them much more flexible. In the snippet just shown above, I could have chosen for instance to include the cardinality of the character element within the book element by moving the "zeroOrMore" from the reference to the definition and written

 <define name="characters">
  <zeroOrMore>
   <element name="character">
    <ref name="name"/>
    <optional>
     <ref name="friend-of"/>
    </optional>
    <ref name="since"/>
     <ref name="qualification"/>
   </element>
  </zeroOrMore>
 </define>

 <element name="book">
  <ref name="isbn"/>
  <ref name="title"/>
  <ref name="author"/>
  <ref name="characters"/>
 </element>

The flat schema, comparable to our W3C XML Schema would be

<?xml version="1.0" encoding="UTF-8"?>
<grammar 
 xmlns="http://relaxng.org/ns/structure/1.0"
 datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes"
 >
 <define name="isbn">
  <attribute name="isbn">
  <data type="nonNegativeInteger"/>
  </attribute>
 </define>

 <define name="title">
  <element name="title">
  <data type="token"/>
  </element>
 </define>

 <define name="author">
  <element name="author">
   <data type="token"/>
  </element>
 </define>

 <define name="name">
  <element name="name">
   <data type="token"/>
  </element>
 </define>

 <define name="friend-of">
  <element name="friend-of">
   <data type="token"/>
  </element>
 </define>

 <define name="since">
  <element name="since">
   <data type="date"/>
  </element>
 </define>

 <define name="qualification">
  <element name="qualification">
   <data type="token"/>
  </element>
 </define>

 <define name="character">
  <element name="character">
   <ref name="name"/>
   <optional>
    <ref name="friend-of"/>
   </optional>
   <ref name="since"/>
   <ref name="qualification"/>
  </element>
 </define>
 
<start>
 <element name="book">
  <ref name="isbn"/>
  <ref name="title"/>
  <ref name="author"/>
  <zeroOrMore>
   <ref name="character"/>
  </zeroOrMore>
  </element>
 </start>
</grammar>

Defining Named Types

[ Corresponding chapter for W3C XML Schema]

RELAX NG is all about patterns and has no notion of "simple types" or "complex types". Here again, we will need to use define and ref to simulate these W3C XML Schema features. The closest way to simulate a datatype is to define the pattern corresponding to the content model of an element or attribute. This can be done for simple types and, depending on the datatype library and implementation you are using, you may even have access to the W3C XML Schema facets through type "parameters".

 <define name="nameType">
  <data type="token">
   <param name="maxLength">32</param>
  </data>
 </define>
 
 <define name="isbnType">
  <data type="nonNegativeInteger">
   <param name="pattern">[0-9]{10}</param>
  </data>
 </define>

Pseudo-complex types can be defined in the same way.

 <define name="bookType">
  <attribute name="isbn">
   <ref name="isbnType"/>
  </attribute>
  <element name="title">
   <ref name="titleType"/>
  </element>
  <element name="author">
   <ref name="authorType"/>
  </element>
  <zeroOrMore>
   <element name="character">
    <ref name="characterType"/>
   </element>
  </zeroOrMore>
 </define>

The full schema using exclusively this "style" would be

<?xml version="1.0" encoding="UTF-8"?>
<grammar 
 xmlns="http://relaxng.org/ns/structure/1.0"
 datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes"
 >
 <define name="isbnType">
  <data type="nonNegativeInteger">
   <param name="pattern">[0-9]{10}</param>
  </data>
 </define>

 <define name="titleType">
  <data type="token"/>
 </define>

 <define name="authorType">
  <data type="token"/>
 </define>

 <define name="nameType">
  <data type="token">
   <param name="maxLength">32</param>
  </data>
 </define>

 <define name="friend-ofType">
  <data type="token"/>
 </define>

 <define name="sinceType">
  <data type="date"/>
 </define>

 <define name="qualificationType">
  <data type="token"/>
 </define>

 <define name="characterType">
  <element name="name">
   <ref name="nameType"/>
  </element>
  <optional>
   <element name="friend-of">
    <ref name="friend-ofType"/>
   </element>
  </optional>
  <element name="since">
   <ref name="sinceType"/>
  </element>
  <element name="qualification">
   <ref name="qualificationType"/>
  </element>
 </define>

 <define name="bookType">
  <attribute name="isbn">
   <ref name="isbnType"/>
  </attribute>
  <element name="title">
   <ref name="titleType"/>
  </element>
  <element name="author">
   <ref name="authorType"/>
  </element>
  <zeroOrMore>
   <element name="character">
    <ref name="characterType"/>
   </element>
  </zeroOrMore>
 </define>

 <start>
  <element name="book">
   <ref name="bookType"/>
  </element>
 </start>
</grammar>

Pages: 1, 2, 3, 4, 5

Next Pagearrow