05. Introducing namespaces

XML offers tremendous freedom in providing the ability to create your own elements, but this allows the possibility of conflicts to arise where elements of the same name appear in the same context. For instance, one XML document might contain the following sequence of elements to describe Canon cameras:

<camera>
<model>Canon Sureshot</model>
<item-code>WP-1</item-code>
</camera>

Another XML document might contain the following sequence of elements to describe Nikon cameras:

<camera>
<version>Nikon Coolpix</version>
<model>L1</model>
</camera>

The <camera> elements exist happily in separate contexts with schemas describing the allowed sequence for each document. Combining the data into a single XML document to describe both Canon and Nikon cameras is problematic, however, as the <camera> elements conflict - which nested sequence is allowed?

Conflict can be avoided by adding a different prefix to the elements in each document to distinguish them apart, like this:

<c:camera>
<c:model>Canon Sureshot</c:model>
<c:item-code>WP-1</c:item-code>
</c:camera>

<n:camera>
<n:version>Nikon Coolpix</n:version>
<n:model>L1</n:model>
</n:camera>

This solution effectively creates two separate <camera> elements. A single XML document can now include both these elements and validation will seek the appropriate schema for each sequence.

The element prefixes are created as XML "namespaces" to uniquely identify elements within a document.

An XML namespace prefix is created by a statement in the root element of an XML document. For instance, all the XSD schema examples in previous chapters create an "xsd" prefix with the statement xmlns:xsd="http://www.w3.org/2001/XMLSchema". The namespace prefix can then be used when declaring elements, such as <xsd:element>, or schema data types such as xsd:string.

Although "xsd" is traditionally the prefix created for XML schema documents it could, in fact, be any valid name. For instance, the statemnet xmlns:abc="http://www.w3.org/2001/XMLSchema" creates an "abc" prefix, which can then be used to declare elements such as <abc:element>, or data types such as abc:string.

Similarly, the statements nominating an XSD in the root XML element, in earlier examples, create an "xsi" namespace prefix with xmlns:xsi="http://www.w3.org/2001/XMLSchemaInstance". In this case it simply allows xsi:noNamespaceSchemaLocation to specify the location of a schema without namespace consideration.

Although "xsi" is traditionally the prefix created for XML schema instances it oculd be any valid name. For instance, the statement xmlns:xyz="http://www.w3.org/2001/XMLSchemaInstance" creates an "xyz" prefix, which can then be used to specify the schema location to xyz:noNamespaceSchemaLocation.

To understand XML namespaces it is essential to recognize that the statement creating a namespace prefix only assigns a URL to the prefix name as a unique identifier - the content at that URL is never sought or used by XML. Indeed, the directory may not even exist within the specified domain - but you must have the right to use that domain. The URL assigned to a namespace prefix identifies the owner of the namespace, so you cannot use someone else's domain as your namespace - unless they have explicitly agreed to it. For instance, you cannot use the domain www.auxy.com that appears in some examples in here.

The cost to register your own domain is very inexpensive but varies according to your choice of Top Level Domain (TLD). A ".com" domain costs around $20 a year. Alternatively, some ISPs offer a "domain parking" facility that can provide you a unique domain name to use for your XML namespaces at a nominal cost.

Applying your own namespace

The previous examples demonstrating XSD schemas, have largely avoided introducing the topic of namespaces by using the xsi:noNamespaceSchemaLocation attribute in the XML root element to nominate the schema - just specifying its location.

In reality this should be avoided and the xsi:schemaLocation attribute should be used to nominate the schema instead. This must specify both namespace and schema location, separate by space, and entirely contained within quotes. For instance, xsi:schemaLocation="http://www.auxy.com/xsd hello.xsd" specifies the namespace URL http://www.auxy.com/xsd and the relative schema location of hello.xsd

A namespace prefix can then be created using the specified URL. For instance, xmlns:ns="http://www.auxy.com/xsd" creates an "ns" prefix, which can be used to distinguish the elements in that XML document.

See below.

:xmlns and :xsi to nominate a namespace and a schema
:ns to create an "ns" namespace prefix

