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 |
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>
|
|
| 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>