Let's take a very simple grammar: an address book consists of zero or more cards, each of which consists of a name and email address. Here's the specification in the compact form of RNG. In these notes, when we refer to a block, this means a series of Relax NG specifications enclosed in curly braces { and }.
We begin with a grammar block that encloses the
entire specification. The start = keywords tells
a validator where to start validating; i.e., which element is the
root element. The rest is a pattern that tells what
a valid document should look like. Relax NG works by
specifying a pattern for structure and content of valid documents.
Any document that matches
the pattern is valid; any document that doesn’t, isn’t.
If you’ve read the tutorial, you’ll
notice that the first examples don’t have the grammar
and start specifications. They aren’t necessary
for a “self-contained” example like this one, but
as soon as we start specifying more complex grammars, we’ll need them.
So why not now?
grammar
{
start = element addressBook
{
element card
{
element name {text},
element email {text}
}*
}
}
If you want to require at least one <card> element,
replace the * with +. An optional element is
followed by a ? (just as in Unix regular expressions).
So, if we want a card to be
able to contain an optional <note> element, we’d
have this specification (the added material is in boldface):
grammar
{
start = element addressBook
{
element card
{
element name {text},
element email {text},
element note {text}?
}*
}
}
Let’s say that we can contact someone either by email or by phone number (but not both). We’d modify our specification this way, showing only the relevant portion. The | character is used to specify a choice. If there is any possibility of ambiguity, you must use parentheses to show which elements are involved in the choice.
element card
{
element name {text},
(
element email {text} |
element phone {text}
),
element note {text}?
}*
Now let’s say that we can either have a name (for example, a company name) or a first name/last name pair. Using parentheses lets us say it easily:
element card
{
(
element name {text} |
(
element firstname {text},
element lastname {text}
)
),
(element email {text} |
element phone {text}),
element note {text}?
}*