<?xml version = "1.0" encoding = "UTF-8" ?>
<ns:doc
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.auxy.com/xsd hello.xsd"
xmlns:ns="http://www.auxy.com/xsd"
>
<ns:msg>Hello World</ns:msg>
</ns:doc >

On the schema side, the root <xsd:schema> element should always have a targetNamespace attribute to specify the same namespace. A namespace prefix can then be created using the specified URL. For instance, xmlns:tns="http://www.auxy.com/xsd" creates a "tns" prefix, which can be used to distinguish the components of that XSD schema document.

<?xml version="1.0" encoding = "UTF-8" ?>
<xsd:schema
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.auxy.com/xsd"
xmlns:tns="http://www.auxy.com/xsd"
>
<!-- DECLARE ELEMENTS. -->
<!-- Simple types. -->
<xsd:element name="msg" type="xsd:string"/>
<!-- Complex types. -->
<xsd:element name="doc" type="tns:docType"/>
<!-- DEFINE STRUCTURE. -->
<xsd:complexType name="docType">
<xsd:sequence>
<xsd:element ref="tns:msg"/>
</xsd:sequence>
</xsd:complexType>
</xsd:schema>

Qualifying namespaces

Components declared globally in an XSD schema always need to be "qualified" to be valid in the XML document - they must include the namespace prefix. Conversely, components declared locally, say within structure definitions, need not be qualified - the namespace prefix is not required in the XML document.

Optionally, the schema root element can include elementFormDefault and attributeFormDefault attributes that can be assigned a "qualified" value to force locally declared components to require the namespace prefix to be used.

If you follow the XSD schema best practices suggested in here these attributes can be ignored because:

It is, however, useful to understand what elementFormDefault and attributeFormDefault do, as you may encounter them in other schemas that do not follow the same schema practices.

<?xml version = "1.0" encoding = "UTF-8" ?>
<ns:doc
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.auxy.com/xsd hello.xsd"
xmlns:ns="http://www.auxy.com/xsd"
ns:id="test">
<ns:msg>Hello World</ns:msg>
</ns:doc >

<?xml version="1.0" encoding = "UTF-8" ?>
<xsd:schema
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.auxy.com/xsd"
xmlns:tns="http://www.auxy.com/xsd"
attributeFormDefault="qualified">
<!-- DECLARE ELEMENTS. -->
<!-- Simple types. -->
<xsd:element name="msg" type="xsd:string"/>
<!-- Complex types. -->
<xsd:element name="doc" type="tns:docType"/>
<!-- DEFINE STRUCTURE. -->
<xsd:complexType name="docType">
<xsd:sequence>
<xsd:element ref="tns:msg"/>
</xsd:sequence>
<xsd:attribute name="id" type="xsd:string" />
</xsd:complexType>
</xsd:schema>

Including other schemas

The components of an XSD schema can be split across several schema documents to make the components more modular. An <xsd:include> element can make external components available by assigning a schema's URL to its schemaLocation attribute.

This can be used to simplify your schemas by creating a "library" schema, containing frequently used common structure definitions, which can be "included" in another schema to make those definitions available.

The XSD schema below adapted to use namespaces to the album.xml used before. The first structure definition references declared elements, but the second definition refereences only XSD data types - it describes a common structure in which an element is allowed to contain teext and optionally have an id attribute

<?xml version="1.0" encoding="UTF-8" ?>
<ns:discography
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.auxy.com/xsd album.xsd"
xmlns:ns="http://www.auxy.com/xsd" >
<ns:artist>Pink</ns:artist>
<ns:album id="2000">Can't Take Me Home</ns:album>
<ns:album id="2001">Misundaztood</ns:album>
<ns:album id="2003">Try This</ns:album>
<ns:album id="2006">I'm Not Dead</ns:album>
<ns:album>(...in production)</ns:album>
</ns:discography>

