Using XML Schema 1.0, when can language components be removed and maintain backwards or forwards compatibility?

| | Comments (0) | TrackBacks (0)

A separate post answered the question "When can language components be removed and maintain backwards or forwards compatibility?" The two main decisions are whether the content is accepted after it has been removed or not, and exactly how much content is removed, that is the adjustments to minOccurs and maxOccurs. This post looks at the various scenarios and decisions using XML Schema 1.0.

Remove and Accept using XML Schema 1.0
One technique of remove and still allow is to replace an element with a wildcard that allows that element. Another technique of remove and still allow is to replace the type definition with an xs:anyType.

The location of the element with respect to wildcards is of crucial importance. There are two main scenarios: the element to be removed is not adjacent to a wildcard, or the element to be removed is adjacent to a wildcard.

Element not adjacent to wildcard
Where the element to be removed is not adjacent to a wildcard, then a wildcard cannot typically be introduced so the the type definition must be replaced with xs:anyType.

An example of this in XSD 1.0 is removing a given from a name structure:

<!-- V1 Name -->
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.example.org/name/1"
xmlns:namens="http://www.example.org/name/1">

<xs:complexType name="nameType">
<xs:sequence>
<xs:element name="given" type="xs:string"/>
<xs:element name="family" type="xs:string"/>
<xs:any namespace="##any" processContents="lax"
minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
<xs:anyAttribute namespace="##any"/>
</xs:complexType>

<xs:element name="personName" type="namens:nameType"/>
</xs:schema>

A wildcard that allows the same namespace cannot be introduced unless it has a minOccurs== maxOccurs. The following is illegal:

An example of this in XSD 1.0 is removing a Family from a Name structure:

<!-- Illegal V2 Name with given replaced by ##any wildcard -->
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.example.org/name/1"
xmlns:namens="http://www.example.org/name/1">

<xs:complexType name="nameType">
<xs:sequence>
<xs:any namespace="##any" processContents="lax"
minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="family" type="xs:string"/>
<xs:any namespace="##any" processContents="lax"
minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
<xs:anyAttribute namespace="##any"/>
</xs:complexType>

<xs:element name="personName" type="namens:nameType"/>
</xs:schema>

but the following is legal:

<!-- legal V2 Name with given replaced by ##targetNamespace wildcard with minOccurs=1=maxOccurs-->
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.example.org/name/1"
xmlns:namens="http://www.example.org/name/1">

<xs:complexType name="nameType">
<xs:sequence>
<xs:any namespace="##targetNamespace" processContents="lax"
minOccurs="1" maxOccurs="1"/>
<xs:element name="family" type="xs:string"/>
<xs:any namespace="##any" processContents="lax"
minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
<xs:anyAttribute namespace="##any"/>
</xs:complexType>

<xs:element name="personName" type="namens:nameType"/>
</xs:schema>

However, this does not allow the case where the previously desired content is no longer required. The only legal schema that still allows the previously defined given and removes the type definition is:
<!-- V1 Name -->
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.example.org/name/1"
xmlns:namens="http://www.example.org/name/1">

<xs:complexType name="nameType">
<xs:sequence>
<xs:element name="given" type="xs:anyType"/>
<xs:element name="family" type="xs:string"/>
<xs:any namespace="##any" processContents="lax"
minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
<xs:anyAttribute namespace="##any"/>
</xs:complexType>

<xs:element name="personName" type="namens:nameType"/>
</xs:schema>

Conclusion
With XML Schema 1.0, there is no way to completely remove an element name and type definition in V2 of the language and yet allow the element defined in V1 to exist in instances when there is no wildcard adjacent to the element in V1 of the language. It is possible to relax an element's type definition in V2 of the language OR replace the element with a wildcard of the targetnamespace with minOccurs=maxOccurs=1 - thus requiring some element from the targetnamespace.

Element adjacent to Wildcard

When the element to be removed is adjacent to a wildcard, then in some combinations of element cardinality, wildcard namespace and wildcard cardinality, the element can be completely removed.

An example of this in XSD 1.0 is removing a family from a name structure:

<!-- V1 Name -->
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.example.org/name/1"
xmlns:namens="http://www.example.org/name/1">

<xs:complexType name="nameType">
<xs:sequence>
<xs:element name="given" type="xs:string"/>
<xs:element name="family" type="xs:string"/>
<xs:any namespace="##any" processContents="lax"
minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
<xs:anyAttribute namespace="##any"/>
</xs:complexType>

<xs:element name="personName" type="namens:nameType"/>
</xs:schema>

Note that we can write a schema that specifies that the "family" is still allowed without saying a type because the following is legal:
<!-- legal V2 Schema -->
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.example.org/name/1"
xmlns:namens="http://www.example.org/name/1">

<xs:complexType name="nameType">
<xs:sequence>
<xs:element name="given" type="xs:string"/>
<xs:any namespace="##any" processContents="lax"
minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
<xs:anyAttribute namespace="##any"/>
</xs:complexType>

<xs:element name="personName" type="namens:nameType"/>
</xs:schema>

However, many schemas have an element at the end that is optional, or does not have a minOccurs == maxOccurs, and this requires use of ##other in the wildcard, such as:
<!-- Name V1 with optional family then ##other -->
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.example.org/name/1"
xmlns:namens="http://www.example.org/name/1">

