XML Schema Tutorial, Part 4

Using XML Schema Namespaces

Namespaces

So far we have largely ignored namespaces, we will hopefully address this a little now. Firstly the full namespacing rules are rather complicated, so this will just be an overview. If your working with a schema that makes use of namespaces then XML Data Bindingwill save you a great deal of time as it takes this complexity away. If you're not using a data binding toolthen you may want to refer to the XSD standard and invest in a good book such as XML Schema from O'Reilly Media.

Namespaces are a mechanism for breaking up your schemas. Up until now we have assumed that you only have a single schema file containing all your element definitions, but the XSD standard allows you to structure your XSD schemas by breaking them into multiple files. These child schemas can then be included into a parent schema.

Breaking schemas into multiple files can have several advantages. You can create re-usable definitions that can be used across several projects. They make definitions easier to read and version as they break down the schema into smaller units that are simpler to manage.

In this example, the schema is broken out into 4 files.

  • CommonTypes - this could contain all your basic types, AddressType, PriceType, PaymentMethodType etc.
  • CustomerTypes - this could contain all your definitions for your customers.
  • OrderTypes - this could contain all your definitions for orders.
  • Main - this would pull all the sub schemas together into a single schema, and define your main element/s.

This all works fine without namespaces, but if different teams start working on different files, then you have the possibility of name clashes, and it would not always be obvious where a definition had come from. The solution is to place the definitions for each schema file within a distinct namespace.

We can do this by adding the attribute targetNamespace into the schema element in the XSD file, i.e.:

<?xml version="1.0"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
           targetNamespace="myNamespace">
   ...
</xs:schema>

The value of targetNamespace is just a unique identifier, typically companies use there url followed by something to qualify it. In principle the namespace has no meaning, but some companies have used the url where the schema is stored, as the targetNamespace and so some XML parsers will use this as a hint path for the schema e.g.: targetNamespace="http://www.microsoft.com/CommonTypes.xsd", but the following would be just as valid targetNamespace="my-common-types".

Placing the targetNamespace attribute at the top of your XSD schema means that all entities defined in it are part of this namespace. So in our example above each of the 4 schema files could have a distinct targetNamespace value.

Lets look at them in detail.

CommonTypes.xsd

