At this point, you may be wondering why we need a chapter about namespaces; after all since the very first example our schemas include an attribute from the xml:lang namespace and that doesn't seem like a big deal.

If you think about it more carefully, you'll see that namespaces are presenting two different challenges to schema languages. The first is syntactical: schema languages need to provide a way to define to which namespaces belong the elements and attributes which are described; the second is how schema languages can cope with the extensibility which is one of the objectives of XML namespaces.

In this chapter, we'll have a closer look at these two challenges before seeing how Relax NG addresses them.

!!!A ten minutes guide to XML namespaces
Let's go back to the motivations beyond XML Namespaces. The first and basic one is to be a kind of replacement for the XML (SGML inherited) doctype public identifier and provide an way to identify which vocabulary, i.e. which set of names is being used in a document. The XML/SGML way of identifying the vocabulary used in our library would be to add a public identifier in the document type declaration such as:

 <?xml version="1.0"?>
 <!DOCTYPE library PUBLIC "-//ERICVANDERVLIST//DTD for library//EN" "library.dtd"/>
 <library>
 .../...
 </library>

One of the downsides of this method is that it doesn't totally decouple the identification of the vocabulary ("-//ERICVANDERVLIST//DTD for library//EN") from the location of the DTD describing the vocabulary ("library.dtd"): I can't identify without giving the location! This is normal since in fact, the identification is the identification of the DTD rather than the identification of the abstract set of names.

The first goal of XML namespaces is to provide identifiers for this abstract notion of "vocabulary", "set of names" or simply "namespaces" without linking these identifiers to any technical implementation (DTD, schemas or whatever) defining or enforcing what they are. These identifiers are no longer public identifiers like those used in doctype declarations but URIs (or rather to be picky "URI references") and to assign a namespace to all the elements from our example, we could write:

 <?xml version="1.0"?>
 <library xmlns="http://eric.van-der-vlist.com/ns/library">
 .../...
 </library>

The identifier for my namespace is the string "http://eric.van-der-vlist.com/ns/library" and this address doesn't have to host any document. At the time I am writing these lines, this address doesn't lead to any web page at all and if you copy it into your favorite web browser, you'd just get a "404 Not Found" error. The assumption is just that I use it only if I own the domain and that I won't use it for several different namespaces. Later on, I could publish something at that location, either a documentation (formal or not) or any kind of schema; that's not forbidden by the namespaces recommendation, this can be useful but the whole subject is highly controversial. Also note that XML namespaces per see do not define any way to associate resources such as schemas or documentations with a namespace URI.

The namespace declaration (xmlns="http://eric.van-der-vlist.com/ns/library") has been done for the document element ("library") and is inherited by all its children elements.

The second goal of XML namespaces is to provide a way to mix elements and attributes from different namespaces in a single document. In our library for instance, the library and book elements use a vocabulary specific to libraries while the author element could use a vocabulary for human resources and the character element be a mixed of both: the character element itself and the qualification element would be from the library namespace while the "name" and "born" elements would be from the HR vocabulary.

Leveraging on declaration inheritance, this could be achieved using the "xmlns" declaration has we have already seen:

 <?xml version="1.0"?>
 <library xmlns="http://eric.van-der-vlist.com/ns/library">
  <book id="b0836217462" available="true">
   <isbn>0836217462</isbn>
   <title xml:lang="en">Being a Dog Is a Full-Time Job</title>
   <author id="CMS" xmlns="http://eric.van-der-vlist.com/ns/person">
    <name>Charles M Schulz</name>
    <born>1922-11-26</born>
    <died>2000-02-12</died>
   </author>
   <character id="PP">
    <name xmlns="http://eric.van-der-vlist.com/ns/person">Peppermint Patty</name>
    <born xmlns="http://eric.van-der-vlist.com/ns/person">1966-08-22</born>
    <qualification>bold, brash and tomboyish</qualification>
    </character>
   <character id="Snoopy">
    <name xmlns="http://eric.van-der-vlist.com/ns/person">Snoopy</name>
    <born xmlns="http://eric.van-der-vlist.com/ns/person">1950-10-04</born>
    <qualification>extroverted beagle</qualification>
   </character>
   <character id="Schroeder">
    <name xmlns="http://eric.van-der-vlist.com/ns/person">Schroeder</name>
    <born xmlns="http://eric.van-der-vlist.com/ns/person">1951-05-30</born>
    <qualification>brought classical music to the Peanuts strip</qualification>
   </character>
   <character id="Lucy">
    <name xmlns="http://eric.van-der-vlist.com/ns/person">Lucy</name>
    <born xmlns="http://eric.van-der-vlist.com/ns/person">1952-03-03</born>
    <qualification>bossy, crabby and selfish</qualification>
   </character>
  </book>
 </library>

