RELAX NG Tutorial

Working Draft 1 June 2001

This version:
Working Draft: 1 June 2001
Editor:
James Clark <jjc@jclark.com>

Copyright © The Organization for the Advancement of Structured Information Standards [OASIS] 2001. All Rights Reserved.

This document and translations of it may be copied and furnished to others, and derivative works that comment on or otherwise explain it or assist in its implementation may be prepared, copied, published and distributed, in whole or in part, without restriction of any kind, provided that the above copyright notice and this paragraph are included on all such copies and derivative works. However, this document itself may not be modified in any way, such as by removing the copyright notice or references to OASIS, except as needed for the purpose of developing OASIS specifications, in which case the procedures for copyrights defined in the OASIS Intellectual Property Rights document must be followed, or as required to translate it into languages other than English.

The limited permissions granted above are perpetual and will not be revoked by OASIS or its successors or assigns.

This document and the information contained herein is provided on an "AS IS" basis and OASIS DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.


Abstract

RELAX NG is a simple schema language for XML, based on RELAX and TREX. A RELAX NG schema specifies a pattern for the structure and content of an XML document. A RELAX NG schema thus identifies a class of XML documents consisting of those documents that match the pattern. A RELAX NG schema is itself an XML document.

Status of this Document

This is a working draft constructed by the editor. It is not an official committee work product and may not reflect the consensus opinion of the committee. Comments on this document may be sent to relax-ng-comment@lists.oasis-open.org.

Table of Contents

1 Getting started
2 Choice
3 Attributes
4 Named patterns
5 Datatyping
6 Enumerations
7 Lists
8 Interleaving
9 Modularity
9.1 Referencing external patterns
9.2 Merging grammars
10 Namespaces
10.1 Using the namespace attribute
10.2 Qualified names
11 Name classes
12 Cross references
13 Annotations
14 Nested grammars
15 Non-restrictions
16 Non-features
17 Differences from TREX

1. Getting started

Consider a simple XML representation of an email address book:

<addressBook>
  <card>
    <name>John Smith</name>
    <email>js@example.com</email>
  </card>
  <card>
    <name>Fred Bloggs</name>
    <email>fb@example.net</email>
  </card>
</addressBook>

The DTD would be as follows:

