XML Schema Tutorial - Part 4 XML Schema Tutorial - Part 4

Home > XML Tutorials > Part 4 - XSD Namespaces

Using XML Schema Namespaces

This article gives an overview of the complex nature of using Namespaces within XML Schemas.

Namespaces Overview

So far in this tutorial we have largely ignored namespaces as they are an added complexity over writing and using basic XSDs. The full set of namespace rules are very complex, be this overview will provide a basic outline of the technology. If you are creating and modifying XML documents validating against XML Schema making use of namespaces, then XML Data Binding will save you a great deal of time as mostly removes this complexity. If you choose not to use an XML Data Binding tool, you may be advised to refer to the XSD standard and invest in a good book regarding XML Schema.

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.

Like what you see? Try Liquid Studio Free Free Trial

Namespace Walk-through Example

In this example, the schema is broken out into four files:

  • CommonTypes - this could contain all your basic types such as AddressType, PriceType, and PaymentMethodType
  • 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 elements.

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:

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

The value of targetNamespace is simply a unique identifier, typically a company may use their URL followed by something descriptive 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:

targetNamespace="http://www.microsoft.com/CommonTypes.xsd"

However, the following would be equally 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.

Let's look at them in detail.

CommonTypes.xsd

<?xml version="1.0" encoding="utf-16" ?>
<!-- Created with Liquid Studio (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>
CommonTypes.xsd

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:

targetNamespace="http://NamespaceTest.com/CommonTypes"

CustomerTypes.xsd

<?xml version="1.0" encoding="utf-16" ?>
<!-- Created with Liquid Studio (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>
CustomerTypes.xsd

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 that namespace:

targetNamespace="http://NamespaceTest.com/CustomerTypes"

Try Liquid Studio and see how we can help you today Free Trial

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", we do this by adding another attribute in the <xs:schema> element:

xmlns:cmn="http://NamespaceTest.com/CommonTypes"

This 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:

<xs:element name="DeliveryAddress" type="cmn:AddressType" />
<xs:element name="BillingAddress" type="cmn:AddressType" />

OrderTypes.xsd

<?xml version="1.0" encoding="utf-16" ?>
<!-- Created with Liquid Studio (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 schemaLocation="CommonTypes.xsd"
               namespace="http://NamespaceTest.com/CommonTypes" />
    <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":

targetNamespace="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 Studio (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>
Main.xsd

The elements in this schema are part of the namespace "http://NamespaceTest.com/Purchase":

targetNamespace="http://NamespaceTest.com/Purchase"

Simplifies Development & Reduces Bugs Free Trial

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 namespace.

Note: The element "CustomerDetails" which is defined in main.xsd is referenced from within "Purchase".

XML Document

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

<?xml version="1.0" ?>
<!-- Created with Liquid Studio (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, such as a carriage return or space).

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 and 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 elementFormDefault Attribute

You may have noticed that each schema contained an attribute elementFormDefault="qualified". This has two possible values, qualified, and unqualified, the default is unqualified. This attribute changes the namespace 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 Studio (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>.

< Prev | 1 | 2 | 3 | 4 | 5 | Next >

Try all the features of Liquid Studio Download Free Trial Now