But we see that it would rapidly become very verbose and XML namespaces provide a way to assign prefixes to namespaces which can then be used to prefix the names of the elements (and attributes) to declare their namespaces. The namespace declared using the "xmlns" attribute is called the "default namespace" since it is assigned to elements which have no prefix. The document above could be rewritten using the default namespace for the library and assigning a prefix to the other namespace:

 <?xml version="1.0"?>
 <library
   xmlns="http://eric.van-der-vlist.com/ns/library"
   xmlns:hr="http://eric.van-der-vlist.com/ns/person">
  <book id="b0836217462" available="true">
   <isbn>0836217462</isbn>
   <title xml:lang="en">Being a Dog Is a Full-Time Job</title>
   <hr:author id="CMS">
    <hr:name>Charles M Schulz</hr:name>
    <hr:born>1922-11-26</hr:born>
    <hr:died>2000-02-12</hr:died>
   </hr:author>
   <character id="PP">
    <hr:name>Peppermint Patty</hr:name>
    <hr:born>1966-08-22</hr:born>
    <qualification>bold, brash and tomboyish</qualification>
    </character>
   <character id="Snoopy">
    <hr:name>Snoopy</hr:name>
    <hr:born>1950-10-04</hr:born>
    <qualification>extroverted beagle</qualification>
   </character>
   <character id="Schroeder">
    <hr:name>Schroeder</hr:name>
    <hr:born>1951-05-30</hr:born>
    <qualification>brought classical music to the Peanuts strip</qualification>
   </character>
   <character id="Lucy">
    <hr:name>Lucy</hr:name>
    <hr:born>1952-03-03</hr:born>
    <qualification>bossy, crabby and selfish</qualification>
   </character>
  </book>
 </library>

The value of the prefix ("hr" in this example) is chosen arbitrarily by the author of the XML document and should be considered as not significant by applications conform the the namespaces specification. Here, I have chosen "hr" standing for "Human Resources" to make it easier to remember for human readers, but I could have chosen any other value (such as "foo") for this prefix as long as, of course, the prefix matches its definition.

We could also prefer, for symmetry, use a prefix for both namespaces:

 <?xml version="1.0"?>
 <lib:library
   xmlns:lib="http://eric.van-der-vlist.com/ns/library"
   xmlns:hr="http://eric.van-der-vlist.com/ns/person">
  <lib:book id="b0836217462" available="true">
   <lib:isbn>0836217462</lib:isbn>
   <lib:title xml:lang="en">Being a Dog Is a Full-Time Job</lib:title>
   <hr:author id="CMS">
    <hr:name>Charles M Schulz</hr:name>
    <hr:born>1922-11-26</hr:born>
    <hr:died>2000-02-12</hr:died>
   </hr:author>
   <lib:character id="PP">
    <hr:name>Peppermint Patty</hr:name>
    <hr:born>1966-08-22</hr:born>
    <lib:qualification>bold, brash and tomboyish</lib:qualification>
    </lib:character>
   <lib:character id="Snoopy">
    <hr:name>Snoopy</hr:name>
    <hr:born>1950-10-04</hr:born>
    <lib:qualification>extroverted beagle</lib:qualification>
   </lib:character>
   <lib:character id="Schroeder">
    <hr:name>Schroeder</hr:name>
    <hr:born>1951-05-30</hr:born>
    <lib:qualification>brought classical music to the Peanuts strip</lib:qualification>
   </lib:character>
   <lib:character id="Lucy">
    <hr:name>Lucy</hr:name>
    <hr:born>1952-03-03</hr:born>
    <lib:qualification>bossy, crabby and selfish</lib:qualification>
   </lib:character>
  </lib:book>
 </lib:library>

Note that for a namespace aware application, these three documents are considered equivalent:  the prefixes are only shortcuts to associate a namespace URI and a "local name" (the part of the name which is after the colon) to disambiguate this name from eventual synonyms defined in other namespaces.

Up to now, we've spoken of elements and attributes are given a similar yet special treatment. Similar in that attribute names can be prefixed to show that they belong to a namespace but special since the default namespace doesn't apply to them and that the attributes which have no prefix are considered to have no namespace URI but still "belong" to the namespace of their parent element. The reason for this is that attributes are supposed to be used to provide meta-data qualifying their parent element rather than to contain actual information and being qualifiers, it has been considered that by default they "belong" to the same vocabulary than their parent elements. This is the reason why I have kept the "id" and "available" attributes without prefix in my there examples.

The last goal of XML namespaces (and the motivation for taking that much pain to allow several namespaces in a single document) is to facilitate the development of independent (or semi-independent) vocabularies which can be used as building blocks. One of the ideas is that if applications are cleanly developed and just drop elements and attributes which they don't understand documents can be extended without breaking existing applications.

For instance, in our library we've not defined the publisher of the book. We can add a "publisher" element in our namespace, but instead we might want to use the definition given by the Dublin Core Metadata Initiative (DCMI) and use their namespaces to write:

 <?xml version="1.0"?>
 <library
   xmlns="http://eric.van-der-vlist.com/ns/library"
   xmlns:hr="http://eric.van-der-vlist.com/ns/person"
   xmlns:dc="http://purl.org/dc/elements/1.1/">
  <book id="b0836217462" available="true">
   <isbn>0836217462</isbn>
   <title xml:lang="en">Being a Dog Is a Full-Time Job</title>
   <dc:publisher>Andrews Mc Meel Publishing</dc:publisher>
   .../...
  </book>
 </library>

