Dr. Tom's Guide to IMS XML Extensions and Incorporations

Dr. Tom wearing a hat.
Thomas D. Wason, Ph.D. (aka Dr. Tom)
http://www.tomwason.com [Home]
wason@mindspring.com



One of the Dr. Tom Guides

Purpose of Document

The purpose of this document is to provide a method for extending one XML binding with elements from another source. A parallel method is also provided for incorporating into the XML binding of one specification the elements and structures of another XML binding . The method uses the W3C XML-Schema standard (recommendation) (http://www.w3.org/XML/Schema).

Document Information

Title Dr. Tom’s Guide to IMS XML Extensions and Incorporations
Author(s) Thomas D. Wason
Version Date 03 June 2001
Copyright Copyright © 2001 IMS Global Learning Consortium, Inc.
Used by permission.

Contents

  1. Introduction
  2. Rules
  3. Summary
  4. Incorporation: Inclusion and Improtation in Schemas
  5. Extending XML Instances
  6. Conclusion

1. Introduction

This guide describes the strategies for extension of XML instances by using XML control documents (XML-Schemas) with namespaces. It also describes methods for incorporating schemas or parts of schemas in other schemas. The methods described here allow an XML instance to be created that could potentially be validated against XML-Schema control documents. All of the example files are included in the appendix following the guide.

The IMS specifications are comprehensive enough that you can do a lot without ever making use of extensions, especially with proper preparation you can see where your information can be put in the existing structures. Often, a different IMS specification will solve many needs as an alternative to using extensions. For example, those trying to describe when or where a course is being taught should use the IMS Enterprise specification rather than the IMS Meta-data specification. Detailed information about an author or instructor can be expressed well in the IMS Learner Information Package.

This method of using namespaces is not just about extensions. It is really about the ability to mix parts from different sources using namespaces to define where the parts came from. Extensions, cross use, and importing from external sources are all instances of the use of namespaces to define and control the mixing of components from divers sources. Inclusions do not normally use namespaces(inclusion is a method of creating a schema from sub-schemas).

This guide describes methods by which:

  • One specification's XML binding may import all or part of another specification's XML binding through using XML-Schema;
  • One specification's XML binding may include all or part of another specification's XML binding through using XML-Schema;
  • An instance of a specification's XML binding may be extended freely (in an XML instance) if permitted by the schema;
  • An instance of a specification's XML binding may be extended under control (through a redefined content model in an XSD).

This guide assumes you have a basic understanding of XML, if not you may want to take a peek at Dr. Tom's Guide to XML (drtomxml.html). For detailed information on the XML-Schema itself see the W3C's XML-Schema standard (recommendation) at http://www.w3.org/XML/Schema. You may also wish to review IMS's use of XML-Schema in Dr. Tom's Guide to XML-Schema (drtomschema.html). A glossary of terms used in this document follows in the appendix.

2. Rules

Here are the rules that are used to build XML-Schemas for incorporating other schemas and for extending schemas and XML instances. The background details are provided further down. The rules for version control are not covered in this guide. A brief summary of the versioning rules is that a schema that includes other schemas must reflect version changes in the included versions in its own version; the version of a schema that imports from other schemas is independent of version changes in the imported schemas. In the following discussion, component refers to both elements and attributes unless noted otherwise. Refer to "Dr. Tom's Guide to XML-Schema" (drtomschema.html) for the general rules for IMS use of XML-Schema.

Note: These rules are not applicable to extensions that are contained within an <EXTENSION> element that has been created in the information model and XML binding. The use of extension is a legacy concern, and will not be used in new IMS XML-Schemas.

2.1 Inclusion and Importation in Schemas

A specification may be built to incorporate pieces and parts of other specifications. Some IMS specifications may include or import parts or all of other IMS or other specifications and standards. If these additions are to be considered part of the specification, then these inclusions and importations are not extensions to the main schema, but are part of it. The main difference between an importation and an inclusion is that in an instance you must show where the importations come from; inclusions do not usually require a subsequent instance to define the source of the components beyond the primary schema. Inclusion can be considered a method of aggregating sub-schemas into one big schema. Here are the basic rules for inclusion and importation in XML-Schemas.

  • Incorporation of all or part of one XML-Schema into another through inclusion or importation is not an extension of the incorporating schema; the incorporated components become part of it.
  • Inclusion incorporates all of one entire binding into another. Inclusion of one specification's XML-Schema (XSD) by another treats the included XSD as if it were part of the including XSD.
  • Importing incorporates only those elements used in the incorporating schema (by reference).
  • The IMS-defined namespaces must be used for all imported and included schemas if namespaces are present (as a targetNamespace).
  • Included sub-schemas without a targetNamespace must be in the same directory as the including XSD.
  • The XML instance must define namespace(s) for all imported components. Importing, as implemented in XML-Schema, requires namespaces on all imported components in the instances either as prefixes or through block declarations.
  • The XML instance does not define namespace(s) for all included components.
  • The use of the IMS-defined prefixes for components is recommended but not required.

2.2 Free Extension

A free extension is an addition to an XML binding in the XML instance without changes in complexType. Free extensions are enabled in the XSD with no designation of specific components that may be used for extensions. Free extensions are optional, and are executed in the XML instance by using the "any" and "anyAttributes" components in the XSD (wildcards). The locations of these "any(Attribute)" extension components follow these rules:

  • The type definitions for all elements except elements that contain data will have an "any" element. Elements that contain data are referred to as terminal leaves.
  • The type definitions for all elements will include "anyAttribute" attribute.
  • The ##other namespace declaration for the namespaces of elements added through the "any" element will be used. An ##other namespace is any namespace except the current namespace.
  • The default namespace for the "anyAttribute" is ##any.
  • The XML instance must define namespace(s) for all imported elements.
  • The containing element's content type is not changed by free extension.

2.3 Controlled Extension

A controlled extension is created by redefining the content model (i.e., type) of the element that contains the extension. The location and name of the extension is defined.

  • The containing element's content type is overridden in an external XML-Schema by deriving a new type from the old and defining it as equivalent via the substitutionGroup attribute in the external schema. The new element overrides the old one. The new element may be used interchangeably with the old one.
  • An overriding element must follow the rules of XML-Schema substitutionGroups.
  • Controlled extensions require an XSD with a namespace for definition of the substitution (overriding) element.
  • If new components (elements, attributes) are introduced for use in the controlled extension, they must be defined in an XSD with a namespace.
  • The substitutionGroup element may override an existing element without adding any new components.
  • A controlled extension may include restrictions to the original complexType such as limiting the "any" element maxOccurs to "0".

2.4 XSD Schema Form

The XML-Schema will have certain forms and characteristics to support.

  • No elements are of simpleType, they are all of complexType.
  • Terminal leaf elements are of simpleContent.
  • All terminal elements are of mixed="false" types.
  • An XSD that is to be imported will have a namespace declared in the XSD.
  • A namespaced XSD may be derived from a non-namespaced XSD by including the non-namespaced into an XSD that defines a namespace.
  • Do not put targetNamespaces in XSDs that are to be included in a super-schema.

2.5 XML Instance Form

Some of these rules may be a restatement of the rules above, but are included here for ease of reference.

  • An XSD that is to be imported into the control XSD will have a namespace declared in the XML instance.
  • An XSD that is to be imported into an XML instance (e.g., for free extension) will have a namespace declared in the XML instance.
  • The XML instance does not define namespace(s) for components included in the XSD.

3. Summary

This document describes how namespaces can be used to mix elements, attributes and structures in an XML instance with and without the control of XML-Schema. The concept of mix includes extensions, cross use, and the introduction of elements from outside sources. The main XML-Schema is called the primary control document. The general model is a primary control document importing part of or including all of an external XML-Schema module. The external module may be a complete XML-Schema or may contain only XML-Schema fragments.

XML Extensions
 
General model of extension, either by combining XML-Schema components
or by freely extending the instance.

There are various ways to incorporate external models in the primary control module and extend an instance. We call the control modules "XML-Schemas". Incorporation means building a schema using some external parts. Extension means adding parts to an instance beyond those included in the control schema. Here is a simple two level taxonomy:

  • Incorporation into an XML-Schema (.xsd)
    • Include
    • Import
  • Extension of an XML Instance (.xml)
    • Free
    • Controlled

Let's get right to it, the discussion of building a schema from other schemas in two ways: inclusion and importation. Then we will turn to ways of actually extending the instances. The examples are based on the "camera" example in the "XML Schemas: Best Practices" (http://www.xfront.com/BestPractices.html) set. The Best Practices series are quite useful. The examples are in the "Hide (Localize) NamespacesVersus Expose Namespaces" (http://www.xfront.com/HideVersusExpose.html) document.

4. Incorporation: Inclusion and Importation in Schemas

An XML-Schema may be constructed to incorporate other XML schemas. Inclusion is simply a method for patching in another file to make it a de facto part of the main file. Importation brings in only specific components, and has them clearly identified. 4.1 Inclusion The IMS Learner Information Package is actually composed of a root XML-Schema (imscp_rootv1p1.xsd) that includes a set of schemas. In this way, the potentially large schema is broken down into a number of smaller pieces. Let us start with an example XSD that we'll then decompose into some sub-schemas that are included in a top-level schema. First, let's look at an XML instance:

<?xml version="1.0" encoding="UTF-8"?>
<!--filename=CameraFull.xml-->
<camera xmlns="http://www.cameraFull.org" 
xmlns:xsi="http://www.w3.org/2000/10/XMLSchema-instance"
	xsi:schemaLocation="http://www.cameraFull.org cameraFull.xsd">
	<body material="plastic">
		<description>Black</description>
	</body>
	<lens>
		<zoom>100mm - 300mm</zoom>
		<f-stop>f/4.5</f-stop>
	</lens>
	<manual_adapter>
		<speed>1 - 1/1000</speed>
	</manual_adapter>
</camera>

Notice that it has a target namespace, http://www.camera.org. Since me use namespaces here is some additional information that may be useful: Although IMS defines target namespaces, they are somewhat arbitrary. Namespaces are similar to a set of pointers. A prefix (if it is used) points to a namespace which then points to a file. The file may contain the name of its target namespace (cleverly called the "targetNamespace") so that when the XML processor finds it, it can "know" that it has found the right file corresponding to the namespace: the target. This might seem like overkill, but it allows verification. The namespace may also provide a "hint" to the processor as to where the schema it is looking for resides. But it's only a hint. The schemaLocation gives the actual path to the schema. If there is not a path, the schema is first considered to be local, interpreting the schemaLocation as a relative location.

XML Extensions 2

Prefix to namespace to schema.

The figure above comes from Dr. Tom's Guide to XML-Schema, see this guide for more: drtomschema.html.

And now the full camera schema below. Notice that all of the components are from defined namespaces with prefixes of "xsd:" or "xsi".

<?xml version="1.0" encoding="UTF-8"?>
<!-- Filename=cameraFull.xsd -->
<!-- 2001-05-07 Thomas Wason, IMS GLC, Inc.-->
<xsd:schema targetNamespace="http://www.cameraFull.org" 
	xmlns:xsd="http://www.w3.org/2000/10/XMLSchema" 
	xmlns:xsi="http://www.w3.org/2000/10/XMLSchema-instance" 
	xmlns="http://www.cameraFull.org" 
	elementFormDefault="qualified" 
	version="1.0">
	<!-- OPTIONAL: xsi:schemaLocation="http://www.w3.org/2000/10/XMLSchema
http://www.w3.org/2000/10/XMLSchema.xsd"-->
	<xsd:attribute name="material" use="optional">
		<xsd:simpleType>
			<xsd:restriction base="xsd:string"/>
		</xsd:simpleType>
	</xsd:attribute>
	<xsd:element name="body" type="bodyType"/>
	<xsd:element name="camera" type="cameraType"/>
	<xsd:element name="description" type="descriptionType"/>
	<xsd:element name="f-stop" type="f-stopType"/>
	<xsd:element name="lens" type="lensType"/>
	<xsd:element name="manual_adapter" type="manual_adapterType"/>
	<xsd:element name="speed" type="speedType"/>
	<xsd:element name="zoom" type="zoomType"/>
	<xsd:complexType name="bodyType">
		<xsd:sequence>
			<xsd:element ref="description"/>
			<xsd:any namespace="##other"/>
		</xsd:sequence>
		<xsd:attribute ref="material"/>
		<xsd:anyAttribute namespace="##any"/>
	</xsd:complexType>
	<xsd:complexType name="cameraType">
		<xsd:sequence>
			<xsd:element ref="body"/>
			<xsd:element ref="lens" minOccurs="0" maxOccurs="8"/>
			<xsd:element ref="manual_adapter" minOccurs="0"/>
			<xsd:any namespace="##other"/>
		</xsd:sequence>
		<xsd:anyAttribute/>
	</xsd:complexType>
	<xsd:complexType name="descriptionType">
		<xsd:simpleContent>
			<xsd:extension base="xsd:string">
				<xsd:anyAttribute/>
			</xsd:extension>
		</xsd:simpleContent>
	</xsd:complexType>
	<xsd:complexType name="f-stopType">
		<xsd:simpleContent>
			<xsd:extension base="xsd:string">
				<xsd:anyAttribute/>
			</xsd:extension>
		</xsd:simpleContent>
	</xsd:complexType>
	<xsd:complexType name="lensType">
		<xsd:sequence>
			<xsd:element ref="zoom"/>
			<xsd:element ref="f-stop"/>
			<xsd:any namespace="##other"/>
		</xsd:sequence>
		<xsd:anyAttribute/>
	</xsd:complexType>
	<xsd:complexType name="manual_adapterType">
		<xsd:sequence>
			<xsd:element ref="speed"/>
			<xsd:any namespace="##other"/>
		</xsd:sequence>
	</xsd:complexType>
	<xsd:complexType name="speedType">
		<xsd:simpleContent>
			<xsd:extension base="xsd:string">
				<xsd:anyAttribute/>
			</xsd:extension>
		</xsd:simpleContent>
	</xsd:complexType>
	<xsd:complexType name="zoomType">
		<xsd:simpleContent>
			<xsd:extension base="xsd:string">
				<xsd:anyAttribute/>
			</xsd:extension>
		</xsd:simpleContent>
	</xsd:complexType>
</xsd:schema>

That is a pretty long XML-Schema. It might be useful to subdivide this long schema into several small ones. A top level schema (camera.xsd) would include them to create an equivalent schema. As the top level schema will normally contain the root element, it is referred to as the "root" schema. Notice that it has a target namespace: http://www.camera.org. Although IMS defines target namespaces, they are somewhat arbitrary. [IMS will use namespaces that point to the IMS XSD site and include the filename without the ".xsd" extension, for example: xsd/imslip_rootv1p1.xsd.]

<?xml version="1.0" encoding="UTF-8"?>
<!-- Filename=camera.xsd -->
<!-- 2001-05-07 Thomas Wason, IMS GLC, Inc.-->
<xsd:schema targetNamespace="http://www.camera.org"  
	xmlns:xsd="http://www.w3.org/2000/10/XMLSchema" 
	xmlns:xsi="http://www.w3.org/2000/10/XMLSchema-instance" 
	xmlns="http://www.camera.org" 
	elementFormDefault="qualified" 
	version="1.0">
<!--xsi:schemaLocation="http://www.w3.org/2000/10/XMLSchema
http://www.w3.org/2000/10/XMLSchema.xsd"-->
	<xsd:annotation>
	<xsd:include schemaLocation="nikon.xsd"/>
	<xsd:include schemaLocation="pentex.xsd"/>
	<xsd:include schemaLocation="olympus.xsd"/>
	<xsd:element name="camera" type="cameraType"/>
	<xsd:complexType name="cameraType">
		<xsd:sequence>
			<xsd:element ref="body"/>
			<xsd:element ref="lens" minOccurs="0" maxOccurs="8"/>
			<xsd:element ref="manual_adapter"/>
			<xsd:any namespace="##other" minOccurs="0"/>
		</xsd:sequence>
		<xsd:anyAttribute/>
	</xsd:complexType>
</xsd:schema>

That's much more manageable. Note that this schema "includes" several schemas:

	<xsd:include schemaLocation="nikon.xsd"/>
	<xsd:include schemaLocation="pentex.xsd"/>
	<xsd:include schemaLocation="olympus.xsd"/>

These are the schemas that I pulled out and made into smaller sub-schemas. Here are the sub-schemas, which do not have targetNamespaces:

<?xml version="1.0" encoding="UTF-8"?>
<!-- filename= nikon.xsd -->
<xsd:schema xmlns:xsi="http://www.w3.org/2000/10/XMLSchema-instance" 
	xmlns:xsd="http://www.w3.org/2000/10/XMLSchema" 
	elementFormDefault="qualified">
	<xsd:element name="description" type="descriptionType"/>
	<xsd:element name="body" type="bodyType"/>
	<xsd:complexType name="bodyType">
		<xsd:sequence>
			<xsd:element ref="description"/>
			<xsd:any namespace="##other" minOccurs="0"/>
		</xsd:sequence>
		<xsd:anyAttribute/>
	</xsd:complexType>
	<xsd:complexType name="descriptionType">
		<xsd:simpleContent>
			<xsd:extension base="xsd:string">
				<xsd:anyAttribute/>
			</xsd:extension>
		</xsd:simpleContent>
	</xsd:complexType>
</xsd:schema>

This XML-Schema creates the elements, "manual_adapter" and "speed".

<?xml version="1.0" encoding="UTF-8"?>
<!-- filename=pentex.xsd -->
<xsd:schema xmlns:xsi="http://www.w3.org/2000/10/XMLSchema-instance" 
	xmlns:xsd="http://www.w3.org/2000/10/XMLSchema" 
	elementFormDefault="qualified">
	<!-- xsi:schemaLocation="http://www.w3.org/2000/10/XMLSchema
	http://www.w3.org/2000/10/XMLSchema.xsd" -->
	<xsd:element name="manual_adapter" type="manual_adapterType"/>
	<xsd:element name="speed" type="speedType"/>
	<xsd:complexType name="manual_adapterType">
		<xsd:sequence>
			<xsd:element ref="speed"/>
			<xsd:any minOccurs="0" namespace="##other"/>
		</xsd:sequence>
	</xsd:complexType>
	<xsd:complexType name="speedType">
		<xsd:simpleContent>
			<xsd:extension base="xsd:string">
				<xsd:anyAttribute/>
			</xsd:extension>
		</xsd:simpleContent>
	</xsd:complexType>
</xsd:schema>

The XML-Schema below creates elements and includes a schema with an element, <f-stop>. This is to show that an included schema can include yet another schema. The whole string of inclusions in undetectable at the top level.

<?xml version="1.0" encoding="UTF-8"?>
<!-- filename=olympus.xsd -->
<!-- 2001-05-07 Thomas D. Wason-->
<xsd:schema xmlns:xsi="http://www.w3.org/2000/10/XMLSchema-instance"
	xmlns:xsd="http://www.w3.org/2000/10/XMLSchema"
	elementFormDefault="qualified"
	version="1.0">
	<!-- OPTIONAL:  xsi:schemaLocation="http://www.w3.org/2000/10/XMLSchema
	 http://www.w3.org/2000/10/XMLSchema.xsd"-->
	<xsd:include schemaLocation="f_stop.xsd"/>
	<xsd:element name="lens" type="lensType"/>
	<xsd:element name="zoom" type="zoomType"/>
	<xsd:complexType name="lensType">
		<xsd:sequence>
			<xsd:element ref="zoom"/>
			<xsd:element ref="f-stop"/>
			<xsd:any minOccurs="0" namespace="##other"/>
		</xsd:sequence>
		<xsd:anyAttribute/>
	</xsd:complexType>
	<xsd:complexType name="zoomType">
		<xsd:simpleContent>
			<xsd:extension base="xsd:string">
				<xsd:anyAttribute/>
			</xsd:extension>
		</xsd:simpleContent>
	</xsd:complexType>
</xsd:schema>

This XML-Schema creates an element <f-stop>.

<?xml version="1.0" encoding="UTF-8"?>
<!-- filename=f_stop.xsd -->
<!--2001-05-07 Thomas Wason (www.tomwason.com) IMS Global Learning Consortium, Inc.
(http://www.imsglobal.org) -->
<xsd:schema xmlns:xsd="http://www.w3.org/2000/10/XMLSchema" 
	elementFormDefault="qualified" 
	xmlns:xsi="http://www.w3.org/2000/10/XMLSchema-instance">
	<xsd:element name="f-stop" type="f-stopType"/>
	<xsd:complexType name="f-stopType">
		<xsd:simpleContent>
			<xsd:extension base="xsd:string">
				<xsd:anyAttribute/>
			</xsd:extension>
		</xsd:simpleContent>
	</xsd:complexType>
</xsd:schema>

An "included" schema does not have to be a complete schema: it could be a fragment. It is simply a file that gets patched into another file. The only change that needs to be made in the XML instance is that it now should use the composite XSD:

<camera xmlns="http://www.camera.org" 
	xmlns:xsi="http://www.w3.org/2000/10/XMLSchema-instance" 
	xsi:schemaLocation="http://www.camera.org camera.xsd">

4.2 Importation

A schema may import another schema or schema fragment. For example, the IMS Content Packaging binding XML-Schema imports the IMS Meta-Data schema. Parts of the imported file are available for use within the importing schema. The entire imported schema is not automatically part of the importing schema. The importing schema must specifically reference the components in the imported file that are to be used. Importing has two steps:

  • pointing to the file
  • referencing the specific components of the file

You point to the file by assigning it a namespace. The imported components thus have a namespace associated with them. Import assignment is accomplished in the schema with an <import> element. Within the IMS system, an import defines both a namespace and a schemaLocation as a file path. In the example below, a relative path (i.e., glass.xsd) is used for the schemaLocation. In this case, the imported file (glass.xsd) is in the same directory as the importing schema:

<xsd:import namespace="http://www.leitz.org" schemaLocation="glass.xsd"/>

The namespace is associated with a namespace prefix so that it can be referenced within the importing schema:

xmlns:leitz="http://www.leitz.org" 

Typically the namespace designation is included in the root element, but it may be at any point in the XML hierarchy at or above the actual element. Take a look at the W3C document "Namespaces in XML "(http://www.w3.org/TR/REC-xml-names/) for more details. Or just always put it in the root element. This is convenient, as then you only have to assign the namespace once. For example, the IMS Content Packaging XML binding uses the IMS Meta-data many times, so a single "import" assignment at the root level makes the namespace available throughout the schema.

A component in the imported file, (e.g., leitz:glass) is used by referencing it in the schema:

<xsd:element name="lens" type="lensType"/>
	<xsd:complexType name="lensType">
		<xsd:sequence>
			<xsd:element ref="zoom"/>
			<xsd:element ref="f-stop"/>
			<xsd:element ref="leitz:glass"/>
		</xsd:sequence>
		<xsd:anyAttribute/>
	</xsd:complexType>

Only those imported elements that have been explicitly referenced are available for use in an instance. The children of a referenced element are considered referenced. This differs from inclusion, which the entire included schema is available in the instance. You can find the complete importing example schema (cameraFullimp.xsd) in the appendix.

An XML instance based on the importing schema must provide a namespace for the imported file. In other words, even though the importing schema points to the imported file, the instance must also point to the imported file. It will have the same namespace, in this case http://www.leitz.org, but could have a different prefix. It is normally good practice to maintain the same prefix to reduce possible confusion. As in the instance, you may find it most convenient to always make the namespace designation and prefix assignment in the root element. Here is how the prefix becomes associated with the actual XSD file via the namespace:

xmlns:leitz="http://www.leitz.org" 
	<xsi:schemaLocation="http://www.leitz.org glass.xsd"<

The first line is contained in the root element. Here are the XSD pieces, with the rest of the file missing:

<?xml version="1.0" encoding="UTF-8"?>
<!-- Filename=cameraFullimp.xsd -->
<xsd:schema targetNamespace="http://www.cameraFullimp.org"
xmlns:xsi="http://www.w3.org/2000/10/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2000/10/XMLSchema" 
xmlns:leitz="http://www.leitz.org" 
xmlns="http://www.cameraFullimp.org" 
elementFormDefault="qualified" 
version="1.0">
	<xsd:import namespace="http://www.leitz.org" schemaLocation="glass.xsd"/>
	. . .
	<xsd:complexType name="lensType">
		<xsd:sequence>
			<xsd:element ref="zoom"/>
			<xsd:element ref="f-stop"/>
			<xsd:element ref="leitz:glass"/>
		</xsd:sequence>
		<xsd:anyAttribute/>
	</xsd:complexType>
	. . .

Below is an XML-Schema that creates an element called , in a namespace, http://www.leitz.org. You will see this schema used again.

<?xml version="1.0" encoding="UTF-8"?>
<!-- filename=glass.xsd -->
<!-- 2001-05-07 Thomas Wason -->
<xsd:schema xmlns="http://www.leitz.org" 
targetNamespace="http://www.leitz.org" 
xmlns:xsi="http://www.w3.org/2000/10/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2000/10/XMLSchema"
elementFormDefault="qualified" 
	version="3.5">
	<!--xsi:schemaLocation="http://www.w3.org/2000/10/XMLSchema 
		http://www.w3.org/2000/10/XMLSchema.xsd"-->
	<xsd:attribute form="qualified" name="style">
		<xsd:simpleType>
			<xsd:restriction base="xsd:string">
				<xsd:enumeration value="professional"/>
				<xsd:enumeration value="consumer"/>
			</xsd:restriction>
		</xsd:simpleType>
	</xsd:attribute>
	<xsd:element name="glass" type="glassType" form="qualified"/>
	<xsd:complexType name="glassType">
		<xsd:simpleContent>
			<xsd:extension base="xsd:string">
				<xsd:anyAttribute/>
			</xsd:extension>
		</xsd:simpleContent>
	</xsd:complexType>
</xsd:schema>

Below is an instance that uses an XML-Schema (cameraFullimp.xsd), includes an element (leitz:glass), from another schema (glass.xsd), from the namespace (http://www.leitz.org),from the namespace (prefix leitz:) designates the element (leitz.glass), that is imported from this schema.

<?xml version="1.0" encoding="UTF-8"?>
<!--filename=CameraFullimp.xml-->
<camera xmlns="http://www.cameraFullimp.org"
xmlns:xsi="http://www.w3.org/2000/10/XMLSchema-instance"
xmlns:cam="http://www.cameraFullimp.org" 
	xmlns:leitz="http://www.leitz.org" 
	xsi:schemaLocation="http://www.cameraFullimp.org cameraFullimp.xsd
	http://www.leitz.org glass.xsd">
	<body material="plastic" leitz:style="professional">
		<description>Black</description>
	</body>
	<lens>
		<zoom>100mm - 300mm</zoom>
		<f-stop>f/4.5</f-stop>
		<leitz:glass>Rare Earth</leitz:glass>
	</lens>
	<manual_adapter>
		<speed>1 - 1/1000</speed>
	</manual_adapter>
</camera>

You could alternatively use a block declaration to declare that an element, and all of the elements it contains, are from a specific namespace:

<glass xmlns="http://www.leitz.org">Rare Earth</glass>

A schemaLocation declaration is still required if the instance is to be validated completely.

5. Extending XML Instances

What if you want to add elements or attributes to an instance without changing the underlying XML-Schema? The are two ways to accomplish this: free and controlled extension. One thing to remember: you can't just make up an element or attribute. You always have to create it someplace in a schema. OK, let's get on with it, starting with free extension.

5.1 Free Extension

You may have noted in the XML-Schemas above that there are two pieces that keep showing up:

<xsd:any namespace="##other" minOccurs="0"/>
		<xsd:anyAttribute/>

These are wildcard elements in XML-Schemas. Let's take the "any" element apart. First, the predefined "any" element in the "xsd" namespace is used:

<xsd:any

You can use any element in place of the "any" element. Try reading that sentence to someone! The any element is a place holder in the schema. It defines a "slot" where another element can be placed in the instance. The schema does not define what that element is. Next, there is a definition of the source of the element. This is done by defining the permitted namespace(s) from which the element may come:

namespace="##other" 

There are several possible namespace source declarations. IMS uses only two: ##other and ##any. ##other means that the element can be drawn from any namespace except the one containing the any element. ##any means that the element may be drawn from any namespace including the one containing the any element. When the ##any namespace declaration is used, the element's type must be "mixed", meaning that the element containing the any element must be able to contain both elements and text. The ##any value is the default namespace condition. Within the IMS schemas, for the any element, ##other namespace condition is used. Whatever the choice, ##other or ##any, the namespace of the element must be defined. I have introduced the ##any condition here because that is what is used for the anyAttribute namespace condition in IMS. We'll see how that is used in just a bit.

Next, we want to say that the instance is not required to fill the any slot. Its use is optional. This is done with the minOccurs attribute by setting it to "0":

minOccurs="0"/>

The default maxOccurs is "1". The anyAttribute element creates a place in which any attribute may be placed. By not declaring a namespace condition, the default is the ##any condition:

<xsd:anyAttribute/>

Now let us turn to an example. The simple CameraFull.xml instance above can be extended to contain an element that is an example of a "free" extension. The free extension is taken from the namespace http://www.leitz.org namespace:

<?xml version="1.0" encoding="UTF-8"?>
<!--filename=CameraFulle.xml-->
<camera xmlns="http://www.cameraFull.org" 
	xmlns:xsi="http://www.w3.org/2000/10/XMLSchema-instance" 
	xmlns:leitz="http://www.leitz.org" 
	xsi:schemaLocation="http://www.cameraFull.org cameraFull.xsd
http://www.leitz.org glass.xsd">
	<body material="plastic" leitz:style="professional">
		<description>Black</description>
	</body>
	<lens>
		<zoom>100mm - 300mm</zoom>
		<f-stop>f/4.5</f-stop>
		<leitz:glass>Rare Earth</leitz:glass>
	</lens>
	<manual_adapter>
		<speed>1 - 1/1000</speed>
	</manual_adapter>
</camera>

Notice how much this instance looks like the one above in which the XML-Schema used imports another schema. The difference is the level of control. When the schema imports components, it defines exactly where they may appear. Under free extension, the imported component may be used anyplace. Both instances must reference a namespace for the imported components.

5.2 Controlled Extension

What if you wanted to extend an instance, but wanted to control what extensions could be used and where they could be used? For example, what if you wanted to require that the element <f-stop> be used at the lens element's content? Controlled extension can seem a bit complicated, but the rewards are tight control over instances created with this method. Organizations that want to create controlled extensions may want to use it. The more casual user should be content with the free extensions.

Actually, you have already seen almost all of the pieces you need to do controlled extensions. A controlled extension is accomplished by replacing the element with a new one that includes the new component (notice that I am using the term "component" here-this could also apply to an attribute). The new element is defined as an acceptable substitute for the old one. In order to make the new element like the old one, the old element's type is adjusted. It's good to know what our end target will look like, so here's an example of the resulting XML instance:

<?xml version="1.0" encoding="UTF-8"?>
<!--filename=CameraCntrl.xml-->
<camera xmlns="http://www.cameraFull.org" 
xmlns:cam="http://www.cameraFull.org"
xmlns:leitzlens="http:leitzlens.org" 
xmlns:xsi="http://www.w3.org/2000/10/XMLSchema-instance"
xsi:schemaLocation="http:leitzlens.org
glasscontrolled.xsd 
http://www.cameraFull.org cameraFull.xsd">
	<body material="plastic" leitzlens:style="professional">
		<description>Black</description>
	</body>
	<leitzlens:lens cam:material="brass">
		<zoom>35mm - 100mm</zoom>
		<f-stop>f/3.5</f-stop>
		<leitzlens:glass>Rare Earth</leitzlens:glass>
	</leitzlens:lens>
	<manual_adapter>
		<speed>1 - 1/1000</speed>
	</manual_adapter>
</camera>

What we want to do is to create an element called leitzlens:lens containing an element leitzlens:glass that replaces the old element lens. To make this example realistic, we will also want to still have the any element stay at the end of the sequence. First, we need to create a new schema (glasscontrolled.xsd) to make the alternative element for lens and the new element we want to introduce <glass>. This new schema will import the schema that contains the element <lens>, namely cameraFull.xsd (or the equivalent composite schema, camera.xsd). This is how the new schema does that:

<?xml version="1.0" encoding="UTF-8"?>
<!-- filename=glasscontrolled.xsd -->
<xsd:schema xmlns="http://www.leitzlens.org" 
	targetNamespace="http://www.leitzlens.org" 
	xmlns:cam="http://www.cameraFull.org" 
	xmlns:xsi="http://www.w3.org/2000/10/XMLSchema-instance" 
	xmlns:xsd="http://www.w3.org/2000/10/XMLSchema" 
	elementFormDefault="qualified" 
	version="3.5">
	<xsd:import namespace="http://www.cameraFull.org" schemaLocation="cameraFull.xsd"/>

Notice that a namespace (http://www.leitzlens.org) has been designated for this schema through the targetNamespace. Any other schema or instance that imports this file must use that as its namespace.

Next, let's create the new element leitzlens:glass:

<xsd:element name="glass" type="glassType" form="qualified"/>
	<xsd:complexType name="glassType">
		<xsd:simpleContent>
			<xsd:extension base="xsd:string">
				<xsd:anyAttribute/>
			</xsd:extension>
		</xsd:simpleContent>
	</xsd:complexType>

We have to work backwards to make the new version of lens. We will make this from the old content lens complexType. We will do this in two steps: turn off the current any element, add the new element, glass, to the end of the sequence and add a new any element after it. This requires two steps: a restriction and then an extension. Restriction has different rules than extension, which is why we are doing restriction first. We need to remove the old any element. In order to do this, we are going to restrict the complexType. We create a new intermediate complexType, restrictlensType in which we set the any element's occurrence to "0". We have to do this, or the parser will think that the new element is a free extension, as any would precede our new element in the sequence. The rules of restriction say that you have to repeat every element in the original. You can't add any new ones.

<xsd:complexType name="restrictlensType">
		<xsd:complexContent>
			<xsd:restriction base="cam:lensType">
				<xsd:sequence>
					<xsd:element ref="cam:zoom"/>
					<xsd:element ref="cam:f-stop"/>
					>xsd:any maxOccurs="0"/>
				</xsd:sequence>
			</xsd:restriction>
		</xsd:complexContent>
	</xsd:complexType>

Now we have turned off any. Note the use of the "cam:" prefix. Next we want to add the new element, <glass>. We do this in a new complexType ,

lensType
, that is based on our restricted complexType:
	<xsd:complexType name="lensType">
		<xsd:complexContent>
			<xsd:extension base="restrictlensType">
				<xsd:sequence>
					<xsd:element ref="glass" minOccurs="0"/>
					<xsd:any namespace="##other"/>
				</xsd:sequence>
				<xsd:attribute ref="cam:material"/>
				<xsd:anyAttribute/>
			</xsd:extension>
		</xsd:complexContent>
	</xsd:complexType>

Notice that the elements that already exist in restrictLensType are not repeated in the extension. Now we want to make the new element <lens>, equivalent to the old one. We have namespaced the old <lens> in the schema, providing the prefix "cam:" so that we can use the same name for the new element. This makes a more readable final instance. We create the equivalence of the new element with the old by declaring the new element as a member of the group that can substitute for the old element. The attribute substitutionGroup is used: <XSD:ELEMENT form="qualified" substitutionGroup="cam:lens" type="lensType" name="lens" />. We want to force the use of a prefix when the new element is used so that it will not be confused with the old one. This is done by forcing the new element to be "qualified", or associated with the proper namespace. Now if you go back and look at the XML instance above, you can see where the pieces come from.

6. Conclusion

It is a good idea to build specifications from other specifications, as it harmonizes the results. It saves work and ensures that several specifications define the same thing in the same way-which is great for interoperability. If you import rather than include, then you have shown where the pieces came from. Additionally, if an imported piece gets a new version, that new versioning does not have to change the version of the schema that imports it. On the other hand, an included piece is invisible in the instance. If an included schema changes, the instance does not have the ability to check that part separately, so a new version is needed to reflect the change. As you can see, you can achieve the same result in an instance in several ways. You can freely extend,you can extend in a controlled manner, and you can have a primary schema that imports components. All are valid and useful. You have to determine which one fits each situation.

Many of the terms in this guide are defined in the Glossary.
 

Author:

Thomas D. Wason, Ph.D. (aka Dr. Tom)
http://www.tomwason.com
wason@mindspring.com

Go to Top
http://www.tomwason.com