3.3. RELAX NG

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‑5, line 18‑7 and line 24‑8). A definition can also be a comma-separated sequence of patterns (line 31‑9 and line 37‑10). 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‑3) 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‑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"   (1)
    datatypes xs = "http://www.w3.org/2001/XMLSchema-datatypes"          (2)
    
    include "WineCatalog.rnc" {                                          (3)
  5     start = cellar-book                                              (4)
    }
    
    cellar = element cellar {                                            (5)
                element wine {                                           (6)
 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 {                                                (7)
                       element first {text}?
 20                  & element family {text}?
                     & element initial {text}?
                   }
                   
    cellar-book =  element cellar-book {                                 (8)
 25                   wine-catalog,
                      element owner {Owner},
                      element location {Address}?,
                      cellar
                   }
 30          
    Address = element street {text},                                     (9)
              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                                                (10)
    
    PostalCodeCA = xs:string {pattern="[A-Z][0-9][A-Z] [0-9][A-Z][0-9]"} (11)
 40 

1

Defines the namespace prefix used in the catalog.

2

Defines the namespace prefix corresponding to the standard XML datatypes.

3

Includes the schema for the wine catalog.

4

Defines the start symbol for this file by redefining the start symbol imported from the wine catalog file.

5

The cellar element is a possibly empty list of wine elements.

6

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.

7

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 xsd:all element but in fact, it is more general and allows the unordered combination of any subgroups of elements.

8

A cellar-book element contains the wine-catalog, a description of the owner, the optional location of the cellar and the cellar-element itself defined on line 8‑5. Owner and Address are themselves patterns.

9

Pattern for the street, the city name, a Canadian province name (the list of available values that can be defined directly).

10

A pattern combining an element and a pattern.

11

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‑3). 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 {                                (1)
                      # needed because this schema will be imported
                      attribute xml:base{text}?, 
                      wine*
 10                }
    
    wine = element wine{                                                 (2)
               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 {                                    (3)
                     element color {Color},
 30                  element alcoholic-strength {Percentage},
                     element nature {text}?
                 }
    
    origin = element origin {                                            (4)
 35                  element country {text},
                     element region {text},
                     element producer {text}
              }
    
 40 Format = "375ml" | "750ml" | "1l"                                    (5)
             | "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}*}        (6)
 50 comment = element comment{Comment}
    
    Color = "red" | "white" | "rosé"                                     (7)
    
    Percentage = xs:decimal {                                            (8)
 55               minInclusive = "0"
                  maxInclusive = "100"
                  fractionDigits ="2"}

1

The wine catalog is a list of wine elements. An xml:base attribute is added to schema to take into account that it will be added during the importing process.

2

A pattern defining all the information related to a given wine.

3

A pattern describing some properties of a wine.

4

Informations about the origin of a wine.

5

List of allowable values for wine format.

6

A comment is text interspersed with emph and bold elements which also contain text. Note that this definition does not allow embedding of emph and bold elements.

7

List of allowable values for the color of wines.

8

A percentage based on standard XML types and constraint attributes.