A double benefit is expected from doing so. Everyone understands that the "publisher" element is corresponding to the definition given by the DCMI:

    URI:            http://purl.org/dc/elements/1.1/publisher
    Namespace:      http://purl.org/dc/elements/1.1/
    Name:           publisher
    Label:          Publisher
    Definition:     An entity responsible for making the resource available
    Comment:        Examples of a Publisher include a person, an organization,
                    or a service.
                    Typically, the name of a Publisher should be used to
                    indicate the entity.
    Type of term:   http://dublincore.org/usage/documents/principles/#element
    Status:         http://dublincore.org/usage/documents/process/#recommended
    Date issued:    1998-08-06
    Date modified:  2002-10-04
    Decision:       http://dublincore.org/usage/decisions/#Decision-2002-03
    This version:   http://dublincore.org/usage/terms/dc/#publisher-004
    Replaces:       http://dublincore.org/usage/terms/dc/#publisher-003

Again, note that the mechanism to retrieve this definition is not specified by the XML namespace recommendation. The second benefit is that if my application has been implemented to skip elements and attributes from unsupported namespaces, the addition of this "dc:publisher" element won't break anything.

!!!The two challenges of namespaces

The progression followed in our "10 minutes guide to namespaces" has carefully be designed to let you guess what these two challenges are and you'll probably have already seen where I wanted to go!

The first issue is to provide the ad-hoc mechanisms to associate namespace URIs to patterns describing elements and attributes and this will be described in the next section.

The second issue is to provide mechanisms to write extensible schemas for those applications skipping unknown namespaces. Of course, writing extensible schemas is not limited to multi namespaces documents and we will see more of it in our next chapter, but we will start introducing the mechanism called "name classes" which is the key to extensibility with Relax NG in the last section of this chapter to fully cover the case of namespaces.

!!!Namespace declarations

Namespace declarations in a Relax NG schema are following the same principles as namespace declarations in an instance document with some differences in the syntax and we will also find both the possibility to use default namespaces and the possibility to use prefixes.

!!Using default namespaces

The namespace expected in the instance document can be defined through the "ns" attribute which is an "inherited" attribute like the "datatypeLibrary" attribute seen before. Being inherited means that we can define it in the document element of the schema if it remains the same all over the schema. For instance, to write a schema for the example where all the library is using the same namespace, we could write:

 <?xml version="1.0" encoding="utf-8"?>
 <element xmlns="http://relaxng.org/ns/structure/1.0" name="library"
          ns="http://eric.van-der-vlist.com/ns/library">
  <oneOrMore>
   <element name="book">
    <attribute name="id"/>
    .../...
   </element>
  </oneOrMore>
 </element>

Or, using the compact syntax:

 default namespace = "http://eric.van-der-vlist.com/ns/library"

 element library
 {
    element book
    {
       attribute id { text },
       .../...
       }*
    }+
 }

