While the ability to constrain instance documents is essential for interoperability, harnessing the type system exploits the real power of XML Schema. The inheritance features in XML Schema allow you to create type hierarchies that capture the data models of the underlying software systems that XML is designed to support.
My previous article discussed one form of inheritance: We used the restriction feature to create new simple types with differently constrained value and lexical spaces. However, XML Schema also supports a mechanism called extension that allows you to augment (rather than constrain) the capabilities of an existing type. By extending the type, you can begin to create hierarchies of complex types, just as you can in object-oriented programming languages.
Complex type extension offers two kinds of subtypes:
Subtypes that contain only simple content (text and attributes only)
Subtypes that contain complex content (other elements in addition to text and attributes)
Listing 1 shows an example of extending a complex type with additional simple content.
Listing 1 Complex Type Extension with simpleContent
<xs:complexType name="MonitorType"> <xs:simpleContent> <xs:extension base="xs:string"> <xs:attribute name="flatscreen" type="xs:boolean"/> </xs:extension> </xs:simpleContent> </xs:complexType>
The MonitorType complex type in Listing 1 uses the simpleContent element to add a single attribute to its content, which is defined as being the string built-in type. The base type of the MonitorType type (string) is specified by the base attribute in the extension element. The additional simple content is specified as the only child of this extension element. The new subtype we have defined can now be used to validate elements such as the following:
<monitor flatscreen="true">HP P4831D</monitor>
Listing 2 shows an example of how to use the extension mechanism to create subtypes with additional elements using the complexContent construct.
Listing 2 Complex Type Extension with complexContent
<xs:complexType name="PersonType"> <xs:sequence> <xs:element name="forename" type="xs:string"/> <xs:element name="surname" type="xs:string"/> </xs:sequence> </xs:complexType> <xs:complexType name="FootballerType"> <xs:complexContent> <xs:extension base="PersonType"> <xs:sequence> <xs:element name="team" type="xs:string"/> <xs:element name="goals" type="xs:int"/> </xs:sequence> </xs:extension> </xs:complexContent> </xs:complexType>
The PersonType type in Listing 2 can be used to validate instances such as the one in Listing 3.
Listing 3 An Instance of the PersonType Type
<person> <forename>Alan</forename> <surname>Turing</surname> </person>
The FootballerType type in Listing 2 has complexContent, allowing elements and attributes to appear within the body of the type. It capitalizes on that fact by adding the team and goals elements to extend the base PersonType to allow the validation of such elements as shown in Listing 4.
Listing 4 A FootballerType Type Instance
<footballer> <forename>Alan</forename> <surname>Shearer</surname> <team>Newcastle United</team> <goals>145</goals> </footballer>
In Listing 4, instances of the FootballerType type have a similar structure to instances of the PersonType type, because the FootballerType subtype inherits the forename and surname elements from the PersonType, but adds the elements team and goals.
From this example, you can see that it's possible to use the extension mechanism to build type hierarchies in XML Schema, just as in object-oriented programming languages. However, to be able to exploit such hierarchies (for example, to "cast" between types), we need another XML Schema mechanism: substitution groups.