<?
xml version="1.0" encoding="utf-16"?>
<!-- Created with Liquid XML Studio 0.9.8.0 (http://www.liquid-technologies.com) -->
<xs:schema targetNamespace="http://NamespaceTest.com/CommonTypes" 
           xmlns:xs="http://www.w3.org/2001/XMLSchema"
           elementFormDefault="qualified">
  
  <xs:complexType name="AddressType">
    <xs:sequence>
      <xs:element name="Line1" type="xs:string" />
      <xs:element name="Line2" type="xs:string" />
    </xs:sequence>
  </xs:complexType>
  
  <xs:simpleType name="PriceType">
    <xs:restriction base="xs:decimal">
      <xs:fractionDigits value="2" />
    </xs:restriction>
  </xs:simpleType>
  
  <xs:simpleType name="PaymentMethodType">
    <xs:restriction base="xs:string">
      <xs:enumeration value="VISA" />
      <xs:enumeration value="MasterCard" />
      <xs:enumeration value="Cash" />
      <xs:enumeration value="Amex" />
    </xs:restriction>
  </xs:simpleType>
</xs:schema>

This schema defines some basic re-usable entities and types.
The use of the targetNamespace attribute in the <xs:schema> element ensures all the enclosed definitions (AddressType, PriceType and PaymentMethodType) are all in the namespace http://NamespaceTest.com/CommonTypes.

CustomerTypes.xsd

<?
xml version="1.0" encoding="utf-16"?>
<!-- Created with Liquid XML Studio 0.9.8.0 (http://www.liquid-technologies.com) -->
<xs:schema     xmlns:cmn="http://NamespaceTest.com/CommonTypes" 
               targetNamespace="http://NamespaceTest.com/CustomerTypes" 
               xmlns:xs="http://www.w3.org/2001/XMLSchema"
               elementFormDefault="qualified">
    <xs:import schemaLocation="CommonTypes.xsd" 
               namespace="http://NamespaceTest.com/CommonTypes"/>
  <xs:complexType name="CustomerType">
    <xs:sequence>
      <xs:element name="Name" type="xs:string" />
      <xs:element name="DeliveryAddress" type="cmn:AddressType" />
      <xs:element name="BillingAddress" type="cmn:AddressType" />
    </xs:sequence>
  </xs:complexType>
</xs:schema>

 

This schema defines the entity CustomerType, which makes use of the AddressType defined in the CommonTypes.xsd schema. We need to do a few things in order to use this.
First we need to import that schema into this one - so we can see it. This is done using <xs:import>.
It is worth noting the presence of the targetNamespace attribute at this point. This means that all entities defined in this schema belong to the namespace "http://NamespaceTest.com/CustomerTypes".
So in order to make use of the AddressType which is defined in CommonTypes.xsd, and part of the namespace "http://NamespaceTest.com/CommonTypes", we must fully qualify it. In order to do this we must define an alias for the namespace "http://NamespaceTest.com/CommonTypes". Again this is done using <xs:schema>.
The line xmlns:cmn="http://NamespaceTest.com/CommonTypes" specifies that the alias cmn represents the namespace "http://NamespaceTest.com/CommonTypes".
We can now make use of the types within the CommonTypes.xsd schema. When we do this we must fully qualify them as they are not in the same targetNamespace as the schema that is using them. We do this as follows: type="cmn:AddressType".

OrderType.xsd

<?
xml version="1.0" encoding="utf-16"?>
<!-- Created with Liquid XML Studio 0.9.8.0 (http://www.liquid-technologies.com) -->
<xs:schema     xmlns:cmn="http://NamespaceTest.com/CommonTypes"
               targetNamespace="http://NamespaceTest.com/OrderTypes" 
               xmlns:xs="http://www.w3.org/2001/XMLSchema"
               elementFormDefault="qualified">
    <xs:import namespace="http://NamespaceTest.com/CommonTypes" 
               schemaLocation="CommonTypes.xsd" />
  <xs:complexType name="OrderType">
    <xs:sequence>
      <xs:element maxOccurs="unbounded" name="Item">
        <xs:complexType>
          <xs:sequence>
            <xs:element name="ProductName" type="xs:string" />
            <xs:element name="Quantity" type="xs:int" />
            <xs:element name="UnitPrice" type="cmn:PriceType" />
          </xs:sequence>
        </xs:complexType>
      </xs:element>
    </xs:sequence>
  </xs:complexType>
</xs:schema>

This schema defines the type OrderType which is within the namespace http://NamespaceTest.com/OrderTypes.
The constructs used here are the same as those used in CustomerTypes.xsd.

Main.xsd

<?
xml version="1.0" encoding="utf-16"?>
<!-- Created with Liquid XML Studio 0.9.8.0 (http://www.liquid-technologies.com) -->
<xs:schema     xmlns:ord="http://NamespaceTest.com/OrderTypes" 
               xmlns:pur="http://NamespaceTest.com/Purchase"
               xmlns:cmn="http://NamespaceTest.com/CommonTypes"
               xmlns:cust="http://NamespaceTest.com/CustomerTypes"
               targetNamespace="http://NamespaceTest.com/Purchase"
               xmlns:xs="http://www.w3.org/2001/XMLSchema"
               elementFormDefault="qualified">
 <xs:import schemaLocation="CommonTypes.xsd" namespace="http://NamespaceTest.com/CommonTypes" />
 <xs:import schemaLocation="CustomerTypes.xsd" namespace="http://NamespaceTest.com/CustomerTypes" />
 <xs:import schemaLocation="OrderTypes.xsd" namespace="http://NamespaceTest.com/OrderTypes" />
 <xs:element name="Purchase">
  <xs:complexType>
   <xs:sequence>
    <xs:element name="OrderDetail" type="ord:OrderType" />
    <xs:element name="PaymentMethod" type="cmn:PaymentMethodType" />
    <xs:element ref="pur:CustomerDetails"/>
   </xs:sequence>
  </xs:complexType>
 </xs:element>
 <xs:element name="CustomerDetails" type="cust:CustomerType"/>
</xs:schema>

 


The elements in this schema are part of the namespace "http://NamespaceTest.com/Purchase" (see tagetNamespace attribute).
This is our main schema and defines the concrete elements "Purchase", and "CustomerDetails" .
This element builds on the other schemas, so we need to import them all, and define aliases for each namesapce.
Note: The element "CustomerDetails" which is defined in main.xsd is referenced from within "Purchase".

The XML

As the root element "Purchase" is in the namespace "http://NamespaceTest.com/Purchase", we must quantify the <Purchase> element within the resulting XML document. Lets look at an example:

<?xml version="1.0"?>
<!-- Created with Liquid XML Studio 0.9.8.0 (http://www.liquid-technologies.com) -->
<p:Purchase xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
            xsi:schemaLocation="http://NamespaceTest.com/Purchase Main.xsd" 
            xmlns:p="http://NamespaceTest.com/Purchase"
            xmlns:o="http://NamespaceTest.com/OrderTypes"
            xmlns:c="http://NamespaceTest.com/CustomerTypes"
            xmlns:cmn="http://NamespaceTest.com/CommonTypes">
 <p:OrderDetail>
  <o:Item>
   <o:ProductName>Widget</o:ProductName>
   <o:Quantity>1</o:Quantity>
   <o:UnitPrice>3.42</o:UnitPrice>
  </o:Item>
 </p:OrderDetail>
 <p:PaymentMethod>VISA</p:PaymentMethod>
 <p:CustomerDetails>
  <c:Name>James</c:Name>
  <c:DeliveryAddress>
   <cmn:Line1>15 Some Road</cmn:Line1>
   <cmn:Line2>SomeTown</cmn:Line2>
  </c:DeliveryAddress>
  <c:BillingAddress>
   <cmn:Line1>15 Some Road</cmn:Line1>
   <cmn:Line2>SomeTown</cmn:Line2>
  </c:BillingAddress>
 </p:CustomerDetails>
</p:Purchase

 

The first thing we see is the xsi:schemaLocation attribute in the root element. This tells the XML parser that elements within the namespace "http://NamespaceTest.com/Purchase" can be found in the file "Main.xsd" (Note the namespace and url are separated with whitespace - carriage return or space will do).

The next thing we do is define some aliases

  • "p" to mean the namespace "http://NamespaceTest.com/Purchase"
  • "c" to mean the namespace "http://NamespaceTest.com/CustomerTypes"
  • "o" to mean the namespace "http://NamespaceTest.com/OrderTypes"
  • "cmn" to mean the namespace "http://NamespaceTest.com/CommonTypes"

You have probably noticed that every element in the schema is qualified with one of these aliases.

The general rules for this are:

The alias must be the same as the target namespace in which the element is defined. It is important to note that this is where the element is defined - not where the complexType is defined.
So the element <OrderDetail> is actually defined in main.xsd so it is part of the namespace "http://NamespaceTest.com/Purchase", even though it uses the complexType "OrderType" which is defined in the OrderTypes.xsd. The contents of <OrderDetail> are defined within the complexType "OrderType", which is in the target namespace "http://NamespaceTest.com/OrderTypes", so the child element <Item> needs qualifying within the namespace "http://NamespaceTest.com/OrderTypes".

The Effect of elementFormDefault

You may have noticed that each schema contained an attribute elementFormDefault="qualified". This has 2 possible values, qualified, and unqualified, the default is unqualified. This attribute changes the namespacing rules considerably. It is normally easier to set it to qualified.

So to see the effects of this property, if we set it to be unqualified in all of our schemas, the resulting XML would look like this:

<?xml version="1.0"?>
<!-- Created with Liquid XML Studio 0.9.8.0 (http://www.liquid-technologies.com) -->
<p:Purchase    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
               xsi:schemaLocation="http://NamespaceTest.com/Purchase Main.xsd"
               xmlns:p="http://NamespaceTest.com/Purchase">
    <OrderDetail>
        <Item>
            <ProductName>Widget</ProductName>
            <Quantity>1</Quantity>
            <UnitPrice>3.42</UnitPrice>
        </Item>
    </OrderDetail>
    <PaymentMethod>VISA</PaymentMethod>
    <p:CustomerDetails>
        <Name>James</Name>
        <DeliveryAddress>
            <Line1>15 Some Road</Line1>
            <Line2>SomeTown</Line2>
        </DeliveryAddress>
        <BillingAddress>
            <Line1>15 Some Road</Line1>
            <Line2>SomeTown</Line2>
        </BillingAddress>
    </p:CustomerDetails>
</p:Purchase>

 

This is considerably different from the previous XML document.

These general rules now apply:

  • Only root elements defined within a schema need qualifying with a namespace.
  • All types that are defined inline do NOT need to be qualified.

The first element is Purchase, this is defined globally in the Main.xsd schema, and therefore needs qualifying within the schemas target namespace "http://NamespaceTest.com/Purchase".

The first child element is <OrderDetail> and is defined inline in Main.xsd->Purchase. So it does not need to be aliased.

The same is true for all the child elements, they are all defined inline, so they do not need qualifying with a namespace.

The final child element <CustomerDetails> is a little different. As you can see we have defined this as a global element within the targetNamespace "http://NamespaceTest.com/Purchase". In the element "Purchase" we just reference it. Because we are using a reference to an element, we must take into account its namespace, thus we alias it <p:CustomerDetails>.

Summary

Namespaces provide a useful way of breaking schemas down into logical blocks, which can then be re-used throughout a company or project. The rules for namespacing in the resulting XML documents are rather complex, the rules provided here are a rough guide, things do get more complex as you dig further into it. For this reason tools to deal with these complexities are useful, see XML Data Binding.

 

<< PrevNext >>

 

 

 

 XSD Tutorial Parts

1 - Defining Elements and Attributes
2 - Best Practices, Conventions & Recommendations
3 - Extending Existing Types
4 - Using XML Schema Namespaces
5 - Group, AttributeGroup, Any and AnyAttribute
XSD Editor Video Demo

This XSD tutorial was created using Liquid XML Studio.

The XSD standard is complex, and without a graphical tool it is difficult to understand. For that reason it is recommended that you install the Free 30 day trial.

The graphical schema editor, split screen editing, XSD/XML validation all make it much easier to learn how to design and work with XML Schemas.

Getting Started

Liquid XML Studio makes it easy to learn new XML technologies.

Download the free 30 day trial now and get started the smart way!