Filename: album.xsd
<?xml version="1.0" encoding="UTF-8" ?>
<xsd:schema
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://www.auxy.com/xsd"
targetNamespace="http://www.auxy.com/xsd">
<xsd:include schemaLocation = "library.xsd" />
<xsd:element name="artist" type="xsd:string"/>
<xsd:element name="discography" type="tns:discoType"/>
<xsd:element name="album" type="tns:strIdType"/>
<xsd:complexType name="discoType">
<xsd:sequence>
<xsd:element ref="tns:artist"/>
<xsd:element ref="tns:album" maxOccurs="20"/>
</xsd:sequence>
</xsd:complexType>
</xsd:schema>

Filename: Library.xsd
<?xml version="1.0" encoding="UTF-8" ?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" >

<!-- sTRUCURE ALLOWING TEXT AND OPTIONAL ID ATTRIBUTE. -->
<xsd:complexType name="strIdType">
<xsd:simpleContent>
<xsd:extension base="xsd:string">
<xsd:attribute name="id" type="xsd:string"/>
</xsd:extension>
</xsd:simpleContent>
</xsd:complexType>
<!-- DEFINE MORE COMMON STRUCTURES HERE. -->
</xsd:schema>

The library schema does not need to consider namespaces as it is only supplying definitions to other schemas. When the library.xsd schema is "included" in the album.xsd schema the library definitions are added to the album.xsd schema namespace. This means that references to library definitions must use the namespace prefix of the including schema - in this case "tns".

Styling the default namespace

The root element of any XML document can include an "xmlns" attribute to specify the default namespace of that document. Where the document uses just one namespace it can be assigned to the xmlns attribute so that namespace becomes the default. This means that the tag names need not include the prefix because they are automatically recognized from the default namespace.

The removal of namespace prefixes when the namespace is assigned as the default brings two useful benefits:

The drawback of making a namespace the default is a loss of flexibility - namespace prefixes allow data from several namespaces to be assembled in a single compound XML document and remain easily identifiable.

The XML document below appears in previous examples and has an "ns" namespace prefix.

<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type = "text/css" href = "pink.css" ?>
<discography
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.auxy.com/xsd album.xsd"
xmlns="http://www.auxy.com/xsd" >
<artist>Pink</artist>
<album id="2000">Can't Take Me Home</album>
<album id="2001">Misundaztood</album>
<album id="2003">Try This</album>
<album id="2006">I'm Not Dead</album>
</discography>

Filename: pink.css
discography { font-family:"Comic Sans MS" cursive; font-size:18pt; }
artist { display:block; font: bold 36pt; color:fuchsia; }
album { display:block; width:325px; height:65px; padding-top:15px; background:no-repeat url(notes.png); }

Importing other namespace

The components of existing schemas can be made available to another schema with the XSD <xsd:import> element. This specifies the existing schema's address to a schemaLocation attribute, like the <xsd:include> element, but additionally specifies the existing schema's namespace to a namespace attribute.

A statement declaring each imported namespace can be added in the <xsd:schema> root element so those namespaces can be used within the new schema.

<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/css" href="cameras.css" ?>
<doc
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.auxy.com/xsd cameras.xsd"
xmlns="http://www.auxy.com/xsd"
xmlns:c="http://www.auxy.com/canon"
xmlns:n="http://www.auxy.com/nikon"
>
<c:camera>
<c:model>Canon Sureshot</c:model>
<c:item-code>WP-1</c:item-code>
</c:camera>
<n:camera>
<n:version>Nikon Coolpix</n:version>
<n:model>L1</n:model>
</n:camera>
<c:camera>
<c:model>Canon Powershot</c:model>
<c:item-code>G-7</c:item-code>
</c:camera>
<n:camera>
<n:version>Nikon Silver</n:version>
<n:model>D40</n:model>
</n:camera>
<n:camera>
<n:version>Nikon Digital</n:version>
<n:model>D50</n:model>
</n:camera>
</doc >

Filename: cameras.xsd

<?xml version="1.0" encoding = "UTF-8" ?>
<xsd:schema
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.auxy.com/xsd"
xmlns:tns="http://www.auxy.com/xsd"
xmlns:c="http://www.auxy.com/canon"
xmlns:n="http://www.auxy.com/nikon"
>
<!-- IMPORT NAMESPACE SCHEMAS. -->
<xsd:import namespace="http://www.auxy.com/canon" schemaLocation="canon.xsd"/>
<xsd:import namespace="http://www.auxy.com/nikon" schemaLocation="nikon.xsd"/>

