To Qualify Or Not to Qualify?

The schemas that we have written up to this point have had no target namespace declaration. We also could only describe elements and attributes that didn’t belong to any namespace.

The declaration of a target namespace gives us the possibility of defining elements and attributes that belong to the target namespace (called “qualified”) and elements and attributes that don’t belong to any namespace (called “unqualified”).

Tip

The purpose of a schema is to describe a vocabulary, in which top-level nodes belong to its target namespace. For this reason, it is forbidden to define global elements that are unqualified when a target namespace is declared.

The distinction between qualified and unqualified elements and attributes is made through their <form> attributes—for example:

<xs:element name="book" form="qualified"/>
  
<xs:attribute name="isbn" form="qualified"/>
  
<xs:attribute name="lang" form="unqualified"/>
  
<xs:element name="character" form="unqualified"/>

The default values of these form attributes are defined in the elementFormDefault and attributeFormDefault attributes that we have added in our xs:schema element.

These attributes both have default values of their own, which are: elementFormDefault="unqualified" and attributeFormDefault="unqualified". These values are appropriate to the case in which only the document element uses a namespace:

<lib:library xmlns:lib="http://dyomedea.com/ns/library">
  <book id="b0836217462" available="yes">
    <isbn>
      0836217462
    </isbn>
    <title>
      Being a Dog Is a Full-Time Job
    </title>
  </book>
</lib:library>

Since global elements and attributes must be qualified, defining this schema as a single schema requires that all the elements and attributes are locally defined.

Another combination, elementFormDefault="qualified" and attributeFormDefault="unqualified" matches the common case in which a namespace is attached to the root element as the default namespace that will, by definition apply to the included elements but not to the attributes. (Per the Namespaces Recommendation, the default namespace does not apply to attributes.)

<library xmlns="http://dyomedea.com/ns/library">
  <book id="b0836217462" available="yes">
    <isbn>
      0836217462
    </isbn>
    <title>
      Being a Dog Is a Full-Time Job
    </title>
  </book>
</library>

The usage considers that unqualified attributes belong to the same vocabulary as their parent element, and the vocabularies that take advantage of qualified attributes are often vocabularies that supply attributes used in elements from other namespaces. Examples of such vocabularies include RDF and attribute-only vocabularies such as XLink and XML Base. The schemas for these vocabularies will benefit from an attributeFormDefault set to qualified.

One should pay attention to the special status of the attributes in the namespace specification. The default namespace does not apply to attributes. This means that an attribute without a prefix is considered to have no namespace.

Another confusing aspect of attributes with a prefix (which thus belong to a namespace) is these attributes are called "global attributes” in the namespaces recommendation. In W3C XML Schema the term global is used differently, in opposition to local elements or attributes. A global attribute, per namespaces, is therefore a qualified attribute per W3C XML Schema, and may be globally or locally defined.

Tip

Remember that <elementFormDefault> and <attributeFormDefault> define default values and that you can specify—element by element and attribute by attribute—if they are qualified or not.

Before we see how we can bring more namespaces into the game, let’s look at a simple instance document with a single namespace and unqualified attributes:

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

If we want to avoid confusion while writing a schema for this instance document, we can define prefixes in the schema for both our target namespace and for the W3C XML Schema namespace, leading to a schema such as:

<?xml version="1.0"?> 
<xs:schema targetNamespace="http://dyomedea.com/ns/library"
  elementFormDefault="qualified" attributeFormDefault="unqualified"
  xmlns:lib="http://dyomedea.com/ns/library"
  xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xs:element name="library">
    <xs:complexType>
      <xs:sequence>
        <xs:element name="book" type="lib:bookType"/>
      </xs:sequence>
    </xs:complexType>
  </xs:element>
  <xs:element name="person">
    <xs:complexType>
      <xs:sequence>
        <xs:element name="name" type="xs:string"/>
        <xs:element name="born" type="xs:date"/>
        <xs:element name="dead" type="xs:date" minOccurs="0"/> 
        <xs:element name="qualification" type="xs:string"
          minOccurs="0"/>
      </xs:sequence>
      <xs:attribute name="id" type="xs:ID" use="required"/>
    </xs:complexType>
  </xs:element>
  <xs:complexType name="bookType">
    <xs:sequence>
      <xs:element name="isbn" type="xs:NMTOKEN"/>
      <xs:element name="title" type="xs:string"/>
      <xs:element name="authors">
        <xs:complexType>
          <xs:sequence>
            <xs:element ref="lib:person" maxOccurs="unbounded"/>
          </xs:sequence>
        </xs:complexType>
      </xs:element>
      <xs:element name="characters">
        <xs:complexType>
          <xs:sequence>
            <xs:element ref="lib:person" maxOccurs="unbounded"/>
          </xs:sequence>
        </xs:complexType>
      </xs:element>
    </xs:sequence>
    <xs:attribute name="id" type="xs:ID" use="required"/>
    <xs:attribute name="available" type="xs:string" use="required"/>
  </xs:complexType>
