"Seegrid will be due for a migration to confluence on the 1st of August. Any update on or after the 1st of August will NOT be migrated"

Derivation by restriction exercises

Contents

Related pages



In SchemaFormalization there is a brief discussion regarding the pros-and-cons of specialized classes "overriding" properties of more generalized classes.

SimonCox noted that in the XML Schema implementation this requires use of derivation-by-restriction, which is one of the less-well understood and less-consistently implemented parts of XML Schema. For this reason he proposed a pattern whereby, when it is necessary that a concrete general case of a class exist alongside specializations, that these be implemented as "siblings" rather than parent and child.

EricBoisvert requested that the issue be revisited.

See schema and instance examples https://www.seegrid.csiro.au/subversion/xmml/trunk/restrictionTest/

0. Restricting across namespace boundaries

Can't be done if it involves changing the type of an element declared "locally" in the source namespace.

1. Restricting xsd:anyType

The type of my:prop1 in the Head element is xsd:anyType. In Child1 this is restricted to xsd:string, and in Child2 this is restricted to my:Child1_Property_Type.
   <complexType name="Head_Type">
      <sequence>
         <element name="prop1" type="anyType"/>
      </sequence>
   </complexType>
   <element name="Head" type="my:Head_Type"/>
   <!-- ========== -->
   <complexType name="Child1_Type">
      <complexContent>
         <restriction base="my:Head_Type">
            <sequence>
               <element name="prop1" type="string"/>
            </sequence>
         </restriction>
      </complexContent>
   </complexType>
   <element name="Child1" type="my:Child1_Type" substitutionGroup="my:Head"/>
   <complexType name="Child1_Property_Type">
      <sequence>
         <element ref="my:Child1"/>
      </sequence>
   </complexType>
   <!-- ========== -->
   <complexType name="Child2_Type">
      <complexContent>
         <restriction base="my:Head_Type">
            <sequence>
               <element name="prop1" type="my:Child1_Property_Type"/>
            </sequence>
         </restriction>
      </complexContent>
   </complexType>
   <element name="Child2" type="my:Child2_Type" substitutionGroup="my:Head"/>

The sample instance shows the result, in which my:prop1 has three different content models, depending on context.
<my:Head ...>
   <my:prop1>
      <my:Child2>
         <my:prop1>
            <my:Child1>
               <my:prop1>test string fgwelkjfh weoihfweoiuf</my:prop1>
            </my:Child1>
         </my:prop1>
      </my:Child2>
   </my:prop1>
</my:Head>

This example validates using all the processors tested.

2. Derived type

However, it doesn't work if you use types with the wrong kind of relationship. For example:
   <complexType name="Geo1_Type">
      <sequence>
         <element name="prop1" type="gml:AbstractGeometricPrimitiveType"/>
      </sequence>
   </complexType>
   <element name="Geo1" type="my:Geo1_Type"/>
   <!-- ========== -->
   <complexType name="Point1_Type">
      <complexContent>
         <restriction base="my:Geo1_Type">
            <sequence>
               <element name="prop1" type="gml:PointType"/>
            </sequence>
         </restriction>
      </complexContent>
   </complexType>
   <element name="Point1" type="my:Point1_Type" substitutionGroup="my:Geo1"/>
is not valid because gml:PointType extends gml:AbstractGeometricPrimitiveType, so my:Point1_Type is not a valid restriction of my:Geo1_Type.

3. Selecting one member of a substitution group

The problem in the previous example can be overcome by using element substitutability instead of types. For example the content model for my:Point1_Type restricts the content model of the parent by selecting one member of the choice group implied by the substitution-group head gml:_Geometry :
   <complexType name="Geo1_Type">
      <sequence>
         <element ref="gml:_Geometry"/>
      </sequence>
   </complexType>
   <element name="Geo1" type="my:Geo1_Type"/>
   <!-- ========== -->
   <complexType name="Point1_Type">
      <complexContent>
         <restriction base="my:Geo1_Type">
            <sequence>
               <element ref="gml:Point"/>
            </sequence>
         </restriction>
      </complexContent>
   </complexType>
   <element name="Point1" type="my:Point1_Type" substitutionGroup="my:Geo1"/>

This leads to instances like the following two samples:
<my:Geo1 ...>
   <gml:Point>
      <gml:pos>1 2</gml:pos>
   </gml:Point>
