Copyright (c) 2001-2003 Thai Open Source Software Center Ltd
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
jing-trang-20131210+dfsg+1/copying.txt 0000664 0000000 0000000 00000003021 12253666075 0017301 0 ustar 00root root 0000000 0000000 Copyright (c) 2001-2003 Thai Open Source Software Center Ltd All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. Neither the name of the Thai Open Source Software Center Ltd nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. jing-trang-20131210+dfsg+1/datatype-sample/ 0000775 0000000 0000000 00000000000 12253666075 0020166 5 ustar 00root root 0000000 0000000 jing-trang-20131210+dfsg+1/datatype-sample/build.xml 0000664 0000000 0000000 00000001135 12253666075 0022007 0 ustar 00root root 0000000 0000000This package contains a very simple example of a pluggable datatype library.
The datatype library is implemented by the class
com.thaiopensource.datatype.sample.BalancedString
. The
bulk of the implementation is inherited from the abstract class
com.thaiopensource.datatype.sample.SimpleDatatypeLibrary
,
which provides default implementations for the methods in the
interfaces which a datatype library must implement. A class that
derives from SimpleDatatypeLibrary
has only to implement
a boolean isValid(String literal)
method. The datatype
library has the URI
http://www.thaiopensource.com/relaxng/datatypes/sample
,
and contains exactly one datatype, which is called
balancedString
. This datatype allows any string in which
parentheses are properly balanced (nested). To use this sample
datatype library, simply include datatype-sample.jar
in
your CLASSPATH. You will then be able to validate against schemas
using this additional datatype. The file datatype-sample.rng is a simple RELAX
NG schema using this datatype; valid.xml is an
instance that is valid with respect to this schema; invalid.xml is an instance that is not valid
with respect to this schema.
The RELAX NG Compact Syntax is compact, non-XML syntax for RELAX NG. It is now defined by an OASIS Committee Specification.
The following tools provide support for the syntax:
-c
option is usedThe compact syntax is now described by the RELAX NG Compact Syntax Committee Specification.
jing-trang-20131210+dfsg+1/doc/derivative.xml 0000664 0000000 0000000 00000101476 12253666075 0020536 0 ustar 00root root 0000000 0000000 ]>This document describes an algorithm for validating an XML document against a RELAX NG schema. This algorithm is based on the idea of what's called a derivative (sometimes called a residual). It is not the only possible algorithm for RELAX NG validation. This document does not describe any algorithms for transforming a RELAX NG schema into simplified form, nor for determining whether a RELAX NG schema is correct.
We use Haskell to describe the algorithm. Do not worry if you don't know Haskell; we use only a tiny subset which should be easily understandable.
First, we define the datatypes we will be using. URIs and local names are just strings.
A ParamList
represents a list of parameters; each parameter
is a pair consisting of a local name and a value.
A Context
represents the context of an XML element.
It consists of a base URI and a mapping from prefixes to namespace
URIs.
A Datatype
identifies a datatype by a datatype library name
and a local name.
A NameClass
represents a name class.
A Pattern
represents a pattern after simplification.
The After
pattern is used internally and will be
explained later.
Note that there is an Element
pattern rather than a
Ref
pattern. In the simplified XML representation of
patterns, every ref
element refers to an
element
pattern. In the internal representation of
patterns, we can replace each reference to a ref
pattern
by a reference to the element
pattern that the
ref
pattern references, resulting in a cyclic data
structure. (Note that even though Haskell is purely functional it can
handle cyclic data structures because of its laziness.)
In the instance, elements and attributes are labelled with QNames; a QName is a URI/local name pair.
An XML document is represented as a ChildNode
. There are
two kinds of child node:
TextNode
containing a string;ElementNode
containing a name (of type
QName
), a Context
, a set of attributes
(represented as a list of AttributeNode
s, each of which
will be an AttributeNode
), and a list of children
(represented as a list of ChildNode
s).An AttributeNode
consists of a String
.
Now we're ready to define our first function: contains
tests whether a
In Haskell, _
is an anonymous variable
that matches any argument.
nullable
tests whether a pattern matches the empty
sequence.
The key concept used by this validation technique is the concept of a derivative. The derivative of a pattern p with respect to a node x is a pattern for what's left of p after matching x; in other words, it is a pattern that matches any sequence that when appended to x will match p.
If we can compute derivatives, then we can determine whether a pattern matches a node: a pattern matches a node if the derivative of the pattern with respect to the node is nullable.
It is desirable to be able to compute the derivative of a node in a streaming fashion, making a single pass over the tree. In order to do this, we break down an element into a sequence of components:
We compute the derivative of a pattern with respect to an element by computing its derivative with respect to each component in turn.
We can now explain why we need the After
pattern. A
pattern After x y
is a pattern that
matches x
followed by an end-tag followed by
y
. We need the After
pattern in
order to be able to express the derivative of a pattern with respect
to a start-tag open.
The central function is childNode
which computes the
derivative of a pattern with respect to a
textDeriv
computes the derivative of a pattern with
respect to a text node.
Choice
is easy:
Interleave
is almost as easy (one of the main
advantages of this validation technique is the ease with which it
handles interleave):
For Group
, the derivative depends on whether
the first operand is nullable.
For After
, we recursively apply textDeriv
to the first argument.
For OneOrMore
we partially expand the
OneOrMore
into a Group
.
A text
pattern matches zero or more text nodes. Thus
the derivative of Text
with respect to a text node is
Text
, not Empty
.
The derivative of a value
, data
or
list
pattern with respect to a text node is
Empty
if the pattern matches and NotAllowed
if it does not.
To determine whether a value
or data
pattern matches, we rely respectively on the
To determine whether a pattern List p
matches a text node, the value of the text node is split into a
sequence of whitespace-delimited tokens, and the resulting sequence is
matched against p
:
In any other case, the pattern does not match the node.
To compute the derivative of a pattern with respect to a list of strings, simply compute the derivative with respect to each member of the list in turn.
In Haskell, []
refers to the empty list.
When constructing Choice
, Group
,
Interleave
and After
patterns while
computing derivatives, we recognize the obvious algebraic identities
for NotAllowed
and Empty
:
The datatypeAllows
and datatypeEqual
functions represent the semantics of datatype libraries. Here, we
specify only the semantics of the builtin datatype library.
Perhaps the trickiest part of the algorithm is in computing the
derivative with respect to a start-tag open. For this,
we need a helper function; applyAfter
takes
a function and applies it to the second operand of
each After
pattern.
We rely here on the fact that After
patterns are
restricted in where they can occur. Specifically, an
After
pattern cannot be the descendant of any pattern
other than a Choice
pattern or another After
pattern; also the first operand of an After
pattern can
neither be an After
pattern nor contain any
After
pattern descendants.
The derivative of a Choice
pattern is as usual.
To represent the derivative of a Element
pattern,
we introduce an After
pattern.
For Interleave
, OneOrMore
Group
or After
we compute the derivative in a
similar way to textDeriv
but with an important twist.
The twist is that instead of applying interleave
,
group
and after
directly to the result of
recursively applying startTagOpenDeriv
, we instead use
applyAfter
to push the interleave
,
group
or after
down into the second operand
of After
. Note that the following definitions ensure
that the invariants on where After
patterns can occur are
maintained.
We make use of the standard Haskell function flip
which flips the order of the arguments of a function of two arguments.
Thus, flip
applied to a function of two arguments
f and an argument x returns a function of one
argument g such that g(y) =
f(y, x).
In any other case, the derivative is NotAllowed
.
To compute the derivative of a pattern with respect to a sequence of attributes, simply compute the derivative with respect to each attribute in turn.
Computing the derivative with respect to an attribute done in a
similar to computing the derivative with respect to a text node. The
main difference is in the handling of Group
, which has to
deal with the fact that the order of attributes is not significant.
Computing the derivative of a Group
pattern with respect
to an attribute node works the same as computing the derivative of an
Interleave
pattern.
valueMatch
is used for matching attribute values. It
has to implement the RELAX NG rules on whitespace: see (weak match 2)
in the RELAX NG spec.
When we see a start-tag close, we know that there cannot be any
further attributes. Therefore we can replace each
Attribute
pattern by NotAllowed
.
When constructing a OneOrMore
, we need to treat an
operand of NotAllowed
specially:
Computing the derivative of a pattern with respect to a list of children involves computing the derivative with respect to each pattern in turn, except that whitespace requires special treatment.
The case where the list of children is empty is treated as if there were a text node whose value were the empty string. See rule (weak match 3) in the RELAX NG spec.
In the case where the list of children consists of a single text
node and the value of the text node consists only of whitespace, the
list of children matches if the list matches either with or without
stripping the text node. Note the similarity with
Otherwise, there must be one or more elements amongst the children, in which case any whitespace-only text nodes are stripped before the derivative is computed.
whitespace
tests whether a string is contains
only whitespace.
Computing the derivative of a pattern with respect to an end-tag is
obvious. Note that we rely here on the invariants about where
After
patterns can occur.
nullable
The nullability of a pattern can be determined straightforwardly as
the pattern is being constructed. Instead of computing
nullable
repeatedly, it should be computed once when the
pattern is constructed and stored as a field in the pattern.
Additional optimizations become possible if it is possible to
efficiently determine whether two patterns are equal. We don't want to
have to completely walk the structure of both patterns to determine
equality. To make efficient comparison possible, we intern
patterns in a hash table. Two interned patterns are equal if and only
if they are the same object (i.e. ==
in Java terms).
(This is similar to the way that String
s are interned to
make Symbol
s which can be compared for equality using
==
.) To make interning possible, there are two notions
of identity defined on patterns each with a corresponding hash
function:
==
or Object.equals
in Java); for a hash function, we can
use Object.hash
in Java or the address of the object in
C/C++To intern patterns, we maintain a set of patterns implemented as a hash table. The hash table used uninterned identity and the corresponding uninterned hash function. When a new pattern is constructed, any subpatterns must first be interned. The pattern is interned by looking it up in the hash table. If it is found, we throw the new pattern away and instead return the existing entry in the hash table. If it is not found, we store the pattern in the hash table before returning it. (This is basically hash-consing.)
In order to avoid exponential blowup with some patterns, it is
essential for the Choice
pattern and the empty-list otherwise.
Eliminating redundant choices means ensuring that the list of
choice-leaves of the constructed pattern contains no duplicates. One
way to do this is to for
Memoization is an optimization technique that can be applied to any pure function that has no side-effects and whose return value depends only on the value of its arguments. The basic idea is to remember function calls. A table is maintained that maps lists of arguments values to previously computed return values for those arguments. When a function is called with a particular list of arguments, that list of arguments is looked up in the table. If an entry is found, then the previously computed value is returned immediately. Otherwise, the value is computed as usual and then stored in the table for future use.
The functions startTagOpenDeriv
,
startTagCloseDeriv
and endTagDeriv
defined
above can be memoized efficiently.
Memoizing textDeriv
is suboptimal because although the
textDeriv
takes the string value of the text node and the
context as arguments, in many cases the result does not depends on
these arguments. Instead we can distinguish two different cases for
the content of an element. One case is that the content contains no
elements (i.e. it's empty or consists of just a string). In this case,
we can first simplify pattern using a textOnlyDeriv
that
replaces each Element
pattern by NotAllowed
.
This can be efficiently memoized.
In this case, textOnlyDeriv
will always be followed
by endTagDeriv
, so we can fold the functionality
of endTagDeriv
into textOnlyDeriv
.
In the other case, the content of the element contains one or more
child elements. In this case, any text nodes can match only
Text
patterns (because of the restrictions in section 7.2
of the RELAX NG specification). The derivative of a Text
pattern with respect to a text node does not depend on either the
value of the text node or the context. We therefore introduce a
mixedTextDeriv
function, which can be efficiently
memoized, for use in this case.
Another important special case of textDeriv
that can
be memoized efficiently is when we can determine statically that a
pattern is consistent with some datatype. More precisely, we can
define a pattern p to be consistent with a datatype
d if and only if for any two strings
s1 s2, and any two
contexts c1 c2, if
datatypeEqual
d s1 c1 s2 c2,
then
textDeriv
c1 p s1
is the same as
textDeriv
c2 p s2.
In this case, we can combine the string and context arguments into a
single argument representing the value of the datatype that the string
represents in the context; this can be much more efficiently memoized
than the general case.
The attDeriv
function can be memoized more efficiently
by splitting it into two function. The first function is a
startAttributeDeriv
function that works like
startTagOpenDeriv
and depends just on the
QName
of the attribute. The second stage works in the
same way to the case when the children of an element contain a single
string.
So far, the algorithms presented do nothing more than compute whether or not the node is valid with respect to the pattern. However, a user will not appreciate a tool that simply reports that the document is invalid, without giving any indication of where the problem occurs or what the problem is.
The most important thing is to detect invalidity as soon as possible. If an implementation can do this, then it can tell the user where the problem occurs and it can protect the application from seeing invalid data. If we consider the XML document to be a sequence of SAX-like events, then detecting the error as soon as possible, means that the implementation must detect when an initial sequence s of events is such that there is no valid sequence of events that starts with s.
This is straightforward with the algorithm above. Detecting the
error as soon as possible is equivalent to detecting when the current
pattern becomes NotAllowed
. Note that this relies on the
NotAllowed
. The current pattern immediately
before it becomes NotAllowed
describes what was expected
and can be used to diagnose the error.
It some scenarios it may be sufficient to produce a single error message for an invalid document, and to cease validation as soon as it is determined that the document is invalid. In other scenarios, it may desirable to attempt to recover from the error and continute validation so as to find subsequent errors in the document. Jing recovers from validation errors as follows:
Group
optional and then retries
startTagOpenDeriv
. If this still causes an error, then
the purposes of validating following siblings, it ignores the
element. For the purpose of validating the element itself, it searches
the whole schema for element
patterns with a name class
that contains the name of the start-tag open. If it finds one or more
such element
patterns, then it uses a choice
of the content of all element
patterns that have a
name-class that contains the name of the start-tag open with maximum
specificity. A name-class that contains the name by virtue of a
name
element is considered more specific than one that
contains the name by virtue of a nsName
or
anyName
element; similarly, a name-class that contains
the name by virtue of a nsName
element is considered more
specific than one that contains the name by virtue of a
anyName
element. If there is no such element pattern,
then it validates only any maximal subtrees rooted in an element for
which the schema does contain an element
pattern. Anything outside the maximal subtrees is ignored.startAttributeDeriv
causes an error, then it
recovers by ignoring the attribute.attribute
patterns by
empty
.After
patterns (i.e. After
patterns not
inside another After
pattern) by empty
.choice
of the second operands of all top-level
After
patterns.Dongwon Lee, Murali Mani, Makoto Murata. Reasoning about XML Schema Languages using Formal Language Theory. 2000. See http://citeseer.nj.nec.com/lee00reasoning.html.
Janusz A. Brzozowski. Derivatives of Regular Expressions. Journal of the ACM, Volume 11, Issue 4, 1964.
Mark Hopkins. Regular Expression Package. Posted to comp.compilers, 1994. Available from ftp://iecc.com/pub/file/regex.tar.gz.
choice
element that can be applied uniformly to elements,
attributes, datatypes and enumerated values. This is not mere
syntactic overloading. The choice
element has a single
uniform semantic in all these cases and can have a single
implementation. Another example is the grammar
element,
which is the container for definitions. The grammar
element is just another pattern and can be composed in just the same
way as other patterns. Composability improves ease of learning and
ease of use. Composability also tends to improve the ratio between
complexity and power: for a given amount of complexity, a more
composable language will be more powerful than a less composable
one.choice
element. Closure under union implies that the
content model of an element can be context dependent. This is a major
difference from XML DTDs, which requires an element of the particular
name to use the same content model throughout the document. The
design of RELAX NG is informed by the theory of finite tree automata
|,*+?
) correspond to operations on such sets. For
example, the choice operator (|
) corresponds to set
union. To extend content models to include attributes, we first
augment the content of an XML element with its attributes; instead of
the content of an element, we use an attribute-set/content pair. The
content is a sequence of elements and strings as before. The
attribute set is a set of name/value pairs. An extended content model
thus denotes a set of attribute-set/content pairs. Each of the
content model operators can be applied in a natural way to these sets
of pairs. For example, the choice operator corresponds to set union
just as before. The sequence operator (,
) concatenates
the content sequences occurring in its operands, but unions the
attribute-sets. This ensures that the extended content models respect
the unorderedness of attributes. At first, it might seem that the
repetition operators (*+
) make no sense for attributes,
but in fact, when wildcards are allowed for attribute names,
repetition of attributes becomes necessary. Although the theory
underlying extended content models is a little tricky, in practice
they are both easy to use and very powerful.choice
element to be applied to datatypes
just as it is to elements or attributes. Derivation by list is
provided in RELAX NG by the list
element. The
list
element allows the normal RELAX NG content model
operators (group
, interleave
,
choice
, oneOrMore
, zeroOrMore
,
optional
) to be used for specifying the sequence of
tokens comprising the list. It is more powerful than the W3C XML
Schema Part 2, which allows only a minimum and maximum length for the
number of tokens in the sequence to be specified .#PCDATA
in
content models. However, SGML suffers from the infamous pernicious
mixed content bug, which causes certain content models involving
#PCDATA
to treat whitespace between tags as significant
in surprising ways. This bug in SGML motivated XML to drastically
restrict the use of #PCDATA
in content models.
Unfortunately, this prohibits many perfectly reasonable content
models. RELAX NG restores the generality of SGML by removing the
restriction on #PCDATA
. (In RELAX NG,
#PCDATA
is represented by a text
element.)
It solves the pernicious mixed content bug by observing that the
pernicious mixed content bug only arises in SGML because SGML parsers
need to report whether whitespace is significant and
insignificant. RELAX NG does no modify or augment the infoset and it
therefore does not need to decide whether whitespace in mixed
content is significant. RELAX NG can therefore lift the restriction
imposed by XML without reintroducing the problem that motivated the
imposition of the restriction.&
operator: A &
B
matches A
followed by B
or
B
followed by A
. XML removed the
&
operator. RELAX NG reintroduces it with a twist.
In SGML, a content model of A & B*
requires all the
B
elements to be consecutive: the required A
element cannot occur in between two B
elements. Usually,
users use the &
operator because they want to allow
child elements to occur in any order, so this restriction is
undesirable. In RELAX NG, the corresponding operator has interleaving
semantics. It matches any interleaving of a sequence containing a
single A
element and a sequence containing zero or more
B
elements; it thus allows the A
element to
occur anywhere, including between two B
elements.&
operator mainly because of
the &
operator's reputation for implementation
complexity. The most difficult part of implementing the
&
operator in SGML is detecting whether a content
model including &
is 1-unambiguous. Unlike SGML, XML
and W3C XML Schema, RELAX NG does not restrict content models to be
1-unambiguous, so this implementation difficulty is removed. The
classic implementation technique for SGML and XML content models is to
construct a Glushkov automaton. The 1-unambiguity restriction is
helpful for this technique because it ensures that the Glushkov
automaton is deterministic. An interleaving operator causes
difficulty with this technique. However, there is an alternative
implementation technique available rdf:Description
, rdf:RDF
,
rdf:ID
, rdf:about
,
rdf:aboutEach
, rdf:bagID
,
rdf:parseType
or rdf:resource
. An important
feature of RELAX NG is that the name of an element is specified
independently of its attributes and content. When the name of an
element is specified as an open name class, all the normal facilities
of RELAX NG remain available for specifying its attributes and
content. For example, in XSLT an element such as xsl:if
can contain certain specific elements from the XSLT namespace and
arbitrary elements from non-XSLT namespaces. These non-XSLT elements
specify literal result elements; although the names of these elements
can be from any non-XSLT namespace, their contents have the same
constraints as elements from the XSLT namespace such as
xsl:if
. RELAX NG's support for extensibility avoids
making any assumptions about what extensibility policies are
appropriate for schemas, but instead provides general facilities that
are sufficient to describe almost any extensibility policy that a
schema author may choose.include
element that references the
schema containing the overridden definition, in a similar fashion to
the internal subset of a DOCTYPE
declaration. This gives
schema authors the freedom to order their definitions as they see fit.
It also makes it explicit when a definition is overriding another
definition. The other improvement is that RELAX NG allows multiple
definitions to be combined together. This is similar to the way that
XML 1.0 DTDs allow multiple attribute list declarations for a single
element type. Unlike XML 1.0 DTDs, RELAX NG requires schema authors
to indicate explicitly when a definition is to be combined (by using a
combine
attribute) and allows combination of arbitrary
patterns using either the interleave
or
choice
operator rather than restricting the facility to
just attributes.xsi:type
attribute is a special case; it is the only
attribute that can affect the content model of an element. In RELAX
NG, any attribute can affect the content model in a quite general way.
Thus, in situations where W3C XML Schema forces the use of the
xsi:type
attribute, RELAX NG allows the schema designer
to choose the attribute name (or indeed choose to use a subelement
instead of an attribute).DOCTYPE
declaration to identify the DTD with respect to which it is valid.
There is no provision for a document to be validated with respect to
DTD that is specified independently of the document. This is
unsatisfactory for interchange. When a document recipient receives a
document from an untrusted sender, the recipient may need to check
that the document is valid with respect to a particular DTD. The
recipient cannot assume that the DOCTYPE
declaration of
the document correctly identifies that DTD. The recipient may want to
validate against a DTD different from that used by the author: for
example, the recipient may validate against a generalized, public DTD,
whereas the author may validate against a restrictive, private DTD
that is a subset of the public DTD. Unlike XML 1.0, RELAX NG does not
tie a document to a single schema. The RELAX NG validation process
has two inputs: a document and a schema against which to validate the
document.xsi:nil
attribute to deal with this. The situation with
RELAX NG is different. RELAX NG can handle both of the above
requirements. Thus, there is no need for RELAX NG to provide any
special facility for database NULLs. If it is desired to standardize
a representation of NULL, then this can be done without changing RELAX
NG. Indeed, it is possible for RELAX NG explicitly to model the
semantics of xsi:nil
that are built-in to W3C XML
Schema.Note:
This page contains pointers to documents describing various aspects of implementing RELAX NG.
The following are available:
grammar
,
define
, ref
and parentRef
For some background on implementing validation of schemas in XML, see Taxonomy of XML Schema Languages using Formal Language Theory.
James Clark