Relax NG, Compared
by Eric van der Vlist
|
Pages: 1, 2, 3, 4, 5
Groups, Compositors and Derivation
|
Table of Contents |
|
Introducing Our First Schema |
[ Corresponding chapter for W3C XML Schema]
Groups
Of course we can use RELAX NG's define and ref to simulate element and attribute groups and write
<define name="bookAttributes">
<attribute name="isbn">
<data type="nonNegativeInteger"/>
</attribute>
<optional>
<attribute name="available">
<data type="token"/>
</attribute>
</optional>
</define>
<define name="mainBookElements">
<element name="title">
<data type="token"/>
</element>
<element name="author">
<data type="token"/>
</element>
</define>
.../...
<element name="book">
<ref name="bookAttributes"/>
<ref name="mainBookElements"/>
<zeroOrMore>
<ref name="character"/>
</zeroOrMore>
</element>
Here again we have more flexibility since our pattern definition may mix both element and attribute definitions.
The W3C XML Schema element and attribute groups are the W3C XML
Schema features which are closest to RELAX NG patterns define
and ref: the advice given by Kohsuke Kawaguchi in his
article W3C XML
Schema Made Simple to avoid using W3C XML Schema complex types to
rely on element and attribute groups may be seen as a way to follow a
RELAX NG style in W3C XML Schema.
Compositors
|
|
| Post your comments |
As we've seen in all our examples up to now, a "sequence" compositor is implicit and the default behavior for RELAX NG.
Choices are defined using a choice element, and group elements can be used as containers:
<define name="nameTypes">
<choice>
<element name="name">
<data type="token"/>
</element>
<group>
<element name="firstName">
<data type="token"/>
</element>
<optional>
<element name="middleName">
<data type="token"/>
</element>
</optional>
<element name="lastName">
<data type="token"/>
</element>
</group>
</choice>
</define>
The choice element can also be used for simple types, giving a coherent way to define enumerations, independent of the datatype library in use.
<define name="availableType"> <choice> <value>stock</value> <value>order</value> <value>na</value> </choice> </define>
RELAX NG is free of most of the limitations of W3C XML Schema concerning non-determinism, and choice can be used to differentiate elements having the same name and different content models. For example, consider the following, which would allow a name to be either plain text or have three subelements.
<element name="name">
<choice>
<text/>
<group>
<element name="firstName">
<data type="token"/>
</element>
<optional>
<element name="middleName">
<data type="token"/>
</element>
</optional>
<element name="lastName">
<data type="token"/>
</element>
</group>
</choice>
</name>
Elements and attributes are managed, as far as possible, in a consistent way and choice can also be used to allow a value to be placed either in an attribute or in an element (this is something RDF permits, for example).
<element name="book"
<choice>
<attribute name="isbn">
<value type="integer"/>
</attribute>
<element name="isbn">
<value type="integer"/>
</element>
</choice>
.../...
</element>
The equivalent of W3C XML Schema xs:all element is the interleave element, which defines unordered lists of subelements. The interleave element has none of the xs:all limitations: we could use it in all our complex content definitions to define a schema where the order of the subelements would not be tested at all, which would not be possible with W3C XML Schema because of the "zeroOrMore" number of character elements included in the book element.
<?xml version="1.0" encoding="UTF-8"?>
<grammar
xmlns="http://relaxng.org/ns/structure/1.0">
<start>
<element name="book">
<interleave>
<attribute name="isbn">
<text/>
</attribute>
<element name="title">
<text/>
</element>
<element name="author">
<text/>
</element>
<zeroOrMore>
<element name="character">
<interleave>
<element name="name">
<text/>
</element>
<optional>
<element name="friend-of">
<text/>
</element>
</optional>
<element name="since">
<text/>
</element>
<element name="qualification">
<text/>
</element>
</interleave>
</element>
</zeroOrMore>
</interleave>
</element>
</start>
</grammar>
Derivation of simple types
The notion of simple types is imported from datatype libraries, and although predefined datatypes may be used to derive new types -- by restriction of predefined types and usage of parameters -- the result of such a derivation is considered a RELAX NG pattern, losing its semantic of simple type and cannot be derived by restriction any longer. Derivation by union is done using a choice element, and the equivalent of our W3C XML Schema example would be
<define name="isbnType">
<choice>
<data type="nonNegativeInteger">
<param name="pattern">[0-9]{10}</param>
</data>
<value>TBD</value>
<value>NA</value>
</choice>
</define>
Derivation by list can be done using the list element, which applies to simple types only. Unlike its W3C XML Schema counterpart, the RELAX NG list operator lets us combine several datatypes within a list. For example, to define a length with an optional unit, we could write
<define name="lengthType">
<list>
<data type="integer"/>
<optional>
<choice>
<value>pixel</value>
<value>in</value>
<value>cm</value>
</choice>
</optional>
</list>
</define>
On the other hand, RELAX NG doesn't provide the granularity available in W3C XML Schema to define cardinalities. So, to define a list of up to ten ISBN codes, we could take the loose route, and define a list of "zeroOrMore" isbnType:
<define name="isbnTypes"> <list> <zeroOrMore> <ref name="isbnType"/> </zeroOrMore> </list> </define>
Or we could explicitly (and verbosely) show the limit:
<define name="isbn10Types">
<list>
<optional>
<ref name="isbnType"/>
<optional>
<ref name="isbnType"/>
<optional>
<ref name="isbnType"/>
<optional>
<ref name="isbnType"/>
<optional>
<ref name="isbnType"/>
<optional>
<ref name="isbnType"/>
<optional>
<ref name="isbnType"/>
<optional>
<ref name="isbnType"/>
<optional>
<ref name="isbnType"/>
<optional>
<ref name="isbnType"/>
</optional>
</optional>
</optional>
</optional>
</optional>
</optional>
</optional>
</optional>
</optional>
</optional>
</list>
</define>