Copyright © The Organization for the Advancement of Structured Information Standards [OASIS] 2002. 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.
This document specifies a compact, non-XML syntax for [RELAX NG].
This Committee Specification was approved for publication by the OASIS RELAX NG technical committee. It is a stable document which represents the consensus of the committee. Comments on this document may be sent to relax-ng-comment@lists.oasis-open.org.
A list of known errors in this document is available at http://www.oasis-open.org/committees/relax-ng/compact-20021121-errata.html.
This specification describes a compact, non-XML syntax for [RELAX NG].
The goals of this syntax are to:
The syntax has similarities to [XQuery Formal Semantics], to [XDuce] and to the DTD syntax of [XML 1.0].
The body of this document contains an informal description of the syntax and how it maps onto the XML syntax. Developers should consult Appendix A for a complete, rigorous description. Appendix B contains an example in the form of schema for RELAX NG.
The following is a summary of the syntax in EBNF. Square brackets are used to indicate optionality. The reader may find it helpful to compare this with the syntax in Section 3 of [RELAX NG]. The start symbol is topLevel.
topLevel | ::= | decl* (pattern | grammarContent*) |
decl | ::= | "namespace " identifierOrKeyword "= " namespaceURILiteral| " default " "namespace " [identifierOrKeyword] "= " namespaceURILiteral| " datatypes " identifierOrKeyword "= " literal |
pattern | ::= | "element " nameClass "{ " pattern "} "| " attribute " nameClass "{ " pattern "} "| pattern (" , " pattern)+| pattern (" & " pattern)+| pattern (" | " pattern)+| pattern " ? "| pattern " * "| pattern " + "| " list " "{ " pattern "} "| " mixed " "{ " pattern "} "| identifier | " parent " identifier| " empty "| " text "| [datatypeName] datatypeValue | datatypeName [" { " param* "} "] [exceptPattern]| " notAllowed "| " external " anyURILiteral [inherit]| " grammar " "{ " grammarContent* "} "| " ( " pattern ") " |
param | ::= | identifierOrKeyword "= " literal |
exceptPattern | ::= | "- " pattern |
grammarContent | ::= | start | define | " div " "{ " grammarContent* "} "| " include " anyURILiteral [inherit] ["{ " includeContent* "} "] |
includeContent | ::= | define | start | " div " "{ " includeContent* "} " |
start | ::= | "start " assignMethod pattern |
define | ::= | identifier assignMethod pattern |
assignMethod | ::= | "= "| " |= "| " &= " |
nameClass | ::= | name | nsName [exceptNameClass] | anyName [exceptNameClass] | nameClass " | " nameClass| " ( " nameClass ") " |
name | ::= | identifierOrKeyword | CName |
exceptNameClass | ::= | "- " nameClass |
datatypeName | ::= | CName | " string "| " token " |
datatypeValue | ::= | literal |
anyURILiteral | ::= | literal |
namespaceURILiteral | ::= | literal | " inherit " |
inherit | ::= | "inherit " "= " identifierOrKeyword |
identifierOrKeyword | ::= | identifier | keyword |
identifier | ::= | (NCName - keyword) | quotedIdentifier |
quotedIdentifier | ::= | "\ " NCName |
CName | ::= | NCName ": " NCName |
nsName | ::= | NCName ":* " |
anyName | ::= | "* " |
literal | ::= | literalSegment ("~ " literalSegment)+ |
literalSegment | ::= | '" ' (Char - ('" ' | newline))* '" '| " ' " (Char - ("' " | newline))* "' "| ' """ ' (['" '] ['" '] (Char - '" '))* '""" '| " ''' " (["' "] ["' "] (Char - "' "))* "''' " |
keyword | ::= | "attribute "| " default "| " datatypes "| " div "| " element "| " empty "| " external "| " grammar "| " include "| " inherit "| " list "| " mixed "| " namespace "| " notAllowed "| " parent "| " start "| " string "| " text "| " token " |
NCName is defined in [XML Namespaces]. Char is defined in [XML 1.0].
In order to use a keyword as an identifier, it must be quoted with \. It is not necessary to quote a keyword that is used as the name of an element or attribute or as datatype parameter.
The value of a literal is the concatenation of the values of its constituent literalSegments. A literalSegment is always terminated only by an occurrence of the same delimiter that began it. The delimiter used to begin a literalSegment may be either one or three occurrences of a single or double quote character. Newlines are allowed only in literalSegments delimited by three quote characters. The value of a literal segment consists of the characters between its delimiters. One way to get a literal whose value contains both a single and a double quote is to divide the literal into multiple literalSegments so that the single and double quote are in separate literalSegments. Another way is to use a literalSegment delimited by three single or double quotes.
Annotations can be specified as described in Section 5.
There is no notion of operator precedence. It is an error for patterns to combine the |, &, , and - operators without using parentheses to make the grouping explicit. For example, foo | bar, baz is not allowed; instead, either (foo | bar), baz or foo | (bar, baz) must be used. A similar restriction applies to name classes and the use of the | and - operators. These restrictions are not expressed in the above EBNF but they are made explicit in the BNF in Section 1.
The value of an anyURILiteral specified with include or external is a URI reference to a grammar in the compact syntax.
Whitespace is allowed between tokens. Tokens are the strings occurring in double quotes in the EBNF in Section 2, except that literalSegment, nsName, CName, identifier and quotedIdentifer are single tokens.
Comments are also allowed between tokens. Comments start with a # and continue to the end of the line. Comments starting with ## are treated specially; see Section 5.
A Unicode character with hex code N can be represented by the escape sequence \x{N}. Using such an escape sequence is completely equivalent to the entering the corresponding character directly. For example,
element \x{66}\x{6f}\x{6f} { empty }
is equivalent to
element foo { empty }
A datatypes declaration declares a prefix used in a QName identifying a datatype. For example,
datatypes xsd = "http://www.w3.org/2001/XMLSchema-datatypes" element height { xsd:double }
In fact, in the above example, the datatypes declaration is not required: the xsd prefix is predeclared to the above URI.
A namespace declaration declares a prefix used in a QName specifying the name of an element or attribute. For example,
namespace rng = "http://relaxng.org/ns/structure/1.0" element rng:text { empty }
As in XML, the xml prefix is predeclared.
A default namespace declaration declares the namespace used for unprefixed names specifying the name of an element (but not of an attribute). For example,
default namespace = "http://example.com" element foo { attribute bar { string } }
is equivalent to
namespace ex = "http://example.com" element ex:foo { attribute bar { string } }
A default namespace declaration may have a prefix as well. For example,
default namespace ex = "http://example.com"
is equivalent to
default namespace = "http://example.com" namespace ex = "http://example.com"
The URI may be empty. This makes the prefix stand for the absent namespace URI. This is necessary for specifying a name class that matches any name with an absent namespace URI. For example:
namespace local = "" element foo { attribute * - local:* { string }* }
is equivalent to
<element xmlns="http://relaxng.org/ns/structure/1.0"" name="foo" ns="http://example.com"> <zeroOrMore> <attribute> <anyName> <except> <nsName ns=""/> </except> </anyName> <data type="string"/> </attribute> <zeroOrMore> </element>
RELAX NG has the feature that if a file does not specify an ns attribute then the ns attribute can be inherited from the including file. To support this feature, the keyword inherit can be specified in place of the namespace URI in a namespace declaration. For example,
default namespace this = inherit element foo { element * - this:* { string }* }
is equivalent to
<element xmlns="http://relaxng.org/ns/structure/1.0"" name="foo"> <zeroOrMore> <element> <anyName> <except> <nsName/> </except> </anyName> <data type="string"/> </element> <zeroOrMore> </element>
In addition, the include and external patterns can specify inherit = prefix to specify the namespace to be inherited by the referenced file. For example,
namespace x = "http://www.example.com" external "foo.rng" inherit = x
is equivalent to
<externalRef href="foo.rng" ns="http://www.example.com" xmlns="http://relaxng.org/ns/structure/1.0"/>
In the absence of an inherit parameter on include or external, the default namespace will be inherited by the referenced file.
In the absence of a default namespace declaration, a declaration of
default namespace = inherit
is assumed.
The RELAX NG XML syntax allows foreign elements and attributes to be used to annotate a RELAX NG schema. A schema in the compact syntax can also have annotations, which will turn into foreign elements and attributes when the schema is translated into XML syntax. The way these annotations are specified depends on where the foreign elements and attributes are to appear in the translated schema. There is also a special shorthand syntax when the foreign element is a documentation element as described in [Compatibility].
An annotation in square brackets can be inserted immediately before a pattern, param, nameClass, grammarContent or includeContent. It has the following syntax:
annotation | ::= | "[ " annotationAttribute* annotationElement* "] " |
annotationAttribute | ::= | name "= " literal |
annotationElement | ::= | name "[ " annotationAttribute* (annotationElement | literal)* "] " |
Each of the annotationAttributes will turn into attributes on the corresponding RELAX NG element. Each of the annotationElements will turn into initial children of the corresponding RELAX NG element, except in the case where the RELAX NG element cannot have children, in which case they will turn into following elements.
Comments starting with ## are used to specify documentation elements from the http://relaxng.org/ns/compatibility/annotations/1.0 namespace as described in [Compatibility]. For example,
## Represents a language element lang { ## English "en" | ## Japanese "jp" }
turns into
<element name="lang" xmlns:a="http://relaxng.org/ns/compatibility/annotations/1.0" xmlns="http://relaxng.org/ns/structure/1.0"> <a:documentation>Represents a language</a:documentation> <choice> <value>en</value> <a:documentation>English</a:documentation> <value>jp</value> <a:documentation>Japanese</a:documentation> </choice> </element>
## comments can only be used immediately before before a pattern, nameClass, grammarContent or includeContent. Multiple ## comments are allowed. Multiple adjacent ## comments without any intervening blank lines are merged into a single documentation element. Any ## comments must precede any annotation in square brackets.
A pattern or nameClass may be followed by any number of followAnnotations with the following syntax:
followAnnotation | ::= | ">> " annotationElement |
Each such annotationElement turns into a following sibling of the RELAX NG element representing the pattern or nameClass.
An annotationElement may be used in any place where grammarContent or includeContent is allowed. For example,
namespace x = "http://www.example.com" start = foo x:entity [ name="picture" systemId="picture.jpeg" notation="jpeg" ] foo = element foo { empty }
turns into
<grammar xmlns:x="http://www.example.com" xmlns="http://relaxng.org/ns/structure/1.0"> <start> <ref name="foo"/> </start> <x:entity name="picture" systemId="picture.jpeg" notation="jpeg"/> <define name="foo"> <element name="foo"> <empty/> </element> </define> </grammar>
If the name of such an element is a keyword, then it must be quoted with \.
There are three kinds of conformant implementation.
A validator conforming to this specification must be able to determine whether a textual object is a correct RELAX NG Compact Syntax schema as specified in Appendix A. It must also be able to determine for any XML document and for any correct RELAX NG Compact Syntax schema whether the document is valid (as defined in [RELAX NG]) with respect to the translation of the schema into XML syntax. It need not be able to output a representation of the translation of the schema into XML syntax.
The requirements in the preceding paragraph are subject to the provisions of the second paragraph of Section 8 of [RELAX NG].
A structure preserving translator must be able to translate any correct RELAX NG Compact Syntax schema into an XML document whose data model is strictly equivalent to the translation specified in Appendix A. For this purpose, two instances of the data model (as specified in Section 2 of [RELAX NG]) are considered strictly equivalent if they are identical after applying the simplifications specified in Sections 4.2, 4.3, 4.4, 4.8, 4.9 and 4.10 of [RELAX NG], with the exception that the base URI in the context of elements may differ.
The RELAX NG compact syntax is not a representation of the XML syntax of a RELAX NG schema; rather it is a representation of the semantics of a RELAX NG schema. Details of the XML syntax that were judged to be insignificant are not captured in the compact syntax. For example, in the XML syntax if the name class for an element or attribute pattern consists of just a single name, it can be expressed either as a name attribute or as a name element; however, in the compact syntax, there is only one way to express such a name class. The simplifications listed in the previous paragraph correspond to those syntactic details that are not captured in the compact syntax.
When comparing two include or externalRef patterns in the XML source for strict equivalence, the value of the href attributes are not compared; instead the referenced XML documents are compared for strict equivalence.
A non-structure preserving translator must be able to translate any correct RELAX NG Compact Syntax schema into an XML document whose data model is loosely equivalent to the translation specified in Appendix A. For this purpose, two instances of the data model (as specified in Section 2 of [RELAX NG]) are considered loosely equivalent if they are such that, after applying all the simplifications specified in Section 4 of [RELAX NG], one can be transformed into the other merely by reordering and renaming definitions. After the simplifications have been applied, the context of elements is ignored when comparing the two instances.
A validator for the compact syntax can be implemented as a combination of a non-structure preserving translator for the compact syntax and a validator for the XML syntax.
The compact syntax is specified by a grammar in BNF. The translation into the XML syntax is specified by annotations in the grammar.
The start symbol is topLevel.
The BNF description consists of a set of production rules. Each production rule has a left-hand side and right-hand side separated by ::=. The left-hand side specifies the name of a non-terminal. The right-hand side specifies a list of one or more alternatives separated by |. Each alternative consists of a sequence of terminals and non-terminals. A non-terminal is specified by a name in italics. A terminal is either a literal string in quotes or a named terminal specified by a name in bold italics. An alternative can also be specified as ε, which denotes an empty sequence of tokens.
Each alternative may be followed by references to one or more named constraints that apply to that alternative.
The translation into XML syntax is specified by associating a value with each terminal and non-terminal in the derivation. Each alternative in the BNF may be followed by an expression in curly braces, which specifies how to compute the value associated with the left-hand side non-terminal. Each terminal and non-terminal on the right-hand side can be labelled with a subscript specifying a variable name. When that variable name is used within the curly braces, it refers to the value associated with that terminal or non-terminal. If an alternative consists of a single terminal or non-terminal, then the expression in curly braces can be omitted; in this case the value of the left-hand side is the value of that terminal or non-terminal.
The result of the translation is not a string containing the XML representation of a RELAX NG schema, but rather is an instance of the data model described in Section 2 of [RELAX NG]; this instance will match the RELAX NG schema for RELAX NG.
A textual object is a correct RELAX NG Compact Syntax schema if:
The computation of the value of a non-terminal may make use of one or more arguments. When the name of such a non-terminal occurs on the left-hand side of a production, it is followed by an argument list that declares the formal arguments for the non-terminal; these formal arguments may be referred to by expressions on the right-hand side, as, for example, in simpleNameClass. When the name occurs on the right-hand side of a production, it may be followed by one or more assignments that specify the actual arguments which will be bound to the formal arguments during the computation of the value of the non-terminal. Arguments may be passed down implicitly: if there is no actual argument corresponding to a particular formal argument, then the formal argument is bound to the value of the variable with the same name as the name of the formal argument. In other words, for any variable x, a default actual argument of x := x is assumed. For example, see nameClassChoice.
In addition to explicit arguments, every non-terminal implicitly has an argument that specifies an environment for the interpretation of a pattern. By default, the implicit environment argument to each non-terminal is the same as its parent. This may be overridden for a particular non-terminal by including environment in the argument list. For example, see topLevel and preamble.
An environment specifies:
The special value inherit is used to indicate that a namespace URI should be inherited from the referencing schema.
In the initial environment used for the start symbol, xml is bound as a namespace prefix to http://www.w3.org/XML/1998/namespace, and xsd is bound as a datatype prefix to http://www.w3.org/2001/XMLSchema-datatypes; the base URI is determined as specified by [RFC 2396].
The value of an expression is one of the following:
Each terminal and non-terminal has an associated type identified by a name. A type is simply a set of values. The value of a terminal or non-terminal is always a member of the set of values identified by the name of its type. The name of the type of a terminal or non-terminal is given following the keyword returns before ::= in the production rule. Similarly, each argument has a type, which is given immediately before the name of the argument. The value of a non-terminal may also be specified to be void; no expression is given for the value of such a non-terminal, nor will the value of such a non-terminal be used in any expression.
The following types are all disjoint:
It is also useful to identify some subtypes of Xml. One type is a subtype of another if the set of values of the one type is a subset of the set of values of the other.
In addition it is useful to have the following union type.
Expressions use the following notation:
xyzzy
" denotes a string
consisting of the characters
xyzzy;<group
>
y </group>
) unless
x is equal to ( ), in which case it
returns y;<choice
>
y </choice>
) unless
x is equal to ( ), in which case it
returns y;<foo
x>
y </foo>
denotes
an XML fragment containing an element from the RELAX NG namespace with
local name foo, attributes x and
content x; the context of the element is determined
from the implicit environment argument as specified for the element
function above.topLevel returns Element ::=
preamblee topLevelBody(environment := e)x
{ x }
preamble returns Environment ::=
ε
{ environment }
| decle preamble(environment := e)d
{ d }
decl returns Environment ::=
"namespace
" namespacePrefixx "=
" namespaceURILiteraly
Constraint: xml prefix
Constraint: xml namespace URI
Constraint: duplicate declaration
{ bindPrefix(environment, x, y) }
| "default
" "namespace
" "=
" namespaceURILiteralx
Constraint: xml namespace URI
Constraint: duplicate declaration
{ bindDefault(environment, x) }
| "default
" "namespace
" namespacePrefixx "=
" namespaceURILiteraly
Constraint: xml prefix
Constraint: xml namespace URI
Constraint: duplicate declaration
{ bindDefault(bindPrefix(environment, x, y), y) }
| "datatypes
" datatypePrefixx "=
" literaly
Constraint: xsd prefix
Constraint: datatypes URI
Constraint: duplicate declaration
{ bindDatatypePrefix(environment, x, y) }
namespacePrefix returns String ::=
identifierOrKeyword
Constraint: valid prefix
datatypePrefix returns String ::=
identifierOrKeyword
namespaceURILiteral returns NamespaceURI ::=
literal
| "inherit
"
{ inherit }
topLevelBody returns Element ::=
pattern
Constraint: single element
| grammarx
{ <grammar
>
x </grammar>
}
grammar returns Elements ::=
ε
{ ( ) }
| memberx grammary
{ (x, y) }
member returns Element ::=
annotatedComponent
| annotationElementNotKeyword
annotatedComponent returns Element ::=
annotationsx componenty
{ applyAnnotations(x, y) }
component returns Element ::=
start
| define
| include
| div
start returns Element ::=
"start
" assignOpx patterny
{ <start
x>
y </start>
}
define returns Element ::=
identifierx assignOpy patternz
{ <define
name=
x
y>
z </define>
}
assignOp returns Attributes ::=
"=
"
{ ( ) }
| "|=
"
{ attribute(name("", "
combine
"), "choice
") }
| "&=
"
{ attribute(name("", "
combine
"), "interleave
") }
include returns Element ::=
"include
" anyURILiteralx optInherity optIncludeBodyz
{ <include
href=
mapSchemaRef(environment, x)
y>
z </include>
}
anyURILiteral returns String ::=
literal
Constraint: any URI
optInherit returns Attributes ::=
ε
{ makeNsAttribute(lookupDefault(environment)) }
| "inherit
" "=
" identifierOrKeywordx
{ makeNsAttribute(lookupPrefix(environment, x)) }
optIncludeBody returns Elements ::=
ε
{ ( ) }
| "{
" includeBodyx "}
"
{ x }
includeBody returns Elements ::=
ε
{ ( ) }
| includeMemberx includeBodyy
{ (x, y) }
includeMember returns Element ::=
annotatedIncludeComponent
| annotationElementNotKeyword
annotatedIncludeComponent returns Element ::=
annotationsx includeComponenty
{ applyAnnotations(x, y) }
includeComponent returns Element ::=
start
| define
| includeDiv
div returns Element ::=
"div
" "{
" grammarx "}
"
{ <div
>
x </div>
}
includeDiv returns Element ::=
"div
" "{
" includeBodyx "}
"
{ <div
>
x </div>
}
pattern returns Elements ::=
innerPattern(anno := ( ))
innerPattern(Xml anno) returns Elements ::=
innerParticle
| particleChoicex
{ applyAnnotations(anno, <choice
>
x </choice>
) }
| particleGroupx
{ applyAnnotations(anno, <group
>
x </group>
) }
| particleInterleavex
{ applyAnnotations(anno, <interleave
>
x </interleave>
) }
| annotatedDataExceptx
{ applyAnnotationsGroup(anno, x) }
particleChoice returns Elements ::=
particlex "|
" particley
{ (x, y) }
| particlex "|
" particleChoicey
{ (x, y) }
particleGroup returns Elements ::=
particlex ",
" particley
{ (x, y) }
| particlex ",
" particleGroupy
{ (x, y) }
particleInterleave returns Elements ::=
particlex "&
" particley
{ (x, y) }
| particlex "&
" particleInterleavey
{ (x, y) }
particle returns Elements ::=
innerParticle(anno := ( ))
innerParticle(Xml anno) returns Elements ::=
annotatedPrimaryx
{ applyAnnotationsGroup(anno, x) }
| repeatedPrimaryx followAnnotationsy
{ (applyAnnotations(anno, x), y) }
repeatedPrimary returns Element ::=
annotatedPrimaryx "*
"
{ <zeroOrMore
>
x </zeroOrMore>
}
| annotatedPrimaryx "+
"
{ <oneOrMore
>
x </oneOrMore>
}
| annotatedPrimaryx "?
"
{ <optional
>
x </optional>
}
annotatedPrimary returns Elements ::=
leadAnnotatedPrimaryx followAnnotationsy
{ (x, y) }
annotatedDataExcept returns Elements ::=
leadAnnotatedDataExceptx followAnnotationsy
{ (x, y) }
leadAnnotatedDataExcept returns Element ::=
annotationsx dataExcepty
{ applyAnnotations(x, y) }
leadAnnotatedPrimary returns Elements ::=
annotationsx primaryy
{ applyAnnotations(x, y) }
| annotationsx "(
" innerPattern(anno := x)y ")
"
{ y }
primary returns Element ::=
"element
" nameClass(isElem := true)x "{
" patterny "}
"
{ <element
>
x y </element>
}
| "attribute
" nameClass(isElem := false)x "{
" patterny "}
"
{ <attribute
>
x y </attribute>
}
| "mixed
" "{
" patternx "}
"
{ <mixed
>
x </mixed>
}
| "list
" "{
" patternx "}
"
{ <list
>
x </list>
}
| datatypeNamex optParamsy
{ <data
x>
y </data>
}
| datatypeNamex datatypeValuey
{ <value
x>
y </value>
}
| datatypeValuex
{ <value
>
x </value>
}
| "empty
"
{ <empty
/>
}
| "notAllowed
"
{ <notAllowed
/>
}
| "empty
"
{ <text
/>
}
| refx
{ <ref
name=
x/>
}
| "parent
" refx
{ <parentRef
name=
x/>
}
| "grammar
" "{
" grammarx "}
"
{ <grammar
>
x </grammar>
}
| "external
" anyURILiteralx optInherity
{ <externalRef
href=
mapSchemaRef(x)
y/>
}
dataExcept returns Element ::=
datatypeNamex optParamsy "-
" leadAnnotatedPrimaryz
{ <data
x>
y <except
>
z </except>
</data>
}
ref returns String ::=
identifier
datatypeName returns Attributes ::=
CNamex
{ datatypeAttributes(lookupDatatypePrefix(environment, prefix(x)), localPart(x)) }
| "string
"
{ datatypeAttributes("", "
string
") }
| "token
"
{ datatypeAttributes("", "
token
") }
datatypeValue returns String ::=
literal
optParams returns Elements ::=
ε
{ ( ) }
| "{
" paramsx "}
"
{ x }
params returns Elements ::=
ε
{ ( ) }
| paramx paramsy
{ (x, y) }
param returns Element ::=
annotationsx identifierOrKeywordy "=
" literalz
{ applyAnnotations(x, <param
name=
y>
z </param>
) }
nameClass(Boolean isElem) returns Elements ::=
innerNameClass(anno := ( ))
innerNameClass(Boolean isElem, Xml anno) returns Elements ::=
annotatedSimpleNameClassx
{ applyAnnotationsChoice(anno, x) }
| nameClassChoicex
{ applyAnnotations(anno, <choice
>
x </choice>
) }
| annotatedExceptNameClassx
{ applyAnnotationsChoice(anno, x) }
nameClassChoice(Boolean isElem) returns Elements ::=
annotatedSimpleNameClassx "|
" annotatedSimpleNameClassy
{ (x, y) }
| annotatedSimpleNameClassx "|
" nameClassChoicey
{ (x, y) }
annotatedExceptNameClass(Boolean isElem) returns Elements ::=
leadAnnotatedExceptNameClassx followAnnotationsy
{ (x, y) }
leadAnnotatedExceptNameClass(Boolean isElem) returns Element ::=
annotationsx exceptNameClassy
{ applyAnnotations(x, y) }
annotatedSimpleNameClass(Boolean isElem) returns Elements ::=
leadAnnotatedSimpleNameClassx followAnnotationsy
{ (x, y) }
leadAnnotatedSimpleNameClass(Boolean isElem) returns Elements ::=
annotationsx simpleNameClassy
{ applyAnnotations(x, y) }
| annotationsx "(
" innerNameClass(anno := x)y ")
"
{ y }
exceptNameClass(Boolean isElem) returns Element ::=
nsNamex "-
" leadAnnotatedSimpleNameClassy
{ <nsName
makeNsAttribute(lookupPrefix(environment, x))>
<except
>
y </except>
</nsName>
}
| "*
" "-
" leadAnnotatedSimpleNameClassx
{ <anyName
>
<except
>
x </except>
</anyName>
}
simpleNameClass(Boolean isElem) returns Element ::=
identifierOrKeywordx
{ <name
makeNsAttribute(isElem ? lookupDefault(environment) : "")
>
x </name>
}
| CNamex
{ <name
makeNsAttribute(lookupPrefix(environment, prefix(x)))>
localPart(x) </name>
}
| nsNamex
{ <nsName
makeNsAttribute(lookupPrefix(environment, x))/>
}
| "*
"
{ <anyName
/>
}
followAnnotations returns Elements ::=
ε
{ ( ) }
| ">>
" annotationElementx followAnnotationsy
{ (x, y) }
annotations returns Xml ::=
documentationsx
{ x }
| documentationsx "[
" annotationAttributesy annotationElementsz "]
"
{ (y, (x, z)) }
annotationAttributes returns Attributes ::=
ε
{ ( ) }
| foreignAttributeNamex "=
" literaly annotationAttributesz
Constraint: duplicate attributes
{ (attribute(x, y), z) }
foreignAttributeName returns Name ::=
prefixedName
Constraint: xmlns namespace URI
Constraint: unqualified name
Constraint: RELAX NG namespace URI
annotationElements returns Elements ::=
ε
{ ( ) }
| annotationElementx annotationElementsy
{ (x, y) }
annotationElement returns Element ::=
foreignElementNamex annotationAttributesContenty
{ element(environment, x, y) }
foreignElementName returns Name ::=
identifierOrKeywordx
{ name("", x) }
| prefixedName
Constraint: RELAX NG namespace URI
annotationElementNotKeyword returns Element ::=
foreignElementNameNotKeywordx annotationAttributesContenty
{ element(environment, x, y) }
foreignElementNameNotKeyword returns Name ::=
identifierx
{ name("", x) }
| prefixedName
Constraint: RELAX NG namespace URI
annotationAttributesContent returns Xml ::=
"[
" nestedAnnotationAttributesx annotationContenty "]
"
{ (x, y) }
nestedAnnotationAttributes returns Attributes ::=
ε
{ ( ) }
| anyAttributeNamex "=
" literaly nestedAnnotationAttributesz
Constraint: duplicate attributes
{ (attribute(x, y), z) }
anyAttributeName returns Name ::=
identifierOrKeywordx
{ name("", x) }
| prefixedName
Constraint: xmlns namespace URI
annotationContent returns Content ::=
ε
{ ( ) }
| nestedAnnotationElementx annotationContenty
{ (x, y) }
| literalx annotationContenty
{ (text(x), y) }
nestedAnnotationElement returns Element ::=
anyElementNamex annotationAttributesContenty
{ element(environment, x, y) }
anyElementName returns Name ::=
identifierOrKeywordx
{ name("", x) }
| prefixedName
prefixedName returns Name ::=
CNamex
Constraint: annotation inherit
{ name(lookupPrefix(environment, prefix(x)), localPart(x)) }
documentations returns Elements ::=
ε
{ ( ) }
| documentationx documentationsy
{ (element(environment, documentationElementName(), text(x)), y) }
identifierOrKeyword returns String ::=
identifier
| keyword
keyword returns String ::=
"attribute
"
| "default
"
| "datatypes
"
| "div
"
| "element
"
| "empty
"
| "external
"
| "grammar
"
| "include
"
| "inherit
"
| "list
"
| "mixed
"
| "namespace
"
| "notAllowed
"
| "parent
"
| "start
"
| "string
"
| "text
"
| "token
"
literal returns String ::=
literalSegment
| literalSegmentx "~
" literaly
{ stringConcat(x, y) }
It is an error if the value of a namespacePrefix is xmlns.
It is an error if the value of namespacePrefix is xml and the the value of the namespaceURILiteral is not http://www.w3.org/XML/1998/namespace.
It is an error if the value of the namespaceURILiteral is http://www.w3.org/XML/1998/namespace and the value of the namespacePrefix is not xml.
It is an error if the value of datatypePrefix is xsd and the the value of the literal is not http://www.w3.org/2001/XMLSchema-datatypes.
It is an error if the value of the literal in a datatypes declaration is not a syntactically legal value for a datatypeLibrary as specified in Section 3 of [RELAX NG].
It is an error if there is more than one namespace declaration of a particular prefix, more than one default namespace declaration or more than one declaration of a particular datatypes prefix.
It is an error if a top-level pattern translates to a sequence of more than one element (which can happen as the result of the use of annotations).
It is an error if the namespace URI of a prefixedName in a foreignAttributeName is the empty string.
It is an error if the namespace URI of a prefixedName in a foreignElementName, a foreignElementNameNotKeyword or a foreignAttributeName is the RELAX NG namespace URI http://relaxng.org/ns/structure/1.0.
It is an error if the namespace URI of a prefixedName in a foreignAttributeName or an anyAttributeName is http://www.w3.org/2000/xmlns.
It is an error if a nestedAnnotationAttributes or an annotationAttributes contains two attributes with the same namespace URI and local name.
It is an error if the namespace URI in the value of a prefixedName is inherit.
This section describes how to transform the textual representation of a RELAX NG schema in compact syntax into a sequence of tokens, which can be parsed using the grammar specified in Section 1.
There are five distinct stages, which are logically consecutive; the result of each stage is the input to the following stage.
The textual representation of the RELAX NG schema in compact syntax may be either a sequence of Unicode characters or a sequence of bytes. In the latter case, the first stage is to transform the sequence of bytes to the sequence of characters. The sequence of bytes may have associated metadata specifying the encoding. One example of such metadata is the charset parameter in a MIME media type [RFC 2046]. If there is such metadata, then the specified encoding is used. Otherwise, the first two bytes of the sequence are examined. If these are #xFF followed by #xFE or #xFE followed by #xFF, then an encoding of UTF-16 [Unicode] will be used, little-endian in the former case, big-endian in the latter case. Otherwise an encoding of UTF-8 [Unicode] is used. It is an error if the sequence of bytes is not a legal sequence in the selected encoding.
If the first character of the sequence is a byte order mark (#xFEFF), then it is removed.
Representations of newlines are normalized to a newline marker. Specifically, each occurrence of
is transformed to a newline marker. The result of this stage is thus a sequence whose members are Unicode characters and newline markers.
In this stage, each escape sequence of the form \x{n}, where n is a hexadecimal number, is replaced by the character with Unicode code n. The escape sequence must match the production escapeSequence; the value computed in the BNF is the Unicode code of the replacement character. It is an error if the replacement character does not match the Char production of [XML 1.0]. It is an error if the input character sequence contains a character sequence escapeOpen that does not start an escapeSequence. After an escape sequence has been replaced, scanning for escape sequences continues following the replacement character; thus \x{5C}x{5C} is transformed to \x{5C} not to \. The replacement for \x{A} or \x{D} is a character, as for all other escape sequences, not a newline marker. Thus the sequence that results from this stage can contain #xA and #xD characters as well as newline markers.
The \ character that opens an escape sequence may be followed by more than one x. This makes it possible for there to be a reversible transformation that maps a schema to a form containing only ASCII characters; the transformation replaces adds an extra x to each existing escape sequence, and replaces every non-ASCII character by an escape sequence with exactly one x.
escapeSequence returns Number ::=
escapeOpen hexNumberx escapeClose
{ x }
escapeOpen returns Void ::=
"\
" xs "{
"
xs returns Void ::=
"x
"
| "x
" xs
escapeClose returns Void ::=
"}
"
hexNumber returns Number ::=
hexDigit
| hexNumberx hexDigity
{ (x * 16) + y }
hexDigit returns Number ::=
"0
"
{ 0 }
| "1
"
{ 1 }
| "2
"
{ 2 }
| "3
"
{ 3 }
| "4
"
{ 4 }
| "5
"
{ 5 }
| "6
"
{ 6 }
| "7
"
{ 7 }
| "8
"
{ 8 }
| "9
"
{ 9 }
| [A
a
]
{ 10 }
| [B
b
]
{ 11 }
| [C
c
]
{ 12 }
| [D
d
]
{ 13 }
| [E
e
]
{ 14 }
| [F
f
]
{ 15 }
In this stage, the sequence of characters and newline markers is tokenized: it is transformed into a sequence of tokens, where each token corresponds to a terminal in the grammar in Section 1.
A sequence of characters and newline markers is tokenized by first finding the longest initial subsequence that:
If the longest such initial subsequence matches separator, this subsequence is discarded. Otherwise, a single non-terminal is produced from this initial subsequence. In either case, the tokenization proceeds with the rest of the sequence. It is an error if there is no such initial subsequence.
The production rules below use some additional notation. Square brackets enclose a character class. A character class of the form [^chars] specifies any legal XML character that does not occur in chars. A legal XML character is a character that matches the Char production of [XML 1.0]. A character class of the form [chars], where chars does not being with ^, specifies any single character that occurs in chars. XML hexadecimal character references are used to denote a single character, as in XML. A newline marker is denoted by &newline;. NCName is defined in [XML Namespaces].
The value of a variable bound to a character class is a string of length 1 containing the character that matched the character class; if the character class matches a newline marker, then the string contains the character #xA.
identifier returns String ::=
NCNamex - keyword
{ x }
| "\
" NCNamex
{ x }
CName returns Qname ::=
NCNamex ":
" NCNamey
{ qName(x, y) }
nsName returns String ::=
NCNamex ":*
"
{ x }
literalSegment returns String ::=
""
" stringNoQuotx ""
"
{ x }
| "'
" stringNoAposx "'
"
{ x }
| """"
" stringNoTripleQuotx """"
"
{ x }
| "'''
" stringNoTripleAposx "'''
"
{ x }
stringNoQuot returns String ::=
ε
{ "" }
| [^"
&newline;]x stringNoQuoty
{ stringConcat(x, y) }
stringNoApos returns String ::=
ε
{ "" }
| [^'
&newline;]x stringNoAposy
{ stringConcat(x, y) }
stringNoTripleQuot returns String ::=
ε
{ "" }
| [^"
]x stringNoTripleQuoty
{ stringConcat(x, y) }
| ""
" [^"
]x stringNoTripleQuoty
{ stringConcat(""
", x, y) }
| """
" [^"
]x stringNoTripleQuoty
{ stringConcat("""
", x, y) }
stringNoTripleApos returns String ::=
ε
{ "" }
| [^'
]x stringNoTripleAposy
{ stringConcat(x, y) }
| "'
" [^'
]x stringNoTripleAposy
{ stringConcat("'
", x, y) }
| "''
" [^'
]x stringNoTripleAposy
{ stringConcat("''
", x, y) }
documentation returns String ::=
documentationLine
| documentationx documentationContinuationy
{ stringConcat(x, y) }
documentationLine returns String ::=
"##
" documentationLineContentx
{ x }
documentationContinuation returns String ::=
[&newline;
]x indent documentationLiney
{ stringConcat(x, y) }
indent returns Void ::=
ε
| [	 ]x indent
documentationLineContent returns String ::=
ε
{ "" }
| "#
" documentationLineContentx
{ x }
| "
" restOfLinex
{ x }
| [^&newline;

#
]x restOfLiney
{ stringConcat(x, y) }
restOfLine returns String ::=
ε
{ "" }
| [^&newline;
]x restOfLiney
{ stringConcat(x, y) }
separator returns Void ::=
[	
 &newline;]
| "#
" [^&newline;
#
] restOfLine
| "#
"
# RELAX NG XML syntax specified in compact syntax. default namespace rng = "http://relaxng.org/ns/structure/1.0" namespace local = "" datatypes xsd = "http://www.w3.org/2001/XMLSchema-datatypes" start = pattern pattern = element element { (nameQName | nameClass), (common & pattern+) } | element attribute { (nameQName | nameClass), (common & pattern?) } | element group|interleave|choice|optional |zeroOrMore|oneOrMore|list|mixed { common & pattern+ } | element ref|parentRef { nameNCName, common } | element empty|notAllowed|text { common } | element data { type, param*, (common & exceptPattern?) } | element value { commonAttributes, type?, xsd:string } | element externalRef { href, common } | element grammar { common & grammarContent* } param = element param { commonAttributes, nameNCName, xsd:string } exceptPattern = element except { common & pattern+ } grammarContent = definition | element div { common & grammarContent* } | element include { href, (common & includeContent*) } includeContent = definition | element div { common & includeContent* } definition = element start { combine?, (common & pattern+) } | element define { nameNCName, combine?, (common & pattern+) } combine = attribute combine { "choice" | "interleave" } nameClass = element name { commonAttributes, xsd:QName } | element anyName { common & exceptNameClass? } | element nsName { common & exceptNameClass? } | element choice { common & nameClass+ } exceptNameClass = element except { common & nameClass+ } nameQName = attribute name { xsd:QName } nameNCName = attribute name { xsd:NCName } href = attribute href { xsd:anyURI } type = attribute type { xsd:NCName } common = commonAttributes, foreignElement* commonAttributes = attribute ns { xsd:string }?, attribute datatypeLibrary { xsd:anyURI }?, foreignAttribute* foreignElement = element * - rng:* { (anyAttribute | text | anyElement)* } foreignAttribute = attribute * - (rng:*|local:*) { text } anyElement = element * { (anyAttribute | text | anyElement)* } anyAttribute = attribute * { text }