It’s good to design extensible schemas, but they make an impact only on developers who can extend our initial schema. A document valid per an extended flavor of our schema is likely to be invalid per our original schema.
By contrast, an open schema lets instances be extensible and allows the addition of content while still remaining valid against the original schema. Of course because the additions are unpredictable, the validation of their structure will be very lax, but extended documents will still be considered valid.
Designing and using open schemas is quite challenging because it gives more power to the XML user, and unexpected situations may result. The use of open schemas also conflicts with some best practices of schema usage: a totally open schema validates any well-formed XML document and is thus totally useless. On the other hand, closed schemas violate the fundamental principle of extensibility of XML, the extensible markup language.
There are several levels of openess from a totally closed schema in which nothing unexpected can happen, to the most extreme case, which allows any well-formed document. In RELAX NG, name classes (introduced in Chapter 10) are the basic blocks that will let you build the wildcards needed to open a schema We’ll take a closer look at name classes before presenting the constructions most often used in open schemas.
Here I’ll first recap the name classes seen in the
previous chapter. You’ve seen how to use
anyName
to match any name from any namespace in
the context of an element or an attribute:
<define name="anything"> <zeroOrMore> <choice> <element> <anyName/> <ref name="anything"/> </element> <attribute> <anyName/> </attribute> <text/> </choice> </zeroOrMore> </define>
or:
anything = ( element * { anything } | attribute * { text } | text )*
Then you saw how to remove specific
namespaces
from anyName
using except
and
nsName
:
<define name="foreign-elements"> <zeroOrMore> <element> <anyName> <except> <nsName ns=""/> <nsName ns="http://eric.van-der-vlist.com/ns/library"/> <nsName ns="http://eric.van-der-vlist.com/ns/person"/> </except> </anyName> <ref name="anything"/> </element> </zeroOrMore> </define>
or:
default namespace lib = "http://eric.van-der-vlist.com/ns/library" namespace local = "" namespace hr = "http://eric.van-der-vlist.com/ns/person" .../... foreign-elements = element * - (local:* | lib:* | hr:*) { anything }*
The two name class elements except
and
nsName
shown in this example can be used
independently. To define a name class for any
name from the lib
namespace, I can write:
<element> <nsName ns="http://eric.van-der-vlist.com/ns/library"/> <ref name="anything"/> </element>
or:
element lib:* { anything }
Elements and attributes have one and only one name.
It’s meaningless to associate them with several name
classes, unless you do it using choice
. The
choice
element provides a method of
combining name classes. To define a name class for any name from the
lib
or hr
namespaces, I can
write:
<element> <choice> <nsName ns="http://eric.van-der-vlist.com/ns/library"/> <nsName ns="http://eric.van-der-vlist.com/ns/person"/> </choice> <ref name="anything"/> </element>
or:
element lib:* | hr:* { anything }
Finally, there is also a name class that operates on
specific element or attribute names. To define a name class
lib:name
or hr:name
, I can
write:
<element> <choice> <name>libname</name> <name>hrname</name> </choice> <ref name="anything"/> </element>
or:
element lib:name | hr:name { text }
Note that the name
name class expects a qualified
name. These name classes can be combined pretty much as you like. You
can also define a name class for any name from the
hr
namespace except the known elements:
<element> <nsName ns=ns="http://eric.van-der-vlist.com/ns/person"/> <except> <name>hr:author</name> <name>hr:name</name> <name>hr:born</name> <name>hr:dead</name> <except> </nsName> <ref name="anything"/> </element>
or:
element hr:* - ( hr:author | hr:name | hr:born | hr:dead ) { anything }
This definition allows for future extension of the
hr
namespace.
13.58.149.129