Wrapped around the axle: Refining and extending structures across namespaces

On many occasions, I have found the need to define a structure in one
namespace and refine it and extend it in another. This always results in me
getting wrapped around the axle, going round and round over how to represent
all that needs representing. I suspect that this is a problem shared by
many. I've come up with a workable but awkward approach, but I'd like to
know if there's a better way.

The two major difficulties I encounter are 1) keeping the refinement and
extension appropriately separate and 2) keeping namespace prefixing in the
instance document simple and manageable. 


I'll demonstrate in a somewhat contrived example. 

Say I have a complex type DocumentType defined in namespace ns1. It defines
the element Header of type HeaderType and Line of type LineType:

  <xs:schema targetNamespace="ns1" xmlns="ns1" 
		xmlns:xs="http://www.w3.org/2001/XMLSchema"
		elementFormDefault="qualified"
attributeFormDefault="unqualified">
	<xs:element name="Document" type="DocumentType"/>
	<xs:complexType name="DocumentType">
		<xs:sequence>
			<xs:element name="Header" type="HeaderType"/>
			<xs:element name="Line" type="LineType"
maxOccurs="unbounded"/>
		</xs:sequence>
	</xs:complexType>
	<xs:complexType name="HeaderType">
		<xs:sequence>
			<xs:element name="CreationDate" type="xs:date"/>
		</xs:sequence>
	</xs:complexType>
	<xs:complexType name="LineType">
		<xs:sequence>
			<xs:element name="LineNumber"
type="xs:positiveInteger"/>
		</xs:sequence>
	</xs:complexType>
   </xs:schema>

Fairly simple. Now, in namespace ns2, I'd like to build an extended
DocumentType, based on ns1:DocumentType, to add a Footer element:  

   <xs:schema targetNamespace="ns2"
xmlns:xs="http://www.w3.org/2001/XMLSchema" 
		xmlns="ns2" xmlns:ns1="ns1" 
		elementFormDefault="qualified"
attributeFormDefault="unqualified">
	<xs:import namespace="ns1" schemaLocation="RefineExtend-NS1.xsd"/>
	<xs:element name="Document" type="DocumentType"/>
	<xs:complexType name="DocumentType">
		<xs:complexContent>
			<xs:extension base="ns1:DocumentType">
				<xs:sequence>
					<xs:element name="Footer"/>
				</xs:sequence>
			</xs:extension>
		</xs:complexContent>
	</xs:complexType>
   </xs:schema>

Also simple. I'd also like to extend ns1:HeaderType to add, e.g., a
LastModifiedDate:
	...
	<xs:complexType name="HeaderType">
		<xs:complexContent>
			<xs:extension base="ns1:HeaderType">
				<xs:sequence>
					<xs:element name="LastModifiedDate"
type="xs:date"/>
				</xs:sequence>
			</xs:extension>
		</xs:complexContent>
	</xs:complexType>
	...

The trouble arises when I want to have ns2:DocumentType use the extended
HeaderType. In order to rebind the Header element in ns2:DocumentType to be
ns2:HeaderType, I must define ns2:DocumentType to restrict ns1:DocumentType:

   <xs:schema targetNamespace="ns2"
xmlns:xs="http://www.w3.org/2001/XMLSchema" 
		xmlns="ns2" xmlns:ns1="ns1" 
		elementFormDefault="qualified"
attributeFormDefault="unqualified">
	<xs:import namespace="ns1" schemaLocation="RefineExtend-NS1.xsd"/>
	<xs:element name="Document" type="DocumentType"/>
	<xs:complexType name="DocumentType">
		<xs:complexContent>
			<xs:restriction base="ns1:DocumentType">
				<xs:sequence>
					<xs:element name="Header"
type="HeaderType"/>
					<xs:element name="Line"
type="ns1:LineType" maxOccurs="unbounded"/>
				</xs:sequence>
			</xs:restriction>
		</xs:complexContent>
	</xs:complexType>
	<xs:complexType name="HeaderType">
		<xs:complexContent>
			<xs:extension base="ns1:HeaderType">
				<xs:sequence>
					<xs:element name="LastModifiedDate"
type="xs:date"/>
				</xs:sequence>
			</xs:extension>
		</xs:complexContent>
	</xs:complexType>
  </xs:schema>

In doing so I have lost the ability to extend ns2:DocumentType to include
the footer element. If I add the footer element footer into the restriction
sequence, I have violated the rules of restriction.

How I've handled it, in an unpretty way, is to separate the extension step
and the restriction step into two levels of hierarchy. ns2:DocumentBaseType
restricts ns1:DocumentType so that I can bind the element Header to type
ns2:HeaderType. ns2:DocumentType then extends DocumentBaseType to add the
Footer element:

   <xs:schema targetNamespace="ns2" xmlns:ns1="ns1" xmlns="ns2" 
		xmlns:xs="http://www.w3.org/2001/XMLSchema" 
		elementFormDefault="qualified"
attributeFormDefault="unqualified">
	<xs:import namespace="ns1" schemaLocation="RefineExtend-NS1.xsd"/>
	<xs:element name="Document" type="DocumentType"/>
	<xs:complexType name="DocumentBaseType">
		<xs:complexContent>
			<xs:restriction base="ns1:DocumentType">
				<xs:sequence>
					<xs:element name="Header"
type="HeaderType"/>
					<xs:element name="Line"
type="ns1:LineType" maxOccurs="unbounded"/>
				</xs:sequence>
			</xs:restriction>
		</xs:complexContent>
	</xs:complexType>
	<xs:complexType name="DocumentType">
		<xs:complexContent>
			<xs:extension base="DocumentBaseType">
				<xs:sequence>
					<xs:element name="Footer"/>
				</xs:sequence>
			</xs:extension>
		</xs:complexContent>
	</xs:complexType>
	<xs:complexType name="HeaderType">
		<xs:complexContent>
			<xs:extension base="ns1:HeaderType">
				<xs:sequence>
					<xs:element name="LastModifiedDate"
type="xs:date"/>
				</xs:sequence>
			</xs:extension>
		</xs:complexContent>
	</xs:complexType>
   </xs:schema>

Messy, but workable. 

The result is an instance document with root element Document as defined in
ns2: 

   <Document xmlns="ns2" xmlns:ns1="ns1" 
		xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="ns2
		RefineExtend-NS2-3.xsd">
	<Header>
		<ns1:CreationDate>1967-08-13</ns1:CreationDate>
		<LastModifiedDate>1967-08-13</LastModifiedDate>
	</Header>
	<Line>
		<ns1:LineNumber>2</ns1:LineNumber>
	</Line>
	<Footer>Text</Footer>
   </Document>

Since most of the content has been defined via restriction, the only
namespace prefixes required are for the elements or types that are fully
defined in ns1.

It can be confusing for the user of the ns2 xsd to figure out the correct
namespace prefixing of elements in the instance documents, though,
especially when the content originated in ns1 and only "migrates" to ns2 as
the result of a restriction. It gets even more confusing when this kind of
refinement/extension cascades down more levels.

My questions are 1) Am I doing this right? and 2) Are there better ways to
achieve what I need to?



Mark Feblowitz
XML Architect
Frictionless Commerce Incorporated
400 Technology Square, 9th floor
Cambridge, MA 02139
(617) 715-7231
mfeblowitz@frictionless.com

Received on Wednesday, 19 December 2001 15:29:01 UTC