Note that the definition of the default namespace in a Relax NG schema do not apply to attributes (exactly as the default namespace doesn't apply to attributes in instance documents).

Exactly as default namespaces could be used and changed all over a multi namespace document, when we are using the XML syntax the "ns" attribute can be changed in a schema and to validate the documents with two namespaces show in our "10 minutes guide to namespaces", we could write:

 <?xml version="1.0" encoding="utf-8"?>
 <element xmlns="http://relaxng.org/ns/structure/1.0"
  name="library"
  ns="http://eric.van-der-vlist.com/ns/library">
  <oneOrMore>
   <element name="book">
    <attribute name="id"/>
    <attribute name="available"/>
    <element name="isbn">
     <text/>
    </element>
    <element name="title">
     <attribute name="xml:lang"/>
     <text/>
    </element>
    <zeroOrMore>
     <element name="author" ns="http://eric.van-der-vlist.com/ns/person">
      <attribute name="id"/>
      <element name="name">
       <text/>
      </element>
      <element name="born">
       <text/>
      </element>
      <optional>
       <element name="died">
        <text/>
       </element>
      </optional>
     </element>
    </zeroOrMore>
    <zeroOrMore>
     <element name="character">
      <attribute name="id"/>
      <element name="name" ns="http://eric.van-der-vlist.com/ns/person">
       <text/>
      </element>
      <element name="born" ns="http://eric.van-der-vlist.com/ns/person">
       <text/>
      </element>
      <element name="qualification">
       <text/>
      </element>
     </element>
    </zeroOrMore>
   </element>
  </oneOrMore>
 </element>

The compact syntax does not provide such a way to redefine the default namespace and defining prefixes will be the preferred way to define schemas with multiple namespaces when using the compact syntax.

Since the three variations used to write the document with the two namespaces in our "10 minutes guide" are considered equivalent for namespaces aware applications, the schema which we've just written will validate them indifferently. There is thus a complete independence between the prefixes and default namespaces used to write the instance document and those used in the schema and the match between namespaces is only done through matching the namespace URIs of each element and attribute.

!!Using prefixes

Although the definition of the default target namespace in a Relax NG is done through a "ns" attribute and thus do not rely on the declaration of the default namespace of the Relax NG document itself (in our examples, the default namespace of the Relax NG document is the Relax NG namespace), the declaration of the prefixes used as shortcut to the non default target namespaces is done through namespaces declarations. In other words, to define a "hr" prefix which will be used as a prefix for the namespaces in names or attributes of the instance, I declare this prefix through a "xmlns:hr" declaration as if I wanted to use it as a prefix for an element or attribute of the Relax NG document.

We can mix both default and non default namespaces in our schemas and write:

 <?xml version="1.0" encoding="utf-8"?>
 <element xmlns="http://relaxng.org/ns/structure/1.0"
  name="library"
  ns="http://eric.van-der-vlist.com/ns/library"
  xmlns:hr="http://eric.van-der-vlist.com/ns/person">
  <!-- The default target namespace is "http://eric.van-der-vlist.com/ns/library" -->
  <oneOrMore>
   <element name="book">
    <attribute name="id"/>
    <attribute name="available"/>
    <element name="isbn">
     <text/>
    </element>
    <element name="title">
     <attribute name="xml:lang"/>
     <text/>
    </element>
    <zeroOrMore>
     <element name="hr:author">
     <!-- Here we are using a "hr" prefix to match "http://eric.van-der-vlist.com/ns/person" -->
      <attribute name="id"/>
      <element name="hr:name">
       <text/>
      </element>
      <element name="hr:born">
       <text/>
      </element>
      <optional>
       <element name="hr:died">
        <text/>
       </element>
      </optional>
     </element>
    </zeroOrMore>
    <zeroOrMore>
     <element name="character">
      <attribute name="id"/>
      <element name="hr:name">
       <text/>
      </element>
      <element name="hr:born">
       <text/>
      </element>
      <element name="qualification">
       <text/>
      </element>
     </element>
    </zeroOrMore>
   </element>
  </oneOrMore>
 </element>

A namespace declaration is provided in the compact syntax to define namespace prefixes:

 default namespace = "http://eric.van-der-vlist.com/ns/library"
 namespace hr = "http://eric.van-der-vlist.com/ns/person"

 element library
 {
    element book
    {
       attribute id { text },
       attribute available { text },
       element isbn { text },
       element title { attribute xml:lang { text }, text },
       element hr:author
       {
          attribute id { text },
          element hr:name { text },
          element hr:born { text },
          element hr:died { text }?
       }*,
       element character
       {
          attribute id { text },
          element hr:name { text },
          element hr:born { text },
          element qualification { text }
       }*
    }+
 }

Again, this schema will validate the three variations seen in the "10 minutes guide". In fact this schema validates exactly the same set of document than the schema using only default namespaces. The third variation would be to use prefixes for both namespaces:

 <?xml version="1.0" encoding="utf-8"?>
 <element xmlns="http://relaxng.org/ns/structure/1.0"
  name="lib:library"
  xmlns:lib="http://eric.van-der-vlist.com/ns/library"
  xmlns:hr="http://eric.van-der-vlist.com/ns/person">
  <oneOrMore>
   <element name="lib:book">
    <attribute name="id"/>
    <attribute name="available"/>
    <element name="lib:isbn">
     <text/>
    </element>
    <element name="lib:title">
     <attribute name="xml:lang"/>
     <text/>
    </element>
    <zeroOrMore>
     <element name="hr:author">
      <attribute name="id"/>
      <element name="hr:name">
       <text/>
      </element>
      <element name="hr:born">
       <text/>
      </element>
      <optional>
       <element name="hr:died">
        <text/>
       </element>
      </optional>
     </element>
    </zeroOrMore>
    <zeroOrMore>
     <element name="lib:character">
      <attribute name="id"/>
      <element name="hr:name">
       <text/>
      </element>
      <element name="hr:born">
       <text/>
      </element>
      <element name="lib:qualification">
       <text/>
      </element>
     </element>
    </zeroOrMore>
   </element>
  </oneOrMore>
 </element>

or:

 namespace lib = "http://eric.van-der-vlist.com/ns/library"
 namespace hr = "http://eric.van-der-vlist.com/ns/person"

 element lib:library
 {
    element lib:book
    {
       attribute id { text },
       attribute available { text },
       element lib:isbn { text },
       element lib:title { attribute xml:lang { text }, text },
       element hr:author
       {
          attribute id { text },
          element hr:name { text },
          element hr:born { text },
          element hr:died { text }?
       }*,
       element lib:character
       {
          attribute id { text },
          element hr:name { text },
          element hr:born { text },
          element lib:qualification { text }
       }*
    }+
 }

And again, this schema is equivalent to the previous ones since it's validating all the variations of namespaces declarations in the instance documents.

!!!Accepting "foreign namespaces"

The last schemas which we have seen will validate instance documents independently of the prefixes being used and they meet the first goals of the namespaces which are to disambiguate elements in multi-namespaces documents. However, they will fail to validate the instance document where we've added the "dc:publisher" element. We could easily update our schema to explicitly add this element to the content model of our "book" element, but that wouldn't make it an open schema accepting addition of elements from any other namespace.

Instead of some "magic feature" which would probably have been quite rigid, Relax NG has introduced a flexible and clever feature to let you define your own level of "openness". The idea to do so is to let you define your own "wildcard" and once you get it, you can include it wherever you want in your content model.

!!Constructing our wildcard

Before we start, let's define what we are trying to achieve! We want a named pattern allowing any element or attribute which do not belong to our "lib" and "hr" namespaces. We probably want to exclude elements and attributes with no namespaces: attributes because our own attributes have no namespace and we might want to differentiate them and elements because allowing elements without namespaces in a document using namespaces is kind of messy.

For the content model of these foreign elements, we have two main options:
*We can be liberal and accept anything including elements and attributes from the namespaces described in the schema.
*We can be more conservative and accept only foreign elements.

If we want to be liberal, we must define the inner content of the wildcard to formalize what "anything" is. In this case, this can be expressed as any number of elements (themselves containing "anything"), attributes and text in any order and this is a good candidate for a recursive named pattern:

  <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 )*