<!-- DECLARE ELEMENTS. -->
<xsd:element name="doc" type="tns:docType"/>
<!-- DEFINE STRUCTURES. -->
<xsd:complexType name="docType">
<xsd:choice maxOccurs="20">
<xsd:element ref="c:camera" maxOccurs="20"/>
<xsd:element ref="n:camera" maxOccurs="20"/>

</xsd:choice>
</xsd:complexType>
</xsd:schema>

Filename: canon.xsd

<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.auxy.com/canon"
xmlns:c="http://www.auxy.com/canon" >
<!-- DECLARE ELEMENTS. -->
<!-- Simple type. -->
<xsd:element name = "model" type = "xsd:string" />
<xsd:element name = "item-code" type = "xsd:string" />
<!-- Complex type. -->
<xsd:element name="doc" type="c:docType"/>
<xsd:element name="camera" type="c:cameraType"/>
<!-- DEFINE STRUCTUES. -->
<xsd:complexType name="docType">
<xsd:sequence>
<xsd:element ref="c:camera" maxOccurs="unbounded"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="cameraType">
<xsd:sequence>
<xsd:element ref="c:model" />
<xsd:element ref="c:item-code" />
</xsd:sequence>
</xsd:complexType>
</xsd:schema>

Filename: nikon.xsd

<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.auxy.com/nikon"
xmlns:n="http://www.auxy.com/nikon" >
<!-- DECLARE ELEMENTS. -->
<!-- Simple type. -->
<xsd:element name = "version" type = "xsd:string" />
<xsd:element name = "model" type = "xsd:string" />
<!-- Complex type. -->
<xsd:element name="doc" type="n:docType"/>
<xsd:element name="camera" type="n:cameraType"/>
<!-- DEFINE STRUCTURES. -->
<xsd:complexType name="docType">
<xsd:sequence>
<xsd:element ref="n:camera" maxOccurs="unbounded"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="cameraType">
<xsd:sequence>
<xsd:element ref="n:version" />
<xsd:element ref="n:model" />
</xsd:sequence>
</xsd:complexType>
</xsd:schema>

Styling multiple namespaces

Styling XML documents that have multiple namespaces is not straightforward with CSS because it also uses the colon character. For instance, a:hover {color:red}. This means a CSS style rule cannot select any element that has a prefix, such as an <ns:doc> element, in the usual way.

The solution provided by CSS3 specification requires an @namespace "at-rule" to be placed at the start of the stylesheet to associate the namespace with the prefix name. The namespace prefix can then be used in a selector by separating the prefix and element name with a "|" pipe character. For instance, an at-rule and style rule for the previous example might look like this:

@namespace c "http://www.auxy.com/canon"
c|camera {displaay:block;background:yellow;}

An asterisk wildcard can be used to select an element of a specified name in any namespace. For instance, to select all <c:camera> and <n:camera> elements in the previous example:

*|camera {display:block;background:yellow;}

At the time fo writing the CSS3 solution has yet to be implemented in IE - but it is supported by Firefox and Opera.

There is, however, a workaround for IE allowing CSS selectors to target elements that have namespace prefixes, by escaping the colon character with a "\" backslash. For instance, to target a <c:camera> element the rule might be

c\:camera {display:block;background:yellow;}

The workaround only works in IE although it is not really intended for this purpose. The technique utilizes IE's support for Unicode escape sequences in selectors, which means that it regards "c:camera" as a single element name - rather than an element named "camera" within the "c" namespace. This is not a great solution but it may be useful until the CSS3 specification is implmeneted across all browsers.

@namespace c "http://www.auxy.com/canon";
@namespace n "http://www.auxy.com/nikon";
c|camera { display:block;background:lime; border:2px solid black; margin:5px; padding:5px; width:450px; }
n|camera { display:block;background:yellow; border:2px solid red; margin:5px; padding:5px; width:450px;}
<!-- Workaround for Internet Explorer. -->
c\:camera { display:block; background:lime; border:2px solid black; margin:5px; padding:5px; width:450px; }
n\:camera { display:block;background:yellow; border:2px solid red; margin:5px; padding:5px; width:450px; }

