As we have seen in the previous section, XML Schema allows a thorough validation of XML instance files. The type extension mechanism is very powerful but its XML format is not user-friendly, especially for complex embedding of sequences and choices. This is why the graphical editing of schemas, provided by editors such as XMLSpy and <oXygen/>, is very useful. In fact when it comes to ease of use, the DTD grammar-like format is much more convenient. In order to get the best of both worlds, an alternative Schema notation has been suggested which is called RELAX NG (REgular LAnguage for XML, New Generation). It features a simpler, intuitive notation to define schemas. RELAX NG is based on the same mathematical theory underlying regular expressions but adapted to the XML context. The mathematical foundations are both simpler and more powerful than the ones of the XML Schema.
Table 3.3. RELAX NG Compact syntax reminder
Compact Syntax (RNC) | XML Syntax (RNG) | |
---|---|---|
{default? namespace id=URI | datatypes id=URI}* { start=pattern | id=pattern }* |
<grammar> {<start> pattern </start> |<define name="NCName">pattern+</define>}* </grammar> |
|
Patterns | ||
element QName «{» pattern «}» |
<element name="QName">pattern+</element> |
|
attribute QName «{» pattern «}» |
<attribute name="QName">pattern+</attribute> |
|
pattern{«,» pattern}+ |
<group name="QName">pattern+</group> |
|
pattern{«&» pattern}+ |
<interleave name="QName">pattern+</interleave> |
|
pattern{«|» pattern}+ |
<choice name="QName">pattern+</choice> |
|
pattern«?»
|
<optional name="QName">pattern+</optional> |
|
pattern«*»
|
<zeroOrMore name="QName">pattern+</zeroOrMore> |
|
pattern«+»
|
<oneOrMore name="QName">pattern+</oneOrMore> |
|
mixed «{» pattern «}» |
<mixed name="QName">pattern+</mixed> |
|
id
|
<ref name="NCName"/> |
|
empty
|
<empty/>
|
|
text
|
<text/>
|
|
data TypeValue |
<value {name="NCName"}?>string+</value> |
|
data TypeValue «{»{id=value}* «}» |
<data {type="NCName"}?> {<param name="NCName">string</param>}* </data> |
Reminder of the RELAX NG Compact and
RELAX NG syntax used in our examples. The top cells
of the table specify the start of the file for RELAX NG Compact and the root element for
RELAX NG. Each line of the bottom part of the table is a different pattern that can be
combined almost freely with the others. The corresponding RELAX NG Compact and RELAX NG
elements appear on the same line within the bottom cell of the table.
Like we did in Table 3.1, we put chevrons around terminal
symbols that appear in the regular expression syntax of RELAX NG Compact. The chevrons should
not appear in the RELAX NG Compact grammar.
In RELAX NG Compact, dataTypeName
can be NCName
,
string
or token
.
RELAX NG has two equivalent syntaxes: one is XML-based and the other (called compact) is more convenient because it allows grammar-like definitions. Eric van der Vlist[59] has written an excellent book explaining both notations in detail. First, he introduces the XML patterns, the theoretical foundations of the formalism, that are combined into ordered and unordered groups and used in choices among alternatives. He then shows how the compact notation can simplify XML notation. In this report, we use the compact notation to develop the RELAX NG schemas. Most validators can deal directly with the compact notation. Example 3.6, a RELAX NG compact notation schema for our cellar book, looks more intuitive than the equivalent XML Schema of Example 3.3. As can be seen in Table 3.3, the structure of RELAX NG Compact definitions is quite regular and simple: a definition is simply a name followed by an equal sign and a pattern definition.
The Trang automatic Schema converter [16] can be used to obtain an XML version; the associated web site of this book shows the resulting RELAX NG version corresponding to the RELAX NG Compact given here.
A pattern can start either with the keyword
element
or
attribute
followed
by another pattern within braces. Patterns can be combined sequentially (with a comma), with
alternatives (with a vertical bar) or by interleaving (with an ampersand). This last case
means that all patterns must occur but not necessarily in order. A pattern can also be
qualified as optional, appear zero or more times or once or more. Mixed patterns allow text
elements to appear between patterns. A reference to another pattern is indicated by simply
giving its name (id).
empty
means that the
content of the element must be empty.
text
corresponds to
any number of text nodes in the instance document. Specifying a value (usually within
braces) means that the element in the document should match this value. It is also possible
to specify facets (in the XML Schema sense) to a type with a list of triples of the form: the
name of the facet, an equal sign and then the value of the facet.
In Example 3.6, we can see examples of element definitions (line 8‑, line 18‑
and
line 24‑
). A definition can also be a comma-separated
sequence of patterns (line 31‑
and line 37‑
). We use it here for type definitions but the concept is more
general and can be applied to any kind of definition. The content of a definition starts
with the keyword
attribute
or element
followed by its name and the
type of its content between braces. Similarly to the regular expressions conventions
described in Table B.1. If the element separator is
&
(such as for name-element
), it indicates an
interleave, meaning that elements in the pattern are unordered. In this case, it means
that the parts of the name
can appear in any order, any of them being optional
because they are followed by a ?
. This is a slight difference from the syntax
allowed for a name
element as defined by the DTD (Example 3.1) and XML Schema (Example 3.3), in
which the only way to indicate this constraint would be to enumerate all possible orderings
of first
, family
and initial
. The root element of the
schema is defined by the rule associated with the start
keyword.
When there are no constraints on the string inside an element, then the type is
text
, but it can also refer to the built-in data types of XML Schema
(see wine
). Restrictions can also be added on types by surrounding them with
braces: patterns (see PostalCodeCA
) or enumerations (see province
element in Address
).
Example 3.6
includes (line 4‑) the definitions of the wine catalog in a
separate file (Example 3.7).
Because the included file also has a
start
symbol, we override its definition by the definition in braces after the name of the file.
Any other included definition could be overridden in this way. There are many other
possibilities to combine definitions of many files but we will not present them in this
document. One should consult
[59]
(Chapter 10) for more details.
Namespace prefixes are declared by a definition following the keyword
namespace
(line 1‑). To use the predefined types of XML Schema (Figure 3.3),
we similarly declare the prefix used for referring to them. RELAX NG does not implement the notions of XML Schema
keys
and
keyref
so that one must resort to the simpler (but often sufficient) notion of DTD
ID
and
IDREF
explained in
Section 3.1.
Example 3.6. [CellarBook.rnc
] RELAX NG Compact schema for the cellar book to validate
Example 2.2.
Compare this file with Example 3.3.
1 namespace cat = "http://www.iro.umontreal.ca/lapalme/wine-catalog"datatypes xs = "http://www.w3.org/2001/XMLSchema-datatypes"
include "WineCatalog.rnc" {
5 start = cellar-book
} cellar = element cellar {
element wine {
10 attribute code {xs:IDREF}, element purchaseDate {xs:date}, element quantity {xs:nonNegativeInteger}, element rating {attribute stars {xs:positiveInteger}?}?, element comment {Comment}? 15 }* } name = element name {
element first {text}? 20 & element family {text}? & element initial {text}? } cellar-book = element cellar-book {
25 wine-catalog, element owner {Owner}, element location {Address}?, cellar } 30 Address = element street {text},
element city {text}, element province {"AB"|"BC"|"MB"|"NB"|"NL"|"NT"| "NS"|"NU"|"ON"|"QC"|"SK"|"YT"}, 35 element postal-code {PostalCodeCA} Owner = name, Address
PostalCodeCA = xs:string {pattern="[A-Z][0-9][A-Z] [0-9][A-Z][0-9]"}
40
|
Defines the namespace prefix used in the catalog. |
|
Defines the namespace prefix corresponding to the standard XML datatypes. |
|
Includes the schema for the wine catalog. |
|
Defines the start symbol for this file by redefining the start symbol imported from the wine catalog file. |
|
The cellar element is a possibly empty list of wine elements. |
|
A wine element is composed of a mandatory code attribute, a date of purchase, a quantity given by a non-negative integer, an optional rating (an empty element with an attribute indicating the number of stars) and finally an optional comment. |
|
A name is an interleaving of a first name, family name and initial (all of
them being optional). This means that these three elements can occur in any
order but not more than once. Interleaving is a of expressing that elements
can appear in any order. Its use here corresponds to the
|
|
A
|
|
Pattern for the street, the city name, a Canadian province name (the list of available values that can be defined directly). |
|
A pattern combining an element and a pattern. |
|
A pattern corresponding to a standard type with a constraint expressed as a regular expression. Here it corresponds to the Canadian postal codes. |
The beginning of
Example 3.7
illustrates how to declare a default namespace for the elements of this file, included in
Example 3.6
(line 4‑). The definition of elements follows the same
principles explained for the cellar book.
wine-catalog
must add an optional attribute
xml:base
that is used by the XML processor during the file inclusion process. It is needed in
order to ensure the integrity of both the including and included file. Element
Format
shows that comments starts with a
#
and go up to the end of the line.
Example 3.7. [WineCatalog.rnc
] RELAX NG Compact schema for the wine catalog to
validate
Example 2.3
This file can be compared with Example 3.4.
1 default namespace = "http://www.iro.umontreal.ca/lapalme/wine-catalog" datatypes xs = "http://www.w3.org/2001/XMLSchema-datatypes" start = wine-catalog 5 wine-catalog = element wine-catalog {# needed because this schema will be imported attribute xml:base{text}?, wine* 10 } wine = element wine{
attribute name {text}, attribute appellation {text}, 15 attribute classification {text}, attribute code {xs:ID}, attribute format {Format}, properties, origin, 20 ( element tasting-note {Comment} | element food-pairing {Comment} | comment )*, element price {xs:decimal}, 25 element year {xs:gYear} } properties = element properties {
element color {Color}, 30 element alcoholic-strength {Percentage}, element nature {text}? } origin = element origin {
35 element country {text}, element region {text}, element producer {text} } 40 Format = "375ml" | "750ml" | "1l"
| "magnum" # 1.5 litres | "jeroboam" # 3 litres | "rehoboam" # 4.5 litres | "mathusalem" # 6 litres 45 | "salmanazar" # 9 litres | "balthazar" # 12 litres | "nabuchodonosor" # 15 litres Comment = mixed {element emph {text}* & element bold {text}*}
50 comment = element comment{Comment} Color = "red" | "white" | "rosé"
Percentage = xs:decimal {
55 minInclusive = "0" maxInclusive = "100" fractionDigits ="2"}
|
The wine catalog is a list of
|
|
A pattern defining all the information related to a given wine. |
|
A pattern describing some properties of a wine. |
|
Informations about the origin of a wine. |
|
List of allowable values for wine format. |
|
A comment is text interspersed with
|
|
List of allowable values for the color of wines. |
|
A percentage based on standard XML types and constraint attributes. |