The only thing new here is the "anyName" element (XML syntax) or "*" operator (compact syntax) to replace the name of an element or attribute. This is the first example of a "name class" (i.e. a class of names) and we'll see that there are many ways to restrict this name class. Now that we have a named pattern to express what "anything" is, we can use it to define what "foreign" elements mean:

  <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 }*

To achieve our purpose, we have introduced two new elements embedded in the "anyName" name class: "except" (or "-" in the compact syntax) which has here the same meaning than with enumerations and "nsName" (xxx:* in the compact syntax) which means "any name from a namespace". When using the XML syntax, "nsName" takes a "ns" attribute while prefixes are used when using the compact syntax. This usage of prefixes in the compact syntax implies that declarations are added to define prefixes for the "lib" (which is also the default namespace) and "hr" namespaces but also for "no namespace" (here we have used the prefix "local").

Note that name classes are not considered as patterns but as a specific set of elements with a specific purpose. A consequence of this statement is that name classes definitions cannot be placed within named patterns to be reused and that we had to repeat the same name class for both elements and attributes.

The same can be done to define foreign attributes:

  <define name="foreign-attributes">
    <zeroOrMore>
      <attribute>
        <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>
      </attribute>
    </zeroOrMore>
  </define>

or:

 foreign-attributes = attribute * - (local:* | lib:* | hr:*) { text }*

And for our convenience, we can also define foreign nodes by combining foreign elements and attributes:

  <define name="foreign-nodes">
    <zeroOrMore>
      <choice>
        <ref name="foreign-attributes"/>
        <ref name="foreign-elements"/>
      </choice>
    </zeroOrMore>
  </define>

or:

 foreign-nodes = ( foreign-attributes | foreign-elements )*

!!Using our wildcard

So far so good and now that we have defined what "foreign-nodes" are, we can use it to give more extensibility to our schema. To enable foreign-nodes where we have added the "dc:publisher" element, i.e. between the "title" and "author" elements, we could write (switching to a "flatter" style to make it more readable):

     <element name="book">
      <attribute name="id"/>
      <attribute name="available"/>
      <ref name="isbn-element"/>
      <ref name="title-element"/>
      <ref name="foreign-nodes"/>
      <zeroOrMore>
        <ref name="author-element"/>
      </zeroOrMore>
      <zeroOrMore>
        <ref name="character-element"/>
      </zeroOrMore>
    </element>

or:

 book-element =
    element book
    {
       attribute id { text },
       attribute available { text },
       isbn-element,
       title-element,
       foreign-nodes,
       author-element*,
       character-element*
    }

This would do the trick for the instance document shown above, but wouldn't validate a document where foreign nodes would be added at any other place, for instance between the "isbn" and "title" elements. We could insert a reference to the "foreign-nodes" pattern between all the elements, but this would be very verbose and if we think about it, we want here to "interleave" these foreign nodes between the content defined for the "book" element and that's a good opportunity to use the "interleave" pattern:

    <element name="book">
      <interleave>
        <group>
          <attribute name="id"/>
          <attribute name="available"/>
          <ref name="isbn-element"/>
          <ref name="title-element"/>
          <zeroOrMore>
            <ref name="author-element"/>
          </zeroOrMore>
          <zeroOrMore>
            <ref name="character-element"/>
          </zeroOrMore>
        </group>
        <ref name="foreign-nodes"/>
      </interleave>
    </element>

or:

    element book
    {
       (
          attribute id { text },
          attribute available { text },
          isbn-element,
          title-element,
          author-element*,
          character-element*
       )
     & foreign-nodes
    }

As seen in "Chapter 6: More Patterns", foreign nodes will be interleaved in the group which was previously defining the content of the book element: the order of the group is still enforced but foreign nodes may appear in any order and everywhere.

!!Where should we allow foreign nodes?

We may be tempted to allow these foreign nodes everywhere in our document, however if the extensibility which would be given is usually fine in elements such as book which already have children element, it's often considered a bad practice to do the same in elements which content is text only, such as the "isbn" element where this would transform a text content models into a mixed content model.

This is due to the weak support for mixed content models which we've already mentioned in "Chapter 6: More patterns" when we've discussed the limitations of the "mixed" pattern. A consequence of allowing foreign elements in "isbn" elements would be that the content of this element could not be considered a "data" any longer and that no datatypes nor restrictions could be applied any longer.

Beyond the limitation of Relax NG, applications would have to concatenate text nodes spread over the foreign elements and this is may be pretty verbose with tools such as XPath and XSLT.

A compromise which is often taken is to allow only foreign attributes in text content models, but that's not an issue for us since our "foreign-attributes" is ready for this purpose:

    <element name="isbn">
      <ref name="foreign-attributes"/>
      <text/>
    </element>

or:

 element isbn { foreign-attributes, text }

!!A couple of traps to avoid

If most of the time, using our wildcards is straightforward there are some situations where this may lead to unexpected schema errors, especially with attributes which usage is subject to restrictions.

The first of the traps which I'd like to mention here is related to the fact that the definition of attributes cannot be duplicated in a schema and the following definition would be invalid:

 element title { attribute xml:space, attribute xml:space, text } # this is invalid