Using the XLink namespace

Note: At the time of writing XLink is not supported by IE - but it is supported by Firefox.

An XML document can include hyperlinks by adding the XLink namespace. The Xml Linking language (XLink) defines a standard way of creating hyperlinks in XML documents. These can be similar to the simple links found in HTML or extended links that combine multiple resources, such as linking a JavaScript file to an XML document.

Any XML element can become a byperlink by including attributes form the XLink namespace. The most useful XLink attribues are described in this table:

Attribute Possible values Description
href URL Link target
type simple | extended Hyperlink or resource
title string Tooltip text
show new | replace New window or current
actuate onRequest | onLoad When clicked or loaded

To make the XLink attributes available the XLink namespace needs to be added in the root XML element like this:

xmlns:xlink="http://www.w3.org/1999/xlink"

XLink attributes can then be added to any XML element to make them into links. For instance, to create a simple hyperlink:

<example xlink:type="simple" xlink:href="http://www.w3.org">Visiti the W3C home page</example>

External resources can be linked in a similar manner. For instance, to link a JavaScript file to the XML document:

<script type="text/javascript" xlink:href="top.js" />

Here's a revision of the cameras example discussed before

<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/css" href="cameras.css" ?>
<doc
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.auxy.com/xsd cameras.xsd"
xmlns="http://www.auxy.com/xsd"
xmlns:c="http://www.auxy.com/canon"
xmlns:n="http://www.auxy.com/nikon"
xmlns:xlink = "http://www.w3.org/1999/xlink" >
<c:camera xlink:href="pics/canon-wp1.png" xlink:type="simple" xlink:title="See this camera" xlink:show="new" xlink:actuate="onRequest">
<c:model>Canon Sureshot</c:model>
<c:item-code>WP-1</c:item-code>
</c:camera>
<n:camera>
<n:version>Nikon Coolpix</n:version>
<n:model>L1</n:model>
</n:camera>
<c:camera>
<c:model>Canon Powershot</c:model>
<c:item-code>G-7</c:item-code>
</c:camera>
<n:camera>
<n:version>Nikon Silver</n:version>
<n:model>D40</n:model>
</n:camera>
<n:camera>
<n:version>Nikon Digital</n:version>
<n:model>D50</n:model>
</n:camera>
</doc >

<?xml version="1.0" encoding = "UTF-8" ?>
<xsd:schema
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.auxy.com/xsd"
xmlns:tns="http://www.auxy.com/xsd"
xmlns:c="http://www.auxy.com/canon"
xmlns:n="http://www.auxy.com/nikon" >
<!-- IMPORT NAMESPACE SCHEMAS. -->
<xsd:import namespace="http://www.auxy.com/canon" schemaLocation="canon.xsd"/>
<xsd:import namespace="http://www.auxy.com/nikon" schemaLocation="nikon.xsd"/>
<!-- DECLARE ELEMENTS. -->
<xsd:element name="doc" type="tns:docType"/>
<!-- DEFINE STRUCTURES. -->
<xsd:complexType name="docType">
<xsd:choice maxOccurs="20">
<xsd:element ref="c:camera" maxOccurs="20"/>
<xsd:element ref="n:camera" maxOccurs="20"/>
</xsd:choice>
</xsd:complexType>
</xsd:schema>

@namespace c "http://www.auxy.com/canon";
@namespace n "http://www.auxy.com/nikon";
c|camera { display:block;background:lime; border:2px solid black; margin:5px; padding:5px; width:450px; }
n|camera { display:block;background:yellow; border:2px solid red; margin:5px; padding:5px; width:450px;}
<!-- Workaround for Internet Explorer. -->
c\:camera { display:block; background:lime; border:2px solid black; margin:5px; padding:5px; width:450px; }
n\:camera { display:block;background:yellow; border:2px solid red; margin:5px; padding:5px; width:450px; }

Summary