</my:Geo1>

<my:Point1 ...>
   <gml:Point>
      <gml:pos>1 2</gml:pos>
   </gml:Point>
</my:Point1>

These examples are OK according to all validators except Xerces-C++ (which is unfortunate since that is the builtin validator in Stylus Studio).

4. Derived property-type

However, the careful reader will have noticed that 3. does not follow the GML Object/property pattern, which requires a container for the element representing the geometry. For example:
<my:Geo1 ... >
   <my:prop2>
      <gml:Point>
         <gml:pos>1 2</gml:pos>
      </gml:Point>
   </my:prop2>
</my:Geo1>

<my:Point1 ...>
   <my:prop2>
      <gml:Point>
         <gml:pos>1 2</gml:pos>
      </gml:Point>
   </my:prop2>
</my:Point1>

These two examples are valid according to the following schema (though not according to Xerces-C++):
   <complexType name="Geo1_Type">
      <sequence>
         <element name="prop2" type="gml:GeometryPropertyType"/>
      </sequence>
   </complexType>
   <element name="Geo1" type="my:Geo1_Type"/>
   <!-- ========== -->
   <complexType name="Point1_Type">
      <complexContent>
         <restriction base="my:Geo1_Type">
            <sequence>
               <element name="prop2" type="my:PointPropertyType"/>
            </sequence>
         </restriction>
      </complexContent>
   </complexType>
   <element name="Point1" type="my:Point1_Type" substitutionGroup="my:Geo1"/>
   <!-- ========== -->
   <complexType name="PointPropertyType">
      <complexContent>
         <restriction base="gml:GeometryPropertyType">
            <sequence minOccurs="0">
               <element ref="gml:Point"/>
            </sequence>
            <attributeGroup ref="gml:AssociationAttributeGroup"/>
         </restriction>
      </complexContent>
   </complexType>

The challenge using this pattern is that it requires the use of explicit property-types, which must themselves be in a suitable derivation relationship. As shown above, this can be achieved if care is taken, but can be a source of nasty gotchas.

The other infelicity in XML Schema restriction is that all the inherited properties must be repeated in the definition of the derived type - a bookkeeping adventure which is also accident prone.

-- SimonCox - 11 Jul 2005

Derived property types

Care must be taken about where you put the cardinality constraint in order to satisfy the strict validation rules laid out in the XML Schema specification.

The GML Association pattern is:
   <complexType name="AssociationType">
      <sequence minOccurs="0">
         <element ref="gml:_Object"/>
      </sequence>
      <attributeGroup ref="gml:AssociationAttributeGroup"/>
   </complexType>
This is used for FeaturePropertyType as follows:
   <complexType name="FeaturePropertyType">
      <sequence minOccurs="0">
         <element ref="gml:_Feature"/>
      </sequence>
      <attributeGroup ref="gml:AssociationAttributeGroup"/>
   </complexType>
Note that the content
<element ref="gml:_Feature"/>
is an implicit choice group as follows
<choice>
   [all the element declarations with 
   substitutionGroup="gml:_Feature" 
   that the processor knows about]
</choice>
The derivation-by-restriction step selects one of these, so the correct form for a specialised feature-property is
   <complexType name="ForecastMemberType">
            <complexContent>
               <restriction base="gml:FeaturePropertyType">
                  <sequence minOccurs="0">
                     <element ref="gml:Observation"/>
                  </sequence>
                  <attributeGroup ref="gml:AssociationAttributeGroup" />
               </restriction>
            </complexContent>
   </complexType>
Note that the minOccurs="0" is on the sequence element, not the element element. This has no effect on the content model, but does allow the processor to recognise that it is a valid restriction. This pattern was introduced consistently starting with GML 3.1.1 to resolve this very issue.

Note also that it is not necessary for *PropertyType to use derivation-by-restriction, unless this is required to enable another substitutability requirement. It is often easier to treat gml:AssociationType as a pattern rather than a root - the definition of gml:FeaturePropertyType takes this approach, which is encouraged by the GML spec.

-- SimonCox - 13 Jul 2005

 
Topic revision: r9 - 15 Oct 2010, UnknownUser
 

Current license: All material on this collaboration platform is licensed under a Creative Commons Attribution 3.0 Australia Licence (CC BY 3.0).