This seems to be pretty sensible since duplicate attributes are forbidden in the instance document. Unfortunately, the attribute "xml:space" is allowed by our "foreign-attributes" named template and we will get an error as well if we extend the definition of our title element without taking care and write:

 element title { foreign-attributes, attribute xml:space, text } # this is also invalid

To fix this error, we will need either to remove the xml:space attribute from the name class of our foreign attributes or to remove the implicit mention of xml:space in our definition and just write:

 element title { foreign-attributes, text }

Of course, this doesn't remove the possibility to include a xml:space attribute in the "title" element since this attribute is a "foreign attribute" as defined in our named pattern.

The second trap is a level higher on the same line and is specific to the DTD compatibility "ID" datatype. In "Chapter 8: Datatype libraries", when we have seen this datatype, we have used it to define the book element:

   <element name="book">
    <attribute name="id">
     <data datatypeLibrary="http://relaxng.org/ns/compatibility/datatypes/1.0" type="ID"/>
    </attribute>
    .../...
   </element>

or:

  element book {
   attribute id {dtd:ID},
   .../...
  }

Here again, we will generate an error if we add our foreign nodes and the reason for this error is that this datatype is emulating the DTD in all its aspects including the fact that if an element "book" is defined with an "id" attribute having a type "ID", all the other definitions of an attribute "id" hosted by an element "book" must have the same type "ID". The problem here is that, hidden in the definition of "anything", there can be elements "book" having an attribute "id" of type "text" and this is considered as an error.

The only workaround if we want to use the DTD type "ID" is to remove this possibility from the named pattern "anything". A fast solution would be to exclude our namespaces from the class names in "anything" but we can find more elaborated constructions with the elements which will be introduced in the next chapter.

!!Adding foreign nodes through combination

To add our foreign nodes, we have transformed:

    <element name="book">
      <attribute name="id"/>
      <attribute name="available"/>
      <ref name="isbn-element"/>
      <ref name="title-element"/>
      <zeroOrMore>
        <ref name="author-element"/>
      </zeroOrMore>
      <zeroOrMore>
        <ref name="character-element"/>
      </zeroOrMore>
    </element>

or:

    element book
    {
      attribute id { text },
      attribute available { text }
      isbn-element,
      title-element,
      author-element*,
      character-element*
    }

into:

    <element name="book">
      <interleave>
        <group>
          <attribute name="id"/>
          <attribute name="available"/>
          <ref name="isbn-element"/>
          <ref name="title-element"/>
          <zeroOrMore>
            <ref name="author-element"/>
          </zeroOrMore>
          <zeroOrMore>
            <ref name="character-element"/>
          </zeroOrMore>
        </group>
        <ref name="foreign-nodes"/>
      </interleave>
    </element>

or:

    element book
    {
       (
          attribute id { text },
          attribute available { text },
          isbn-element,
          title-element,
          author-element*,
          character-element*
       )
     & foreign-nodes
    }

and this operation could be done as a pattern combination by interleave if the content of the element "book" is described as a named pattern:

  <define name="book-content">
    <attribute name="id"/>
    <attribute name="available"/>
    <ref name="isbn-element"/>
    <ref name="title-element"/>
    <zeroOrMore>
      <ref name="author-element"/>
    </zeroOrMore>
    <zeroOrMore>
      <ref name="character-element"/>
    </zeroOrMore>
  </define>

or:

 book-content =
    attribute id { text },
    attribute available { text },
    isbn-element,
    title-element,
    author-element*,
    character-element*

This pattern can then easily be extended as:

  <define name="book-content" combine="interleave">
    <ref name="foreign-nodes"/>
  </define>

or

 book-content &= foreign-nodes

and used to define the "book" element:

    <element name="book">
      <ref name="book-content"/>
    </element>

or:

 element book { book-content }

This combination can be done in a single document but this mechanism can also be used to extend a vocabulary through merging a grammar containing only these combinations.

Note that the exact same combination does also work for appending foreign attributes to the elements which have a text only content model.

!!!Namespaces and building blocks, chameleon design

!!Back to XHTML 2.0

In "Chapter 10: Creating Building Blocks", we've seen the example of the schemas for XHTML 2.0 and I have urged you not to worry about the namespace declarations which hadn't been introduced yet. Let's have a closer look now that we know how to declare namespaces.

If we look for namespace declarations in the top level schema (the "driver"), we will find them only in the grammar element:

 <?xml version="1.0" encoding="UTF-8"?>
 <grammar ns="http://www.w3.org/2002/06/xhtml2"
         xmlns="http://relaxng.org/ns/structure/1.0"
         xmlns:x="http://www.w3.org/1999/xhtml">

  <x:h1>RELAX NG schema for XHTML 2.0</x:h1>
  .../...
    <x:h3>Structure Module</x:h3>
    <include href="xhtml-struct-2.rng"/>
   .../...
 </grammar>

What do we see in this snippet?