<xs:complexType name="nameType">
<xs:sequence>
<xs:element name="given" type="xs:string"/>
<xs:element name="family" type="xs:string" minOccurs="0"/>
<xs:any namespace="##other" processContents="lax"
minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
<xs:anyAttribute namespace="##any"/>
</xs:complexType>

<xs:element name="personName" type="namens:nameType"/>
</xs:schema>

This schema can also be rewritten to allow the family, though it will also allow any other element in the target namespace
<!-- Name V2 with ##any -->
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.example.org/name/1"
xmlns:namens="http://www.example.org/name/1">

<xs:complexType name="nameType">
<xs:sequence>
<xs:element name="given" type="xs:string"/>
<xs:any namespace="##any" processContents="lax"
minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
<xs:anyAttribute namespace="##any"/>
</xs:complexType>

<xs:element name="personName" type="namens:nameType"/>
</xs:schema>

If we want to only allow a family name in the target namespace as well as any other namespace, then the type of family must be xs:any in V2, such as:
<!-- Name V2 with anyType family and ##other -->
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.example.org/name/1"
xmlns:namens="http://www.example.org/name/1">

<xs:complexType name="nameType">
<xs:sequence>
<xs:element name="given" type="xs:string"/>
<xs:element name="family" type="xs:anyType" minOccurs="0"/>
<xs:any namespace="##other" processContents="lax"
minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
<xs:anyAttribute namespace="##any"/>
</xs:complexType>

<xs:element name="personName" type="namens:nameType"/>
</xs:schema>

There is one scenario where we cannot write a schema that allows the removed content without retaining the type, which is when the removed content is adjacent to another optional element.
<!-- Name V1 with optional family and middle and ##other-->
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.example.org/name/1"
xmlns:namens="http://www.example.org/name/1">

<xs:complexType name="nameType">
<xs:sequence>
<xs:element name="given" type="xs:string"/>
<xs:element name="family" type="xs:string" minOccurs="0"/>
<xs:element name="middle" type="xs:string" minOccurs="0"/>
<xs:any namespace="##other" processContents="lax"
minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
<xs:anyAttribute namespace="##any"/>
</xs:complexType>

<xs:element name="personName" type="namens:nameType"/>
</xs:schema>

The middle and wildcard cannot be replaced with a wildcard of ##any because the family is still optional. The only Schema 1.0 change that still permits the middle is to replace the type with xs:anyType. It cannot be replaced with a wildcard with ##targetNamespace because that wildcard and the optional family would create a UPA violation.

Conclusion
With XML Schema 1.0, it is possible to completely remove an element name and type definition in V2 of the language and still allow the element defined in V1 to exist in instances when there is a wildcard adjacent to the element in V1 of the language IF the element is mandatory OR if the element is optional and is not proceeded by another optional element. If the element is optional and is proceeded by another optional element, it is possible to relax an element's type definition in V2 of the language.


Remove and not Accept minOccurs < maxOccurs with XML Schema 1.0
For example,
<!-- Name V1 with optional middle and ##other-->
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.example.org/name/1"
xmlns:namens="http://www.example.org/name/1">

<xs:complexType name="nameType">
<xs:sequence>
<xs:element name="given" type="xs:string"/>
<xs:element name="family" type="xs:string"/>
<xs:element name="middle" type="xs:string" minOccurs="0"/>
<xs:any namespace="##other" processContents="lax"
minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
<xs:anyAttribute namespace="##any"/>
</xs:complexType>

<xs:element name="personName" type="namens:nameType"/>
</xs:schema>

<!-- Name V2 with middle removed and ##other-->
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.example.org/name/1"
xmlns:namens="http://www.example.org/name/1">

<xs:complexType name="nameType">
<xs:sequence>
<xs:element name="given" type="xs:string"/>
<xs:element name="family" type="xs:string"/>
<xs:any namespace="##other" processContents="lax"
minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
<xs:anyAttribute namespace="##any"/>
</xs:complexType>

<xs:element name="personName" type="namens:nameType"/>
</xs:schema>

Conclusion
With XML Schema 1.0, it is possible to completely remove an element name and type definition in V2 of the language and disallow the element if the element is optional so V2 is forwards compatible with V1, but V2 will only be backwards compatible with V1 if all the V1 producers do not produce instances of the element.

Remove and Not Accept minOccurs == maxOccurs with XML Schema 1.0

Using the Name V1 introduced in the previous section, the following schema is neither backwards or forwards compatible with V1:

For example,
<!-- Name V1 with family removed -->
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.example.org/name/1"
xmlns:namens="http://www.example.org/name/1">

<xs:complexType name="nameType">
<xs:sequence>
<xs:element name="given" type="xs:string"/>
<xs:element name="middle" type="xs:string" minOccurs="0"/>
<xs:any namespace="##other" processContents="lax"
minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
<xs:anyAttribute namespace="##any"/>
</xs:complexType>

<xs:element name="personName" type="namens:nameType"/>
</xs:schema>

0 TrackBacks

Listed below are links to blogs that reference this entry: Using XML Schema 1.0, when can language components be removed and maintain backwards or forwards compatibility?.

TrackBack URL for this entry: http://www.pacificspirit.com/cgi-bin/mt/mt-tb.cgi/152

Leave a comment

About this Entry

This page contains a single entry by Dave Orchard published on September 13, 2007 3:21 PM.

When can language components be removed and maintain backwards or forwards compatibility? was the previous entry in this blog.

PVRs in Canada? is the next entry in this blog.

Find recent content on the main index or look in the archives to find all content.

Categories