<!DOCTYPE addressBook [
<!ELEMENT addressBook (card*)>
<!ELEMENT card (name, email)>
<!ELEMENT name (#PCDATA)>
<!ELEMENT email (#PCDATA)>
]>

A RELAX NG pattern for this could be written as follows:

<element name="addressBook" xmlns="http://relaxng.org/ns/structure/0.9">
  <zeroOrMore>
    <element name="card">
      <element name="name">
        <text/>
      </element>
      <element name="email">
        <text/>
      </element>
    </element>
  </zeroOrMore>
</element>

If the addressBook is required to be non-empty, then we can use oneOrMore instead of zeroOrMore:

<element name="addressBook" xmlns="http://relaxng.org/ns/structure/0.9">
  <oneOrMore>
    <element name="card">
      <element name="name">
        <text/>
      </element>
      <element name="email">
        <text/>
      </element>
    </element>
  </oneOrMore>
</element>

Now let's change it to allow each card to have an optional note element.

<element name="addressBook" xmlns="http://relaxng.org/ns/structure/0.9">
  <zeroOrMore>
    <element name="card">
      <element name="name">
        <text/>
      </element>
      <element name="email">
        <text/>
      </element>
      <optional>
	<element name="note">
	  <text/>
	</element>
      </optional>
    </element>
  </zeroOrMore>
</element>

Note that the text pattern matches arbitrary text, including empty text. Note also that whitespace separating tags is ignored when matching against a pattern.

All the elements specifying the pattern must be namespace qualified by the namespace URI:

http://relaxng.org/ns/structure/0.9

The examples above use a default namespace declaration xmlns="http://relaxng.org/ns/structure/0.9" for this. A namespace prefix is equally acceptable:

<rng:element name="addressBook" xmlns:rng="http://relaxng.org/ns/structure/0.9">
  <rng:zeroOrMore>
    <rng:element name="card">
      <rng:element name="name">
        <rng:text/>
      </rng:element>
      <rng:element name="email">
        <rng:text/>
      </rng:element>
    </rng:element>
  </rng:zeroOrMore>
</rng:element>
</rng:div>

For the remainder of this document, the default namespace declaration will be left out of examples.

2. Choice

Now suppose we want to allow the name to be broken down into a givenName and a familyName, allowing an addressBook like this:

<addressBook>
  <card>
    <givenName>John</givenName>
    <familyName>Smith</familyName>
    <email>js@example.com</name>
  </card>
  <card>
    <name>Fred Bloggs</name>
    <email>fb@example.net</email>
  </card>
</addressBook>

We can use the following pattern:

<element name="addressBook">
  <zeroOrMore>
    <element name="card">
      <choice>
        <element name="name">
          <text/>
        </element>
        <group>
          <element name="givenName">
            <text/>
          </element>
          <element name="familyName">
            <text/>
          </element>
        </group>
      </choice>
      <element name="email">
        <text/>
      </element>
      <optional>
	<element name="note">
	  <text/>
	</element>
      </optional>
    </element>
  </zeroOrMore>
</element>

This corresponds to the following DTD:

<!DOCTYPE addressBook [
<!ELEMENT addressBook (card*)>
<!ELEMENT card ((name | (givenName, familyName)), email, note?)>
<!ELEMENT name (#PCDATA)>
<!ELEMENT email (#PCDATA)>
<!ELEMENT givenName (#PCDATA)>
<!ELEMENT familyName (#PCDATA)>
<!ELEMENT note (#PCDATA)>
]>

3. Attributes

Suppose we want the card element to have attributes rather than child elements. The DTD might look like this

<!DOCTYPE addressBook [
<!ELEMENT addressBook (card*)>
<!ELEMENT card EMPTY>
<!ATTLIST card
  name CDATA #REQUIRED
  email CDATA #REQUIRED>
]>

Just change each element pattern to an attribute pattern:

<element name="addressBook">
  <zeroOrMore>
    <element name="card">
      <attribute name="name">
        <text/>
      </attribute>
      <attribute name="email">
        <text/>
      </attribute>
    </element>
  </zeroOrMore>
</element>

In XML, the order of attributes is traditionally not significant. RELAX NG follows this tradition. The above pattern would match both

<card name="John Smith" email="js@example.com"/>

and

<card email="js@example.com" name="John Smith"/>

In contrast, the order of elements is significant. The pattern

<element name="card">
  <element name="name">
    <text/>
  </element>
  <element name="email">
    <text/>
  </element>
</element>

would not match:

<card><email>js@example.com</email><name>John Smith</name></card>

Note that an attribute element by itself indicates a required attribute, just as an element element by itself indicates a required element. To specify an optional attribute, use optional just as with element:

<element name="addressBook">
  <zeroOrMore>
    <element name="card">
      <attribute name="name">
        <text/>
      </attribute>
      <attribute name="email">
        <text/>
      </attribute>
      <optional>
        <attribute name="note">
          <text/>
        </attribute>
      </optional>
    </element>
  </zeroOrMore>
</element>

The group and choice patterns can be applied to attribute elements in the same way they are applied to element patterns. For example, if we wanted to allow either a name attribute or both a givenName and a familyName attribute, we can specify this in the same way that we would if we were using elements:

<element name="addressBook">
  <zeroOrMore>
    <element name="card">
      <choice>
        <attribute name="name">
          <text/>
        </attribute>
        <group>
          <attribute name="givenName">
            <text/>
          </attribute>
          <attribute name="familyName">
            <text/>
          </attribute>
        </group>
      </choice>
      <attribute name="email">
        <text/>
      </attribute>
    </element>
  </zeroOrMore>
</element>

There are no restrictions on how element elements and attribute elements can be combined. For example, the following pattern would allow a choice of elements and attributes independently for both the name and the email part of a card:

<element name="addressBook">
  <zeroOrMore>
    <element name="card">
      <choice>
	<element name="name">
	  <text/>
	</element>
	<attribute name="name">
	  <text/>
	</attribute>
      </choice>
      <choice>
	<element name="email">
	  <text/>
	</element>
	<attribute name="email">
	  <text/>
	</attribute>
      </choice>
    </element>
  </zeroOrMore>
</element>

As usual, the relative order of elements is significant, but the relative order of attributes is not. Thus the above would match any of:

<card name="John Smith" email="js@example.com"/>
<card email="js@example.com" name="John Smith"/>
<card email="js@example.com"><name>John Smith</name></card>
<card name="John Smith"><email>js@example.com</email></card>
<card><name>John Smith</name><email>js@example.com</email></card>

However, it would not match

<card><email>js@example.com</email><name>John Smith</name></card>

because the pattern for card requires any email child element to follow any name child element.

There is one difference between attribute and element patterns: <text/> is the default for the content of an attribute pattern, whereas an element pattern is not allowed to be empty. For example,

<attribute name="email"/>

is short for

<attribute name="email">
  <text/>
</attribute>

It might seem natural that

<element name="x"/>

matched an x element with no attributes and no content. However, this would make the meaning of empty content inconsistent between the element pattern and the attribute pattern, so RELAX NG does not allow the element pattern to be empty. A pattern that matches an element with no attributes and no children must use <empty/> explicitly:

<element name="addressBook">
  <zeroOrMore>
    <element name="card">
      <element name="name">
        <text/>
      </element>
      <element name="email">
        <text/>
      </element>
      <optional>
        <element name="prefersHTML">
          <empty/>
        </element>
      </optional>
    </element>
  </zeroOrMore>
</element>

4. Named patterns

For a non-trivial RELAX NG pattern, it is often convenient to be able to give names to parts of the pattern. Instead of

<element name="addressBook">
  <zeroOrMore>
    <element name="card">
      <element name="name">
	<text/>
      </element>
      <element name="email">
        <text/>
      </element>
    </element>
  </zeroOrMore>
</element>

we can write

<grammar>

  <start>
    <element name="addressBook">
      <zeroOrMore>
	<element name="card">
	  <ref name="cardContent"/>
	</element>
      </zeroOrMore>
    </element>
  </start>

  <define name="cardContent">
    <element name="name">
      <text/>
    </element>
    <element name="email">
      <text/>
    </element>
  </define>

</grammar>

A grammar element has a single start child element, and zero or more define child elements. The start and define elements contain patterns. These patterns can contain ref elements that refer to patterns defined by any of the define elements in that grammar element. A grammar pattern is matched by matching the pattern contained in the start element.

We can use the grammar element to write patterns in a style similar to DTDs:

<grammar>

  <start>
    <ref name="AddressBook"/>
  </start>

  <define name="AddressBook">
    <element name="addressBook">
      <zeroOrMore>
        <ref name="Card"/>
      </zeroOrMore>
    </element>
  </define>

  <define name="Card">
    <element name="card">
      <ref name="Name"/>
      <ref name="Email"/>
    </element>
  </define>

  <define name="Name">
    <element name="name">
      <text/>
    </element>
  </define>

  <define name="Email">
    <element name="email">
      <text/>
    </element>
  </define>

</grammar>

Recursive references are allowed. For example

<define name="inline">
  <zeroOrMore>
    <choice>
      <text/>
      <element name="bold">
        <ref name="inline"/>
      </element>
      <element name="italic">
        <ref name="inline"/>
      </element>
      <element name="span">
        <optional>
          <attribute name="style"/>
        </optional>
        <ref name="inline"/>
      </element>
    </choice>
  </zeroOrMore>
</define>

However, recursive references must be within an element. Thus, the following is not allowed:

<define name="inline">
  <choice>
    <text/>
    <element name="bold">
      <ref name="inline"/>
    </element>
    <element name="italic">
      <ref name="inline"/>
    </element>
    <element name="span">
      <optional>
	<attribute name="style"/>
      </optional>
      <ref name="inline"/>
    </element>
  </choice>
  <optional>
    <ref name="inline"/>
  </optional>
</define>

A start element may also have a name attribute. This is a shorthand for a define with that name together with a start element referencing that definition. For example

<grammar>
  <start name="inline">
    <zeroOrMore>
      <choice>
	<text/>
	<element name="bold">
	  <ref name="inline"/>
	</element>
      </choice>
    </zeroOrMore>
  </start>
</grammar>

is short for

<grammar>
  <start>
    <ref name="inline"/>
  </start>
  <define name="inline">
    <zeroOrMore>
      <choice>
	<text/>
	<element name="bold">
	  <ref name="inline"/>
	</element>
      </choice>
    </zeroOrMore>
  </define>
</grammar>

5. Datatyping

RELAX NG allows patterns to reference externally-defined datatypes, such as those defined by W3C XML Schema Part 2. RELAX NG implementations may differ in what datatypes they support. You must use datatypes that are supported by the implementation you plan to use.

The data pattern matches a string that represents a value of a named datatype. The datatypeNamespace attribute contains a URI identifying the collection of datatypes being used. The datatype collection defined W3C XML Schema Part 2 would be identified by the URI http://www.w3.org/2001/XMLSchema-datatypes. The type attribute specifies the name of the datatype in the collection identified by the datatypeNamespace attribute. For example, if a RELAX NG implementation supported the built-in datatypes of W3C XML Schema Part 2, you could use:

<element name="number">
  <data type="integer" datatypeNamespace="http://www.w3.org/2001/XMLSchema-datatypes"/>
</element>

It is inconvenient to specify the datatypeNamespace attribute on every data element, so RELAX NG allows the datatypeNamespace attribute to be inherited. The datatypeNamespace attribute can be specified on any RELAX NG element. If a data element does not have a datatypeNamespace attribute, it will use the value from the closest ancestor that has a datatypeNamespace attribute. Typically, the datatypeNamespace attribute is specified on the root element of the RELAX NG pattern. For example:

<element name="point" datatypeNamespace="http://www.w3.org/2001/XMLSchema-datatypes">
  <element name="x">
    <data type="double"/>
  </element>
  <element name="y">
    <data type="double"/>
  </element>
</element>

If the children of an element or an attribute match a data pattern, then complete content of the element or attribute must match that data pattern. It is not permitted to have a pattern which allows part of the content to match a data pattern, and another part to match another pattern. For example, the following pattern is not allowed:

<element name="bad">
  <data type="int"/>
  <element name="note">
    <text/>
  </element>
</element>

However, this would be fine:

<element name="ok">
  <data type="int"/>
  <attribute name="note">
    <text/>
  </attribute>
</element>

Note that this restriction does not apply to the text pattern.

Datatypes may have parameters. For example, a string datatype may have a parameter controlling the length of the string. The parameters applicable to any particular datatype are determined by the datatyping vocabulary. Parameters are specified by adding one or more param elements as children of the data element. For example, the following constrains the email element to contain a string at most 127 characters long:

<element name="email">
  <data type="string">
    <param name="maxLength">127</param>
  </data>
</element>

6. Enumerations

Many markup vocabularies have attributes whose value is constrained to be one of set of specified values. The value pattern matches a string that has a specified value. For example,

<element name="card">
  <attribute name="name"/>
  <attribute name="email"/>
  <attribute name="preferredFormat">
    <choice>
      <value>html</value>
      <value>text</value>
    </choice>
  </attribute>
</element>

allows the preferredFormat attribute to have the value html or text. This corresponds to the DTD

<!DOCTYPE card [
<!ELEMENT card EMPTY>
<!ATTLIST card
  name CDATA #REQUIRED
  email CDATA #REQUIRED
  preferredFormat (html|text) #REQUIRED>
]>

The value pattern is not restricted to attribute values. For example, the following is allowed:

<element name="card">
  <element name="name">
    <text/>
  </element>
  <element name="email">
    <text/>
  </element>
  <element name="preferredFormat">
    <choice>
      <value>html</value>
      <value>text</value>
    </choice>
  </element>
</element>

The prohibition against a data pattern's matching only part of the content of an element also applies to value patterns.

By default, the value pattern will consider the string in the pattern to match the string in the document if the two strings are the same after the whitespace in both strings is normalized. Whitespace normalization strips leading and trailing white-space characters, and collapses sequences of one or more white-space characters to a single space character. This corresponds to the behaviour of an XML parser for an attribute that is declared as other than CDATA. Thus the above pattern will match any of

<card name="John Smith" email="js@example.com" preferredFormat="html"/>
<card name="John Smith" email="js@example.com" prefersFormat="  html  "/>

The way that the value pattern compares the pattern string with the document string can be controlled by specifying a type attribute and optionally a datatypeNamespace attribute, which identify a datatype in the same way as for the data pattern. The pattern string matches the document string if they both represent the same value of the specified datatype. Thus, whereas the data pattern matches an arbitrary value of a datatype, the value pattern matches a specific value of a datatype.

If there is no ancestor element with a datatypeNamespace element, the datatype namespace defaults to the RELAX NG namespace. This provides two datatypes, string and token. The datatype token corresponds to the default comparison behavior of the value pattern. The datatype string compares strings without any normalization (other than that performed by XML). For example,

<element name="card">
  <attribute name="name"/>
  <attribute name="email"/>
  <attribute name="preferredFormat">
    <choice>
      <value type="string">html</value>
      <value type="string">text</value>
    </choice>
  </attribute>
</element>

will not match

<card name="John Smith" email="js@example.com" prefersHTML="  html  "/>

7. Lists

The list pattern matches a whitespace-separated sequence of tokens; it contains a pattern that the sequence of individual tokens must match. The list pattern splits a string into a list of strings, and then matches the resulting list of strings against the pattern inside the list pattern.

For example, suppose we want to have a vector element that contains two floating point numbers separated by whitespace. We could use list as follows:

<element name="vector">
  <list>
    <data type="float"/>
    <data type="float"/>
  </list>
</element>

Or suppose we want the vector element to contain a list of one or more floating point numbers separated by whitespace:

<element name="vector">
  <list>
    <oneOrMore>
      <data type="double"/>
    </oneOrMore>
  </list>
</element>

Or suppose we want a path element containing an even number of floating point numbers:

<element name="path">
  <list>
    <oneOrMore>
      <data type="double"/>
      <data type="double"/>
    </oneOrMore>
  </list>
</element>

The list pattern must not contain element or attribute patterns.

8. Interleaving

The interleave pattern allows child elements to occur in any order. For example, the following would allow the card element to contain the name and email elements in any order:

<element name="addressBook">
  <zeroOrMore>
    <element name="card">
      <interleave>
	<element name="name">
	  <text/>
	</element>
	<element name="email">
	  <text/>
	</element>
      </interleave>
    </element>
  </zeroOrMore>
</element>

The pattern is called interleave because of how it works with patterns that match more than one element. Suppose we want to write a pattern for the HTML head element which requires exactly one title element, at most one base element and zero or more style, script, link and meta elements and suppose we are writing a grammar pattern that has one definition for each element. Then we could define the pattern for head as follows:

<define name="head">
  <element name="head">
    <interleave>
      <ref name="title"/>
      <optional>
        <ref name="base"/>
      </optional>
      <zeroOrMore>
        <ref name="style"/>
      </zeroOrMore>
      <zeroOrMore>
        <ref name="script"/>
      </zeroOrMore>
      <zeroOrMore>
        <ref name="link"/>
      </zeroOrMore>
      <zeroOrMore>
        <ref name="meta"/>
      </zeroOrMore>
    </interleave>
  </element>
</define>

Suppose we had a head element that contained a meta element, followed by a title element, followed by a meta element. This would match the pattern because it is an interleaving of a sequence of two meta elements, which match the child pattern

      <zeroOrMore>
        <ref name="meta"/>
      </zeroOrMore>

and a sequence of one title element, which matches the child pattern

      <ref name="title"/>

The semantics of the interleave pattern are that a sequence of elements matches an interleave pattern if it is an interleaving of sequences that match the child patterns of the interleave pattern. Note that this is different from the & connector in SGML: A* & B matches the sequence of elements A A B or the sequence of elements B A A but not the sequence of elements A B A.

One special case of interleave is very common: interleaving <text/> with a pattern p represents a pattern that matches what p matches but also allows characters to occur as children. The mixed element is a shorthand for this.

<mixed> p </mixed>

is short for

<interleave> <text/> p </interleave>

9. Modularity

9.1. Referencing external patterns

The externalRef pattern can be used to reference a pattern defined in a separate file. The externalRef element has a required href attribute that specifies the URL of a file containing the pattern. The externalRef matches if the pattern contained in the specified URL matches. Suppose for example, you have a RELAX NG pattern that matches HTML inline content stored in inline.rng:

<grammar>
  <start name="inline">
    <zeroOrMore>
      <choice>
        <text/>
        <element name="code">
          <ref name="inline"/>
        </element>
        <element name="em">
          <ref name="inline"/>
        </element>
        <!-- etc -->
      </choice>
    </zeroOrMore>
  </start>
</grammar>

Then we could allow the note element to contain inline HTML markup by using externalRef as follows:

<element name="addressBook">
  <zeroOrMore>
    <element name="card">
      <element name="name">
        <text/>
      </element>
      <element name="email">
        <text/>
      </element>
      <optional>
	<element name="note">
	  <externalRef href="inline.rng"/>
	</element>
      </optional>
    </element>
  </zeroOrMore>
</element>

For another example, suppose you have two RELAX NG patterns stored in files pattern1.rng and pattern2.rng. Then the following is a pattern that which match anything matched by one of those patterns:

<choice>
  <externalRef href="pattern1.rng"/>
  <externalRef href="pattern2.rng"/>
</choice>

9.2. Merging grammars

The include element allows grammars to be merged together. A grammar pattern may have include elements as children. An include element has a required href attribute that specifies the URL of a file containing a grammar pattern. The referenced grammar pattern will be merged with the grammar pattern containing the include element.

@@@ Add example

Normally, duplicate definitions (two definitions with the same name) result in an error. However, define elements may be put inside the include element to indicate that they are to replace definitions in the included grammar pattern.

Suppose the file addressBook.rng contains the following grammar pattern:

<grammar>

  <start>
    <element name="addressBook">
      <zeroOrMore>
	<element name="card">
	  <element name="name">
	    <text/>
	  </element>
	  <element name="email">
	    <text/>
	  </element>
          <ref name="card.local"/>
	</element>
      </zeroOrMore>
    </element>
  </start>

  <define name="card.local">
    <empty/>
  </define>

</grammar>

Another pattern could customize addressBook.rng as follows:

<grammar>

  <include href="addressBook.rng">

    <define name="card.local">
      <optional>
	<element name="note">
	  <text/>
	</element>
      </optional>
    </define>

  </include>

</grammar>

This would be equivalent to:

<grammar>

  <start>
    <element name="addressBook">
      <zeroOrMore>
	<element name="card">
	  <element name="name">
	    <text/>
	  </element>
	  <element name="email">
	    <text/>
	  </element>
          <ref name="card.local"/>
	</element>
      </zeroOrMore>
    </element>
  </start>

  <define name="card.local">
    <optional>
      <element name="note">
	<text/>
      </element>
    </optional>
  </define>

</grammar>

which is equivalent to

<element name="addressBook">
  <zeroOrMore>
    <element name="card">
      <element name="name">
	<text/>
      </element>
      <element name="email">
	<text/>
      </element>
      <optional>
	<element name="note">
	  <text/>
	</element>
      </optional>
    </element>
  </zeroOrMore>
</element>

It is also possible to combine together duplicate definitions from separate files by adding a combine attribute to the define elements. The combine attribute specifies how the definitions should be combined; it may have the value choice or interleave. For example, we could have written our customization as:

<grammar>

  <include href="addressBook.rng"/>

  <define name="card.local" combine="choice">
    <!-- no optional element needed this time -->
    <element name="note">
      <text/>
    </element>
  </define>

</grammar>

This would be equivalent to:

<grammar>

  <start>
    <element name="addressBook">
      <zeroOrMore>
	<element name="card">
	  <element name="name">
	    <text/>
	  </element>
	  <element name="email">
	    <text/>
	  </element>
          <ref name="card.local"/>
	</element>
      </zeroOrMore>
    </element>
  </start>

  <define name="card.local">
    <choice>
      <empty/>
      <element name="note">
        <text/>
      </element>
    </choice>
  </define>

</grammar>

This has the same meaning as before, since an optional pattern is equivalent to a choice between the pattern and empty.

We could also have used combine="interleave" here:

<grammar>

  <include href="addressBook.rng"/>

  <define name="card.local" combine="interleave">
    <optional>
      <element name="note">
	<text/>
      </element>
    </optional>
  </define>

</grammar>

This would be equivalent to:

<grammar>

  <start>
    <element name="addressBook">
      <zeroOrMore>
	<element name="card">
	  <element name="name">
	    <text/>
	  </element>
	  <element name="email">
	    <text/>
	  </element>
          <ref name="card.local"/>
	</element>
      </zeroOrMore>
    </element>
  </start>

  <define name="card.local">
    <interleave>
      <empty/>
      <optional>
        <element name="note">
	  <text/>
        </element>
      </optional>
    </interleave>
  </define>

</grammar>

This has the same meaning as before, since adding an empty pattern to the content of a interleave pattern does not make any difference to what the interleave pattern matches.

@@@ Add example of combine="interleave" with attributes.

The notAllowed pattern never matches anything. Just as adding empty to a group makes no difference, so adding notAllowed to a choice makes no difference. It is typically used in a definition that is referenced in a choice element to allow an including pattern to specify additional choices. For example, suppose a RELAX NG pattern inline.rng provides a pattern for inline content, which allows bold and italic elements arbitrarily nested:

<grammar>

  <start name="inline">
    <zeroOrMore>
      <choice>
	<text/>
	<element name="bold">
	  <ref name="inline"/>
	</element>
	<element name="italic">
	  <ref name="inline"/>
	</element>
        <ref name="local.inline"/>
      </choice>
    </zeroOrMore>
  </start>

  <define name="local.inline">
    <notAllowed/>
  </define>

</grammar>

Another RELAX NG pattern could use inline.rng and add code and em to the set of inline elements as follows:

<grammar>

  <include href="inline.rng">

    <define name="local.inline">
      <choice>
	<element name="code">
	  <ref name="inline">
	</element>
	<element name="em">
	  <ref name="inline">
	</element>
      </choice>
    </define>

  </include>  

  <start>
    <element name="doc">
      <zeroOrMore>
	<element name="p">
	  <ref name="inline"/>
	</element>
      </zeroOrMore>
    </element>
  </start>

</grammar>

We could instead have used combine="choice". In this case, inline.rng would need to separate out the choices as a separate definition:

<grammar>

  <start name="inline">
    <zeroOrMore>
      <ref name="inline.class"/>
    </zeroOrMore>
  </start>

  <define name="inline.class">
    <choice>
      <text/>
      <element name="bold">
	<ref name="inline"/>
      </element>
      <element name="italic">
	<ref name="inline"/>
      </element>
    </choice>
  </define>

</grammar>

and the customization would add to those choices:

<grammar>

  <include href="inline.rng"/>

  <start>
    <element name="doc">
      <zeroOrMore>
	<element name="p">
	  <ref name="inline"/>
	</element>
      </zeroOrMore>
    </element>
  </start>

  <define name="inline.class" combine="choice">
    <choice>
      <element name="code">
	<ref name="inline">
      </element>
      <element name="em">
	<ref name="inline">
      </element>
    </choice>
  </define>
  
</grammar>

10. Namespaces

RELAX NG is namespace-aware. Thus, it considers an element or attribute to have both a local name and a namespace URI which together constitute the name of that element or attribute.

10.1. Using the namespace attribute

The element pattern uses a namespace attribute to specify the namespace URI of the elements that it matches. For example

<element name="foo" namespace="http://www.example.com">
  <empty/>
</element>

would match any of

<foo xmlns="http://www.example.com"/>
<e:foo xmlns:e="http://www.example.com"/>
<example:foo xmlns:example="http://www.example.com"/>

but not any of

<foo/>
<e:foo xmlns:e="http://WWW.EXAMPLE.COM"/>
<example:foo xmlns:example="http://www.example.net"/>

A value of an empty string for the namespace attribute indicates a null or absent namespace URI (just as with the xmlns attribute). Thus, the pattern

<element name="foo" namespace="">
  <empty/>
</element>

matches any of

<foo xmlns=""/>
<foo/>

but not any of

<foo xmlns="http://www.example.com"/>
<e:foo xmlns:e="http://www.example.com"/>

It is tedious and error-prone to specify the namespace attribute on every element, so RELAX NG allows it to be defaulted. If an element pattern does not specify a namespace attribute, then it defaults to the value of the namespace attribute of the nearest ancestor that has a namespace attribute, or the empty string if there is no such ancestor. Thus

<element name="addressBook">
  <zeroOrMore>
    <element name="card">
      <element name="name">
        <text/>
      </element>
      <element name="email">
        <text/>
      </element>
    </element>
  </zeroOrMore>
</element>

is equivalent to

<element name="addressBook" namespace="">
  <zeroOrMore>
    <element name="card" namespace="">
      <element name="name" namespace="">
        <text/>
      </element>
      <element name="email" namespace="">
        <text/>
      </element>
    </element>
  </zeroOrMore>
</element>

and

<element name="addressBook" namespace="http://www.example.com">
  <zeroOrMore>
    <element name="card">
      <element name="name">
        <text/>
      </element>
      <element name="email">
        <text/>
      </element>
    </element>
  </zeroOrMore>
</element>

is equivalent to

<element name="addressBook" namespace="http://www.example.com">
  <zeroOrMore>
    <element name="card" namespace="http://www.example.com">
      <element name="name" namespace="http://www.example.com">
        <text/>
      </element>
      <element name="email" namespace="http://www.example.com">
        <text/>
      </element>
    </element>
  </zeroOrMore>
</element>

The attribute pattern also takes a namespace attribute. However, there is a difference in how it defaults. This is because of the fact that the XML Namespaces Recommendation does not apply the default namespace to attributes. If a namespace attribute is not specified on the attribute pattern, then it defaults to the empty string. Thus

<element name="addressBook" namespace="http://www.example.com">
  <zeroOrMore>
    <element name="card">
      <attribute name="name"/>
      <attribute name="email"/>
    </element>
  </zeroOrMore>
</element>

is equivalent to

<element name="addressBook" namespace="http://www.example.com">
  <zeroOrMore>
    <element name="card" namespace="http://www.example.com">
      <attribute name="name" namespace=""/>
      <attribute name="email" namespace=""/>
    </element>
  </zeroOrMore>
</element>

and so will match

<addressBook xmlns="http://www.example.com">
  <card name="John Smith" email="js@example.com"/>
</addressBook>

or

<example:addressBook xmlns:example="http://www.example.com">
  <example:card name="John Smith" email="js@example.com"/>
</example:addressBook>

but not

<example:addressBook xmlns:example="http://www.example.com">
  <example:card example:name="John Smith" example:email="js@example.com"/>
</example:addressBook>

To match this last example, the attribute patterns must specify global="true":

<element name="addressBook" namespace="http://www.example.com">
  <zeroOrMore>
    <element name="card">
      <attribute name="name" global="true"/>
      <attribute name="email" global="true"/>
    </element>
  </zeroOrMore>
</element>

This is equivalent to:

<element name="addressBook" namespace="http://www.example.com">
  <zeroOrMore>
    <element name="card" namespace="http://www.example.com">
      <attribute name="name" namespace="http://www.example.com"/>
      <attribute name="email" namespace="http://www.example.com"/>
    </element>
  </zeroOrMore>
</element>

Thus, specifying global="true" on an attribute pattern makes the namespace attribute default in the same way that it does on an element pattern.

The namespace attribute is allowed on any element in a RELAX NG pattern. The global attribute is allowed only on an attribute pattern.

10.2. Qualified names

When a pattern matches elements and attributes from multiple namespaces, using the namespace attribute would require repeating namespace URIs in different places in the pattern. This is error-prone and hard to maintain, so RELAX NG also allows the element and attribute patterns to use a prefix in the value of the name attribute to specify the namespace URI. In this case, the prefix specifies the namespace URI to which that prefix is bound by the namespace declarations in scope on the element or attribute pattern. Thus

<element name="e:addressBook" xmlns:e="http://www.example.com">
  <zeroOrMore>
    <element name="e:card">
      <element name="e:name">
        <text/>
      </element>
      <element name="e:email">
        <text/>
      </element>
    </element>
  </zeroOrMore>
</element>

is equivalent to

<element name="addressBook" namespace="http://www.example.com">
  <zeroOrMore>
    <element name="card" namespace="http://www.example.com">
      <element name="name" namespace="http://www.example.com">
        <text/>
      </element>
      <element name="email" namespace="http://www.example.com">
        <text/>
      </element>
    </element>
  </zeroOrMore>
</element>

If a prefix is specified in the value of the name attribute of an element or attribute pattern, then that prefix determines the namespace URI of the elements or attributes that will be matched by that pattern, regardless of the value of any namespace attribute.

Note that the XML default namespace (as specified by the xmlns attribute) is not used in determining the namespace URI of elements and attributes that element and attribute patterns match.

11. Name classes

Normally, the name of the element to be matched by an element element is specified by a name attribute. An element element can instead start with an element specifying a name-class. In this case, the element pattern will only match an element if the name of the element is a member of the name-class. The simplest name-class is anyName, which any name at all is a member of, regardless of its local name and its namespace URI. For example, the following pattern matches any well-formed XML document:

<grammar>

  <start name="anyElement">
    <element>
      <anyName/>
      <zeroOrMore>
	<choice>
	  <attribute>
	    <anyName/>
	  </attribute>
	  <text/>
	  <ref name="anyElement"/>
	</choice>
      </zeroOrMore>
    </element>
  </start>

</grammar>

The namespaceName name-class contains any name with the namespace URI specified by the namespace attribute, which defaults in the same way as the namespace attribute on the element pattern.

The choice name-class matches any name that is a member of any of its child name-classes.

The not name-classes contains any name that is not a member of the child name-class.

For example

<element name="card" namespace="http://www.example.com">
  <zeroOrMore>
    <attribute>
      <not>
        <choice>
          <namespaceName/>
          <namespaceName namespace=""/>
        </choice>
      </not>
    </attribute>
  </zeroOrMore>
  <text/>
</element>

would allow the card element to have any number of namespace-qualified attributes provided that they were qualified with namespace other than that of the card element.

Note that an attribute pattern matches a single attribute even if it has a name-class that contains multiple names. To match zero or more attributes, the zeroOrMore element must be used.

The difference name-class contains any name that is a member of the first child name-class, but not a member of any of the following name-classes. The not name-class is, in fact, a shorthand for difference:

<not> name-class </not>

is short for

<difference> <anyName/> name-class </difference>

The name name-class contains a single name. The content of the name element specifies the name in the same way as the name attribute of the element pattern. The namespace attribute specifies the namespace URI in the same way as the element pattern.

Some schema languages have a concept of lax validation, where an element or attribute is validated against a definition only if there is one. We can implement this concept in RELAX NG with name classes that uses difference and name. Suppose, for example, we wanted to allow an element to have any attribute with a qualified name, but we still wanted to ensure that if there was an xml:space attribute, it had the value default or preserve. It wouldn't work to use:

<element name="example">
  <zeroOrMore>
    <attribute>
      <anyName/>
    </attribute>
  </zeroOrMore>
  <optional>
    <attribute name="xml:space">
      <choice>
        <value>default</value>
        <value>preserve</value>
      </choice>
    </attribute>
  </optional>
</element>

because an xml:space attribute with a value other than default or preserve would match

    <attribute>
      <anyName/>
    </attribute>

even though it did not match

    <attribute name="xml:space">
      <choice>
        <value>default</value>
        <value>preserve</value>
      </choice>
    </attribute>

The solution is to use name together with difference:

<element name="example">
  <zeroOrMore>
    <attribute>
      <difference>
        <anyName/>
        <name>xml:space</name>
      </difference>
    </attribute>
  </zeroOrMore>
  <optional>
    <attribute name="xml:space">
      <choice>
        <value>default</value>
        <value>preserve</value>
      </choice>
    </attribute>
  </optional>
</element>

Note that the define element cannot contain a name-class; it can only contain a pattern.

12. Cross references

RELAX NG generalizes the ID/IDREF feature of XML. A data pattern may have either a key or a keyRef attribute. A data pattern with a key attribute behaves like an XML ID; a data pattern with a keyRef attribute type behaves like an XML IDREF. Whereas XML has a single symbol-space of IDs and IDREFs, RELAX NG has an unlimited number of named symbol-spaces. The value of the key or keyRef is an unprefixed name identifying the symbol-space. An element or attribute that matches a data pattern with a key attribute is called a key; an element or attribute that matches a data pattern with a keyRef attribute is called a key-reference. A document is invalid if it has two distinct keys in the same symbol-space with same value; it is also invalid if it contains a key-reference that does not have a corresponding key in the same symbol-space in the same document with the same value.

Whereas in XML IDs and IDREFs must be names, in RELAX NG keys and key-references may have any datatype; whether an element or attribute is a key or key-reference is orthogonal to its datatype.The values of keys and key-references are compared using the datatype specified by the data pattern. All data patterns sharing the same symbol space must specify the same value for the type attribute.

For example, suppose a document contains termref elements referencing defined terms:

<element name="termref">
  <data type="token" keyRef="term"/>
</element>

For each such defined term, there is a corresponding dt, dd pair in a glossary element:

<element name="glossary">
  <zeroOrMore>
    <element name="dt">
      <data type="token" key="term"/>
    </element>
    <element name="dd">
      <text/>
    </element>
  </zeroOrMore>
</element>

The above example is using the builtin token datatype introduced in the Enumerations section.

It must be possible to determine for any element or attribute whether it is a key or key reference and, if so, the symbol space of the key or key reference, by examining just the name of the element or attribute and the names of the ancestors of that element or attribute. For example, it is not permitted to have the pattern:

<element name="bad">
  <choice>
    <data type="string" key="x"/>
    <data type="string" key="y"/>
  </choice>
</element>

13. Annotations

If a RELAX NG element has an attribute or child element with a namespace URI other than the RELAX NG namespace, then that attribute or element is ignored. Thus, you can add annotations to RELAX NG patterns simply by using an attribute or element in a separate namespace:

<element name="addressBook" xmlns="http://relaxng.org/ns/structure/0.9" xmlns:a="http://www.example.com/annotation">
  <zeroOrMore>
    <element name="card">
      <a:documentation>Information about a single email address.</a:documentation>
      <element name="name">
        <text/>
      </element>
      <element name="email">
        <text/>
      </element>
    </element>
  </zeroOrMore>
</element>

14. Nested grammars

There is no prohibition against nesting grammar patterns. A ref pattern refers to a definition from nearest grammar ancestor. There is also a parentRef element that escapes out of the current grammar and references a definition from the parent of the current grammar.

Imagine the problem of writing a pattern for tables. The pattern for tables only cares about the structure of tables; it doesn't care about what goes inside a table cell. First, we create a RELAX NG pattern table.rng as follows:

<grammar>

<define name="cell.content">
  <notAllowed/>
</define>

<start>
  <element name="table">
    <oneOrMore>
      <element name="tr">
        <oneOrMore>
	  <element name="td">
	    <ref name="cell.content"/>
	  </element>
        </oneOrMore>
      </element>
    </oneOrMore>
  </element>
</start>

</grammar>

Patterns that include table.rng must redefine cell.content. By using a nested grammar pattern containing a parentRef pattern, the including pattern can redefine cell.content to be a pattern defined in the including pattern's grammar, thus effectively importing a pattern from the parent grammar into the child grammar:

<grammar>

<start>
  <element name="doc">
    <zeroOrMore>
      <choice>
	<element name="p">
	  <ref name="inline"/>
	</element>
	<grammar>
	  <include href="table.rng">
	    <define name="cell.content">
	      <parentRef name="inline"/>
	    </define>
          </include>
	</grammar>
      </choice>
    </zeroOrMore>
  </element>
</start>

<define name="inline">
  <zeroOrMore>
    <choice>
      <text/>
      <element name="em">
        <ref name="inline"/>
      </element>
    </choice>
  </zeroOrMore>
</define>

</grammar>

Of course, in a trivial case like this, there is no advantage in nesting the grammars: we could simply have have included table.rng within the outer grammar element. However, when the included grammar has many definitions, nesting it avoids the possibility of name conflicts between the including grammar and the included grammar.

15. Non-restrictions

RELAX NG does not require patterns to be "deterministic" or "unambiguous".

Suppose we wanted to write the email address book in HTML, but use class attributes to specify the structure.

<element name="html">
  <element name="head">
    <element name="title">
      <text/>
    </element>
  </element>
  <element name="body">
    <element name="table">
      <attribute name="class">
        <value>addressBook</value>
      </attribute>
      <oneOrMore>
        <element name="tr">
	  <attribute name="class">
	    <value>card</value>
	  </attribute>
          <element name="td">
	    <attribute name="class">
	      <value>name</value>
	    </attribute>
            <interleave>
              <text/>
              <optional>
                <element name="span">
                  <attribute name="class">
                    <value>givenName</value>
                  </attribute>
                  <text/>
                </element>
              </optional>
              <optional>
                <element name="span">
                  <attribute name="class">
                    <value>familyName</value>
                  </attribute>
                  <text/>
                </element>
              </optional>
            </interleave>
          </element>
          <element name="td">
	    <attribute name="class">
	      <value>email</value>
	    </attribute>
            <text/>
          </element>
        </element>
      </oneOrMore>
    </element>
  </element>
</element>

This would match a XML document such as:

<html>
  <head>
    <title>Example Address Book</title>
  </head>
  <body>
    <table class="addressBook">
      <tr class="card">
        <td class="name">
          <span class="givenName">John</span>
          <span class="familyName">Smith</span>
        </td>
        <td class="email">js@example.com</td>
      </tr>
    </table>
  </body>
</html>

but not

<html>
  <head>
    <title>Example Address Book</title>
  </head>
  <body>
    <table class="addressBook">
      <tr class="card">
        <td class="name">
          <span class="givenName">John</span>
          <!-- Note the incorrect class attribute -->
          <span class="givenName">Smith</span>
        </td>
        <td class="email">js@example.com</td>
      </tr>
    </table>
  </body>
</html>

16. Non-features

The role of RELAX NG is simply to specify a class of documents, not to assist in interpretation of the documents belonging to the class. It does not change the infoset of the document. In particular, RELAX NG

  • does not allow defaults for attributes to be specified

  • does allow entities to be specified

  • does allow notations to be specified

  • does not specify whether white-space is significant

Also RELAX NG does not define a way for an XML document to associate itself with a RELAX NG pattern.

17. Differences from TREX

  1. the concur pattern has been removed

  2. the string pattern has been replaced by the value pattern

  3. the anyString pattern has been renamed to text

  4. the namespace URI is different

  5. pattern elements must be namespace qualified

  6. anonymous datatypes have been removed

  7. the data pattern can have parameters specified by param child elements

  8. the list pattern has been added for matching whitespace-separated lists of tokens

  9. the data pattern can have a key or keyRef attribute

  10. the replace and group values for the combine attribute have been removed

  11. an include element in a grammar may contain define elements that replace included definitions

  12. an include element occurring as a pattern has been renamed to externalRef; an include element is now allowed only as a child of the grammar element

  13. the parent attribute on the ref element has been replaced by a new parentRef element

  14. the ns attribute has been renamed to namespace

  15. the nsName element has been renamed to namespaceName

  16. the type attribute of the data element is an unqualified name; the data element uses the datatypeNamespace attribute rather than the ns attribute to identify the namespace of the datatype