* xmlns="http://relaxng.org/ns/structure/1.0" means that the default namespace of the schema as a XML document is "http://relaxng.org/ns/structure/1.0". That just means that elements without prefix in the schema as a XML document are Relax NG patterns.
* ns="http://www.w3.org/2002/06/xhtml2" defines the default namespace for the schema itself: the schema describes elements from the "http://www.w3.org/2002/06/xhtml2" namespace unless some other namespace is explicitly defined. Let's call it the "target namespace" to avoid any confusion with the default namespace of the schema considered as a XML document.
* xmlns:x="http://www.w3.org/1999/xhtml" defines that the prefix "x" is assigned to "http://www.w3.org/1999/xhtml". This declaration is used here to include XHTML documentation in the schema and we will see this in more detail in "Chapter 13: Annotating Schemas".

This would translate in the compact syntax as:

 default namespace = "http://www.w3.org/2002/06/xhtml2"
 namespace x = "http://www.w3.org/1999/xhtml"

 .../...

 include "xhtml-struct-2.rnc"


Let's now have a look at the module describing the structure:

 <?xml version="1.0" encoding="UTF-8"?>
 <grammar xmlns="http://relaxng.org/ns/structure/1.0"
         xmlns:x="http://www.w3.org/1999/xhtml">

   <x:h1>Structure Module</x:h1>
   .../...

 </grammar>