</xs:schema>

In this example, the names of components defined by the schema are always unprefixed when they are defined. Because this schema only defines components in the single http://dyomedea.com/ns/library namespace (identified as the targetNamespace attribute of the xs:schema element), there isn’t any risk of confusion. The only other namespaces used here are the namespace for W3C XML Schema itself, identified with an xs prefix, and another mapping for the http://dyomedea.com/ns/library namespace, using lib as the prefix. The lib-prefixed form is used for cross-references between declarations.

A strictly equivalent schema, defining the exact same data model, can be defined using the target namespace as the default namespace of the schema document:

<?xml version="1.0"?> 
<xs:schema targetNamespace="http://dyomedea.com/ns/library"
  elementFormDefault="qualified" attributeFormDefault="unqualified"
  xmlns:xs="http://www.w3.org/2001/XMLSchema"
  xmlns="http://dyomedea.com/ns/library">
  <xs:element name="library">
    <xs:complexType>
      <xs:sequence>
        <xs:element name="book" type="bookType"/>
      </xs:sequence>
    </xs:complexType>
  </xs:element>
  <xs:element name="person">
    <xs:complexType>
      <xs:sequence>
        <xs:element name="name" type="xs:string"/>
        <xs:element name="born" type="xs:date"/>
        <xs:element name="dead" type="xs:date" minOccurs="0"/> 
        <xs:element name="qualification" type="xs:string"
          minOccurs="0"/>
      </xs:sequence>
      <xs:attribute name="id" type="xs:ID" use="required"/>
    </xs:complexType>
  </xs:element>
  <xs:complexType name="bookType">
    <xs:sequence>
      <xs:element name="isbn" type="xs:NMTOKEN"/>
      <xs:element name="title" type="xs:string"/>
      <xs:element name="authors">
        <xs:complexType>
          <xs:sequence>
            <xs:element ref="person" maxOccurs="unbounded"/>
          </xs:sequence>
        </xs:complexType>
      </xs:element>
      <xs:element name="characters">
        <xs:complexType>
          <xs:sequence>
            <xs:element ref="person" maxOccurs="unbounded"/>
          </xs:sequence>
        </xs:complexType>
      </xs:element>
    </xs:sequence>
    <xs:attribute name="id" type="xs:ID" use="required"/>
    <xs:attribute name="available" type="xs:string" use="required"/>
  </xs:complexType>
</xs:schema>

In this version, all references to W3C XML Schema’s own elements are still made using the xs prefix. Names of components are still unprefixed, but the lib prefix is now unnecessary, so all of those prefixes can disappear. Because the default namespace is defined in this document, W3C XML Schema will understand the connection between the components it defines and references to those components.

If you prefer to use prefixes on the components you are defining and use the W3C XML Schema vocabulary without prefixes, you can also define the W3C XML Namespace as the default namespace and declare a prefixed namespace (here, lib) for the components you’re defining:

<?xml version="1.0"?> 
<schema targetNamespace="http://dyomedea.com/ns/library"
  elementFormDefault="qualified" attributeFormDefault="unqualified"
  xmlns="http://www.w3.org/2001/XMLSchema"
  xmlns:lib="http://dyomedea.com/ns/library">
  <element name="library">
    <complexType>
      <sequence>
        <element name="book" type="lib:bookType"/>
      </sequence>
    </complexType>
  </element>
  <element name="person">
    <complexType>
      <sequence>
        <element name="name" type="string"/>
        <element name="born" type="date"/>
        <element name="dead" type="date" minOccurs="0"/>
        <element name="qualification" type="string" minOccurs="0"/>
      </sequence>
      <attribute name="id" type="ID" use="required"/>
    </complexType>
  </element>
  <complexType name="bookType">
    <sequence>
      <element name="isbn" type="NMTOKEN"/>
      <element name="title" type="string"/>
      <element name="authors">
        <complexType>
          <sequence>
            <element ref="lib:person" maxOccurs="unbounded"/>
          </sequence>
        </complexType>
      </element>
      <element name="characters">
        <complexType>
          <sequence>
            <element ref="lib:person" maxOccurs="unbounded"/>
          </sequence>
        </complexType>
      </element>
    </sequence>
    <attribute name="id" type="ID" use="required"/>
    <attribute name="available" type="string" use="required"/>
  </complexType>
</schema>

The references to W3C XML Schema data types are now done without a prefix while the references to components defined in the target namespace are done with a “lib” prefix.