Or:

 namespace x = "http://www.w3.org/1999/xhtml"

 x:h1 [[ "Structure Module" ]
 start = html
 ...

The big difference with the top level schema is that the target namespace isn't defined in the schema defining the module.

How can that work? It's a feature common to the "include" and "externalRef" pattern than when no target namespace is defined in the imported schema, the target namespace from the schema performing the inclusion or external reference is used. In our case, that means that the target namespace from the driver ("http://www.w3.org/2002/06/xhtml2") is used by any module which do no specify a target namespace.

For this reason, schemas without target namespace are often called "chameleon schemas" since they take the target namespace of any context in which they are included or referenced.

In the compact syntax, an "inherit" qualifier has been added to specify a namespace must be inherited at inclusion or external reference time:

 namespace xhtml2 = "http://www.w3.org/2002/06/xhtml2"
 namespace x = "http://www.w3.org/1999/xhtml"

 .../...

 include "xhtml-struct-2.rnc" inherit = xhtml2

This "inherit" qualifier has the same role as a "ns" attribute in an "include" or externalRef" of the XML syntax.

!!Applicability to our library

Back to XHTML 2.0 and our library, we may want to include XHTML elements into the description of our library, for instance to allow the same content for the definition of our titles and qualification than in the XHTML "p" element, i.e. what's described in the "Inline text" module as the "Inline.model" named pattern. The idea beside this mechanism of modules is that we can select the modules we'll want to include and we can follow this principle to pick just what we need and that's just what we'll do by including the common modules ("xhtml-attribs-2.rng" and "xhtml-datatypes-2.rng") and the "Inline Text" module (""xhtml-inltext-2.rng"):

 <?xml version="1.0" encoding="UTF-8"?>
 <grammar xmlns="http://relaxng.org/ns/structure/1.0">
   <start>
     <ref name="library"/>
   </start>
   <include href="xhtml-attribs-2.rng"/>
   <include href="xhtml-inltext-2.rng"/>
   <include href="xhtml-datatypes-2.rng"/>
   <define name="library">
     <element name="library">
       <oneOrMore>
         <element name="book">
           <attribute name="id"/>
           <attribute name="available"/>
           <element name="isbn">
             <text/>
           </element>
           <element name="title">
             <attribute name="xml:lang"/>
             <ref name="Inline.model"/>
           </element>
           <oneOrMore>
             <element name="author">
               <attribute name="id"/>
               <element name="name">
                 <text/>
               </element>
               <optional>
                 <element name="born">
                   <text/>
                 </element>
               </optional>
               <optional>
                 <element name="died">
                   <text/>
                 </element>
               </optional>
             </element>
           </oneOrMore>
           <zeroOrMore>
             <element name="character">
               <attribute name="id"/>
               <element name="name">
                 <text/>
               </element>
               <optional>
                 <element name="born">
                   <text/>
                 </element>
               </optional>
               <element name="qualification">
                 <ref name="Inline.model"/>
               </element>
             </element>
           </zeroOrMore>
         </element>
       </oneOrMore>
     </element>
   </define>
 </grammar>

Or:

 start = library
 include "xhtml-attribs-2.rnc"
 include "xhtml-inltext-2.rnc"
 include "xhtml-datatypes-2.rnc"
 library =
   element library {
     element book {
       attribute id { text },
       attribute available { text },
       element isbn { text },
       element title {
         attribute xml:lang { text },
         Inline.model
       },
       element author {
         attribute id { text },
         element name { text },
         element born { text }?,
         element died { text }?
       }+,
       element character {
         attribute id { text },
         element name { text },
         element born { text }?,
         element qualification { Inline.model }
       }*
     }+
   }

With this schema, I can include all the XHTML formatting described in the "Inline Text Module" in my "title" and "qualification" elements, but since they must be in the target namespace defined in this schema (i.e. with no namespace since I haven't defined a target namespace here). The local names of the elements are thus the same than those of XHTML 2.0 but these elements must have no namespace. An example of valid document could be:

 <?xml version="1.0" encoding="utf-8"?>
 <library>
   <book id="b0836217462" available="true">
     <isbn>0836217462</isbn>
     <title xml:lang="en">Being a Dog Is a <em>Full-Time Job</em></title>
     <author id="CMS">
       <name>Charles M Schulz</name>
       <born>1922-11-26</born>
       <died>2000-02-12</died>
     </author>
     <character id="PP">
       <name>Peppermint Patty</name>
       <born>1966-08-22</born>
       <qualification>bold, brash and tomboyish</qualification>
     </character>"http://www.w3.org/2002/06/xhtml2"
     <character id="Snoopy">
       <name>Snoopy</name>
       <born>1950-10-04</born>
       <qualification>extroverted <strong>beagle</strong></qualification>
     </character>
     <character id="Schroeder">
       <name>Schroeder</name>
       <born>1951-05-30</born>
       <qualification>brought classical music to the Peanuts strip</qualification>
     </character>
     <character id="Lucy">
       <name>Lucy</name>
       <born>1952-03-03</born>
       <qualification>bossy, crabby and selfish</qualification>
     </character>
   </book>
 </library>

Because the XHTML 2.0 schemas for the modules are chameleon schemas, to import the definitions from XHTML in their namespaces, I need to specify this namespace in my "include" patterns:

 <?xml version="1.0" encoding="UTF-8"?>
 <grammar xmlns="http://relaxng.org/ns/structure/1.0">
   <start>
     <ref name="library"/>
   </start>
   <include href="xhtml-attribs-2.rng" ns="http://www.w3.org/2002/06/xhtml2"/>
   <include href="xhtml-inltext-2.rng" ns="http://www.w3.org/2002/06/xhtml2"/>
   <include href="xhtml-datatypes-2.rng" ns="http://www.w3.org/2002/06/xhtml2"/>
   <define name="library">
     <element name="library">
       <oneOrMore>
         <element name="book">
           <attribute name="id"/>
           <attribute name="available"/>
           <element name="isbn">
             <text/>which
           </element>
           <element name="title">
             <attribute name="xml:lang"/>
             <ref name="Inline.model"/>
           </element>
           <oneOrMore>
             <element name="author">
               <attribute name="id"/>
               <element name="name">
                 <text/>
               </element>
               <optional>
                 <element name="born">
                   <text/>
                 </element>
               </optional>
               <optional>
                 <element name="died">
                   <text/>
                 </element>
               </optional>
             </element>
           </oneOrMore>
           <zeroOrMore>
             <element name="character">
               <attribute name="id"/>
               <element name="name">
                 <text/>
               </element>
               <optional>
                 <element name="born">
                   <text/>
                 </element>
               </optional>
               <element name="qualification">
                 <ref name="Inline.model"/>
               </element>
             </element>
           </zeroOrMore>
         </element>
       </oneOrMore>
     </element>
   </define>
 </grammar>

Or:

 namespace x = "http://www.w3.org/2002/06/xhtml2"

 start = library
 include "xhtml-attribs-2.rnc" inherit = x
 include "xhtml-inltext-2.rnc" inherit = x
 include "xhtml-datatypes-2.rnc" inherit = x
 library =
   element library {
     element book {
       attribute id { text },
       attribute available { text },
       element isbn { text },
       element title {
         attribute xml:lang { text },
         Inline.model
       },
       element author {
         attribute id { text },
         element name { text },
         element born { text }?,
         element died { text }?
       }+,
       element character {
         attribute id { text },
         element name { text },
         element born { text }?,
         element qualification { Inline.model }
       }*
     }+
   }

The namespace which is inherited is now explicitly set to "http://www.w3.org/2002/06/xhtml2" and valid documents look like:

 <?xml version="1.0" encoding="utf-8"?>
 <library xmlns:x="http://www.w3.org/2002/06/xhtml2">
   <book id="b0836217462" available="true">
     <isbn>0836217462</isbn>
     <title xml:lang="en">Being a Dog Is a <x:em>Full-Time Job</x:em></title>
     <author id="CMS">
       <name>Charles M Schulz</name>
       <born>1922-11-26</born>
       <died>2000-02-12</died>
     </author>
     <character id="PP">
       <name>Peppermint Patty</name>
       <born>1966-08-22</born>
       <qualification>bold, brash and tomboyish</qualification>
     </character>
     <character id="Snoopy">
       <name>Snoopy</name>
       <born>1950-10-04</born>
       <qualification>extroverted <x:strong>beagle</x:strong></qualification>
     </character>
     <character id="Schroeder">
       <name>Schroeder</name>
       <born>1951-05-30</born>
       <qualification>brought classical music to the Peanuts strip</qualification>
     </character>
     <character id="Lucy">
       <name>Lucy</name>
       <born>1952-03-03</born>
       <qualification>bossy, crabby and selfish</qualification>
     </character>
   </book>
 </library>

!!Good or evil?

Chameleon schemas are controversial and I am not a big fan of them. On the bright side, they look very handy. The first variation of XHTML inclusion in our library is more concise than the second one where we need to declare the XHTML namespace in each document and add a prefix to XHTML elements. On the other hand, one can question the benefit of adding XHTML elements if they can be identified as XHTML by their namespace. Yes, we can add "em" or "strong" elements in our "title" and "qualification" elements, but how can an application recognize them as XHTML document if they have no namespace or belong to the namespace of our own application?

Chameleon schemas kind of abuse namespaces to remove most of the interest of using them and for this reason I would recommend to be very cautious when you are using them!
