6.
Restrictions and Substitutions
The restriction
element comes into play while deriving new types from the base type. It merely
regulates or reduces the tasks that are performed in the base type for the new
type. Thus, it is imperative to first create the base type. Then, while
creating the new type, the values can be curbed using the restriction element.
The restriction
element was touched upon cursorily in the earlier chapter, but the primary
focus then in that chapter was on simple types. In this chapter, we shall
scrutinize the nuances of restricting the complexType element, in considerable
detail.
b.xsd
<xs:schema
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="zzz" type="c2" />
<xs:complexType name="c1">
<xs:sequence>
<xs:element name="aaa" minOccurs="0"
maxOccurs="unbounded" type="xs:string" />
<xs:element name="bbb"
type="xs:string"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="c2">
<xs:complexContent>
<xs:restriction base="c1">
<xs:sequence>
<xs:element name="aaa" minOccurs="1"
maxOccurs="unbounded" type="xs:string"/>
<xs:element name="bbb"
type="xs:string"/>
</xs:sequence>
</xs:restriction>
</xs:complexContent>
</xs:complexType>
</xs:schema>
b.xml
<?xml version="1.0"?>
<zzz>
<aaa />
<bbb />
</zzz>
The root element
zzz is allotted the type c2. This type starts with a complexContent element,
followed by the restriction element, with its base initialized to the type c1.
This lays certain restrictions on the type c1.
The type c1 has
an element aaa with the minOccurs attribute having the value of 0. In addition,
there exists a string element bbb. The type c2 has the same elements of aaa and
bbb, but with the minOccurs value of 1. This ensures the presence of at least
one occurrence of the element aaa in the xml file.
Uprooting the
element aaa from the xml file would obviously flag an error.
Error
Element 'zzz' has invalid child element 'bbb'. Expected
'aaa'.
However, on
eliminating aaa from the xml file and changing the type of element zzz from c2
to c1, would eliminate all errors. This is because, the element aaa becomes
optional in the type c1.
b.xsd
...
<xs:complexType name="c2">
<xs:complexContent>
<xs:restriction base="c1">
<xs:sequence>
<xs:element name="aaa" minOccurs="1"
maxOccurs="unbounded" type="xs:string"/>
<xs:element name="bbb"
type="xs:string"/>
<xs:element name="ccc"
type="xs:string"/>
</xs:sequence>
</xs:restriction>
</xs:complexContent>
</xs:complexType>
...
Error
Unhandled Exception: System.Xml.Schema.XmlSchemaException:
Invalid particle derivation by restriction. An error occurred at
file:///c:/xmlprg/b.xsd(9, 2).
The above
exception is thrown because the element ccc has been added after the element
bbb in complexType c2. We are not allowed to add or subtract anything from the
type c1. All the original members must remain unaltered. Also, the names of the
elements can neither be changed nor removed. The only permissible action is
that of restricting the existing elements. However, the base type cannot be
changed or extended; only the elements can be restricted.
b.xsd
<xs:schema
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="zzz" type="c2" />
<xs:complexType name="c1">
<xs:sequence>
<xs:element name="aaa" type="xs:integer"
/>
<xs:element name="bbb"
type="xs:string"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="c2">
<xs:complexContent>
<xs:restriction base="c1">
<xs:sequence>
<xs:element name="aaa">
<xs:simpleType>
<xs:restriction base="xs:integer">
<xs:maxExclusive value="100"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
<xs:element name="bbb"
type="xs:string"/>
</xs:sequence>
</xs:restriction>
</xs:complexContent>
</xs:complexType>
</xs:schema>
b.xml
<?xml version="1.0"?>
<zzz>
<aaa> 10 </aaa>
<bbb />
</zzz>
In the above xsd
program, the root element zzz is based on type c2. This type restricts type c1,
which consists of two elements: element aaa, which is an integer, and element
bbb, which is a string. In type c2, another element aaa is created, whose value
is restricted to a maximum of 100. In this manner, the value of an element can
be restricted.
b.xsd
<xs:schema
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="zzz" type="c2" />
<xs:complexType name="c1">
<xs:sequence>
<xs:element name="aaa">
<xs:simpleType>
<xs:restriction base="xs:integer">
<xs:maxExclusive value="100"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
<xs:element name="bbb"
type="xs:string"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="c2">
<xs:complexContent>
<xs:restriction base="c3">
<xs:sequence>
<xs:element name="aaa">
<xs:simpleType>
<xs:restriction base="xs:integer">
<xs:maxExclusive value="100"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
<xs:element name="bbb"
type="xs:string"/>
</xs:sequence>
</xs:restriction>
</xs:complexContent>
</xs:complexType>
<xs:complexType name="c3">
<xs:sequence>
<xs:element name="aaa" type="xs:integer"
/>
<xs:element name="bbb"
type="xs:string"/>
</xs:sequence>
</xs:complexType>
</xs:schema>
b.xml
<?xml version="1.0"?>
<zzz>
<aaa> 10 </aaa>
<bbb />
</zzz>
In the above
example, the root element zzz is assigned the type c2. This complexType c2
contains the complexContent. Then, using the restriction element, it restricts
its type to c3. This type c3 is very elementary. It has an integer element aaa
and a string element bbb. In type c3, the simpleType element is used together
with restriction, to further restrict the value of the type aa to less than
100. This explains why the xml file passes validation.
The type c1 is
created with two elements aaa and bbb. For the element aaa, a combination of
simpleType and restriction has been used, wherein the restriction element
regulates the integer value of the type to be less than 100. To authenticate
this, change the type of zzz from c2 to c1, and you shall surely not encounter
any errors.
Now, carry out
one more minor amendment to the xsd file.
b.xsd
..
<xs:complexType name="c2">
<xs:complexContent>
<xs:restriction base="c1">
<xs:sequence>
<xs:element name="aaa">
...
In the
complexType definition for type c2, the restriction is now based on the type
c1, instead of c3. However, even though c1 is a perfectly valid type, the
following exception is thrown:
Error
Unhandled Exception: System.Xml.Schema.XmlSchemaException:
Invalid particle derivation by restriction. An error occurred at
file:///c:/xmlprg/b.xsd(15, 2).
Thus, it is not
permissible to restrict an element that has already been restricted in the
parent class. Consequently, the type c1 cannot be used as a base for
restriction any more.
b.xsd
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="zzz" type="c2" />
<xs:complexType name="c1">
<xs:sequence>
<xs:element name="aaa" minOccurs="1"
maxOccurs="unbounded" type="xs:string" />
<xs:element name="bbb"
type="xs:string"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="c2">
<xs:complexContent>
<xs:restriction base="c1">
<xs:sequence>
<xs:element name="aaa" minOccurs="0"
maxOccurs="unbounded" type="xs:string"/>
<xs:element name="bbb"
type="xs:string"/>
</xs:sequence>
</xs:restriction>
</xs:complexContent>
</xs:complexType>
</xs:schema>
The first xsd
program of this chapter has been replicated here with a few modifications. The
value of the minOccurs attribute in type c1 has been changed from 0 to 1, thus
mandating at least one occurrence of this type in the file.
On similar lines,
the type c2, which extends from type c1, is assigned a minOccurs value of 0.
This triggers off an error, because the element has been made less restrictive,
rather than being made more restrictive. The exception that is generated is the
same as the one witnessed in the previous program.
Modify the type
c1 to the following:
<xs:element name="aaa" minOccurs="0"
maxOccurs="unbounded" type="xs:string" fixed="hi"
/>
An error erupts
because the element aaa in the type c1, has been assigned a fixed value of
'hi'. Now, modify the statement in type c2 to the following:
<xs:element name="aaa" minOccurs="1"
maxOccurs="unbounded" type="xs:string"
fixed="hi1"/>
In the type c2,
the fixed attribute is added to the element aaa, and a value of 'hi' is
assigned to it. Nevertheless, this is not sufficient, since a value of 'hi'
must be specified in the xml file to get rid of the error.
On changing the
value of the fixed attribute to 'hi1', which is different from the value
assigned to the element aaa, the same particle error gets reported. Thus to
summarize, when we create a new type, it should be more restrictive rather than
being less restrictive.
The Redefine
element
b.xsd
<xs:schema
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:redefine schemaLocation="b1.xsd">
</xs:redefine>
<xs:element name="zzz" type="c1" />
</xs:schema>
b1.xsd
<xs:schema
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:complexType name="c1">
<xs:sequence>
<xs:element name="aaa"
type="xs:integer"/>
</xs:sequence>
</xs:complexType>
</xs:schema>
b.xml
<?xml version="1.0"?>
<zzz>
<aaa> 10 </aaa>
</zzz>
The xsd file is
now assigned a new element called 'redefine'. The schemaLocation attribute is
initialized to a different xsd file named b1.xsd. The file b1.xsd has a type
called c1, which contains a simple element called aaa of type string. In the
file b.xsd, the root element zzz is assigned the type c1.
No errors are
visible, despite the fact that the type c1 has been created in another file.
Thus, the 'redefine' element acts analogous to an 'include' or an 'import'
statement. All the types that are present in the schemaLocation file can now be
used in the main xsd file.
In the xml file,
the root element zzz has a child element named aaa. The 'redefine' element
works in a same manner corresponding to an 'include' or an 'import' statement,
which differ from one another only with respect to the namespaces. If this is
the case, then what is the necessity of having another element that behaves in
a similar manner? Read on to unravel the mystery.
b.xsd
<xs:schema
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:redefine schemaLocation="b1.xsd">
<xs:complexType name="c1">
<xs:complexContent>
<xs:extension base="c1">
<xs:sequence>
<xs:element name="bbb"
type="xs:integer"/>
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>
</xs:redefine>
<xs:element name="zzz" type="c1" />
</xs:schema>
b1.xsd
<xs:schema
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:complexType name="c1">
<xs:sequence>
<xs:element name="aaa"
type="xs:integer"/>
</xs:sequence>
</xs:complexType>
</xs:schema>
b.xml
<?xml version="1.0"?>
<zzz>
<aaa> 10 </aaa>
<bbb> 10 </bbb>
</zzz>
This example
illustrates the use of the redefine element. The 'include' or 'import' elements
introduce a truck-load of types which could require some modifications to suit
the requirements. This is attainable by utilizing the redefine element. Thus,
the redefine element allows redefining or altering of the existing types. The
above program demonstrates how this can be achieved.
A type called c1
is created within a complexType element, even though this type is already
present in the file b1.xsd. This newly created type c1 extends from the
original type c1.
Specifying c1 in
the complexType hints at the fact that the existing definition of type c1,
which is present in the file b1.xsd, needs to be changed. In the extension
element, the base refers to the original c1 present in the file b1.xsd, and not
to the type c1 that is being defined. Hence, no circular definition error is
instigated.
The type c1 is
extended with the help of the extension element. Thus, in addition to the
existing element aaa from the original c1, another element bbb is introduced.
The end-result is that the xml file can now have the two elements of aaa and
bbb. In the above program, the redefine
element is used to add an element to a type, which is created in another file.
In file b.xsd,
change the element name bbb to aaa as follows:
<xs:element name="aaa"
type="xs:integer"/>
Also, change the
contents in the file b.XML as follows:
b.xml
<?xml version="1.0"?>
<zzz>
<aaa> 10 </aaa>
<aaa> 20 </aaa>
</zzz>
To our amazement,
no errors meet the eye. This is because, the first element aaa originates from
the original type c1 based in file b1.xsd, while the second comes from the
newly defined type c1, which is defined in file b.xsd. The XML framework is
able to distinguish between the two identically named elements, both named aaa.
But as always, there is a minor caveat.
In the file
b.xsd, change the data type of the element aaa from integer to string as
follows:
<xs:element name="aaa"
type="xs:string"/>
This modification
results in the following exception:
Error
Unhandled Exception: System.Xml.Schema.XmlSchemaException: In
the same scope elements with the same name have to have the same type. An error
occurred at file:///c:/xmlprg/b.xsd(7, 2).
This elucidates
the fact that a file can have multiple elements sharing same name, provided
they have the same data type. Redefining the original aaa of type integer to
the newly added element aaa of type string, leads to the above error.
b.xsd
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:redefine schemaLocation="b1.xsd">
<xs:complexType name="c1">
<xs:complexContent>
<xs:restriction base="c1">
<xs:sequence>
<xs:element name="bbb"
type="xs:integer"/>
</xs:sequence>
</xs:restriction>
</xs:complexContent>
</xs:complexType>
</xs:redefine>
<xs:element name="zzz" type="c1" />
</xs:schema>
Error
Unhandled Exception: System.Xml.Schema.XmlSchemaException:
Invalid particle derivation by restriction. An error occurred at
file:///c:/xmlprg/b.xsd(3, 2).
In the above
program, the 'extension' element is altered to 'restriction'. This generates
the familiar ‘Invalid particle’ error. This exception is expected, since the
basic rules of restriction have been flouted.
A restriction
element can delimit the existing elements, but it cannot permit any additions
to them. The 'redefine' element cannot alter the rules of the other elements.
b.xsd
...
<xs:element name="aaa"
type="xs:integer"/>
...
b.xml
<?xml version="1.0"?>
<zzz>
<aaa> 10 </aaa>
</zzz>
In the xsd file,
the element name is reverted to aaa. Further, the additional element aaa is
removed from the xml file. Now, everything returns back to normal.
The extension and
the restriction elements can be used to redefine the types, provided that the
rules pertaining to them are not tampered with in the least. On replacing the
'redefine' element with the 'include' statement and eliminating the closing
'redefine' element, the following error is encountered:
b.xsd
...
<xs:include schemaLocation="b1.xsd" />
...
Error
Unhandled Exception: System.Xml.Schema.XmlSchemaException:
Unhandled Exception: System.Xml.Schema.XmlSchemaException: The
'http://www.w3.org/2001/XMLSchema:complexType' element is not supported in this
context. An error occurred at file:///c:/xmlprg/b.xsd(3, 2).
The 'import' or
'include' elements cannot be used to redefine the existing types. However, the
'redefine' element can be used as a super-set of either an 'include' or an
'import' element, to either modify or change existing elements.
b.xsd
...
<xs:redefine schemaLocation="b1.xsd" >
<xs:complexType name="c2"/>
....
</xs:redefine>
...
Error
Unhandled Exception: System.Xml.Schema.XmlSchemaException: No
complex type to redefine. An error occurred at file:///c:/xmlprg/b.xsd(3, 2).
The 'redefine'
element redefines an existing type, but it does not create a new one. In the
b1.xsd file, only one type exists, viz. the type c1. The above error emerges
when we attempt at creating a new type c2 using the 'redefine' element.
The 'redefine'
element works in the same way as the 'include' element. Here, the schema being
introduced must either exist in the same namespace as the redefining schema, or
it should not belong to any namespace.
The type c1 in
b1.xsd does not belong to any namespace, since the target namespace is empty.
If the file b.xsd belongs to a namespace, such as abc, then the redefined type
c1 would also fall in the abc namespace.
b.xsd
<xs:schema
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:redefine schemaLocation="b1.xsd">
<xs:complexType name="c1">
<xs:complexContent>
<xs:extension base="c2">
<xs:sequence>
..
..
</xs:sequence>
</xs:extension>
Error
Unhandled Exception: System.Xml.Schema.XmlSchemaException: If
type is being redefined the base type has to be self-rereference. An error
occurred at file:///c:/xmlprg/b.xsd(3, 2).
To redefine an
existing type, the base attribute in the extension or the restriction element
must also have the same type as the type that is being redefined. Redefining c1
with the base as c2 results in an exception. Note the word ‘self-rereference’
in the error message, a mistake committed by the developers at Microsoft.
Thus, by using
redefine, the existent definition has now been annihilated, and only the new
type definition i.e. c1, prevails. There is no means of accessing the old
definition.
Substitution
Groups
b.xsd
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="zzz">
<xs:complexType>
<xs:sequence>
<xs:element ref="aaa"/>
<xs:element ref="bbb"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="aaa"
type="xs:string"/>
<xs:element name="bbb"
type="xs:string"/>
<xs:element name="ccc"
type="xs:string" substitutionGroup="aaa" />
<xs:element
name="ddd" type="xs:string" substitutionGroup
="bbb" />
</xs:schema>
b.xml
<?xml version="1.0"?>
<zzz>
<aaa> 10 </aaa>
<bbb> 10 </bbb>
</zzz>
The above example
has a root element zzz with an anonymous complexType. This type has two string
type elements that refer to elements aaa and bbb, respectively. The elements
aaa and bbb are placed as children to the schema. In the xml file, the zzz
element is followed by the elements aaa and a bbb, in sequence.
b.xml
<?xml version="1.0"?>
<zzz>
<ccc> 10 </ccc>
<bbb> 10 </bbb>
</zzz>
The above xml
file gives no error, even though aaa has been replaced by ccc. This comes about
because the element ccc is provided with a substitutionGroup attribute, which
is initialized to the element aaa. Thus, the aaa element can always be replaced
with ccc. In other words, the element ccc can be used in place of aaa anywhere
in the file.
b.xml
<?xml version="1.0"?>
<zzz>
<ccc> 10 </ccc>
<ddd> 10 </ddd>
</zzz>
Along the same
lines, the ddd element has the attribute of the substitution group initialized
to bbb, as a result of which, the bbb tag can now be replaced with the ddd tag
in the xml file.
b.xml
<?xml version="1.0"?>
<zzz>
<ccc> 10 </ccc>
<ddd> 10 </bbb>
</zzz>
Error
Unhandled Exception: System.Xml.XmlException: The 'ddd' start
tag on line '4' doesn't match the end tag of 'bbb' in file
'file:///c:/xmlprg/b.xml'. Line 4, position 12.
What is not
permitted is the fifty-fifty combination, i.e. element ddd cannot be the
starting tag and the element bbb as the ending tag.
In the above
program, the tag ddd has been used as the starting tag, whereas the tag bbb has
been used as the ending tag. The above exception is bound to occur, since the
creator of the xml file is not expected to use mismatched tags. He/She would
not be aware that a substitution group is being dealt with, and not a normal
tag.
<xs:element name="ccc"
type="xs:integer" substitutionGroup="aaa" />
Error
Unhandled Exception: System.Xml.Schema.XmlSchemaException:
'ccc' cannot be a member of substitution group with head element 'aaa'. An
error occurred at file:///C:/xmlprg/b.xsd(12, 2).
The element aaa
is of a string type. However, while creating the element ccc with the attribute
of substitutionGroup initialized to aaa, the type is altered to integer. If an
element is substituted for another, then both, the original and the substitute
elements must have the same features, or else an error will result.
b.xsd
<xs:schema
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="zzz">
<xs:complexType>
<xs:sequence>
<xs:element ref="aaa"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="aaa">
<xs:simpleType>
<xs:restriction base="xs:integer">
<xs:maxExclusive value="100"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
<xs:element
name="ccc" type="xs:integer"
substitutionGroup="aaa" />
</xs:schema>
Error
Unhandled Exception: System.Xml.Schema.XmlSchemaException:
'ccc' cannot be a member of substitution group with head element 'aaa'. An
error occurred at file:///C:/xmlprg/b.xsd(12, 2).
In the above
example, the element aaa is of simpleType and the base type is integer. It uses
the restriction element to limit the range of the values to 100.
The above error
occurs when we attempt to make the element ccc as part of the aaa group. Thus, only simple elements can be
substituted by other elements.
b.xsd
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="zzz">
<xs:complexType>
<xs:sequence>
<xs:element name="aaa" type="xs:integer"
/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element
name="ccc" type="xs:integer"
substitutionGroup="aaa" />
</xs:schema>
Error
Unhandled Exception: System.Xml.Schema.XmlSchemaException:
Reference to undeclared substitution group affiliation. An error occurred at
file:///c:/xmlprg/b.xsd(9, 2).
Earlier, we had
succinctly mentioned that the element name that is used in the substitutionGroup,
must necessarily be a global one. In the above case, the element aaa is a local
element, but it is part of the complexType element. Thus, the local elements
can use the 'ref' attribute to refer to the global elements.
b.xsd
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="zzz">
<xs:complexType>
<xs:sequence maxOccurs="unbounded">
<xs:element ref="aaa"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="aaa"
type="xs:string"/>
<xs:element
name="bbb" type="xs:string"
substitutionGroup="aaa" />
<xs:element
name="ccc" type="xs:string"
substitutionGroup="aaa" />
</xs:schema>
b.xml
<?xml version="1.0"?>
<zzz>
<aaa> 10 </aaa>
<bbb> 10 </bbb>
<ccc> 10 </ccc>
</zzz>
In the above
example, the sequence has the maxOccurs attribute set to 'unbounded'. Thus, its
contents can occur as many times as desired.
The sequence
contains an element that refers to the element aaa, which is of type string.
Besides the element aaa, which is declared to be of type string, there are two
more elements, viz. bbb and ccc. Both these elements use the substitutionGroup
attribute with the value of aaa. Thus, they can replace the element aaa in the
xml file.
The xml file has
the three elements aaa, bbb and ccc, placed in a sequence. Since the elements
bbb and ccc can replace aaa, no errors are displayed.
b.xsd
<xs:schema
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="zzz">
<xs:complexType>
<xs:sequence maxOccurs="unbounded">
<xs:element ref="bbb"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="aaa"
type="xs:string"/>
<xs:element
name="bbb" type="xs:string"
substitutionGroup="aaa" />
</xs:schema>
b.xml
<?xml version="1.0"?>
<zzz>
<bbb> 10 </bbb>
<aaa> 10 </aaa>
</zzz>
Error
Element 'zzz' has invalid child element 'aaa'. Expected
'bbb'. An error occurred at file:///c:/xmlprg/b.xml(4, 2).
The substitution
group allows the use of the element bbb as the 'ref' value for an element.
However, the reverse is not permitted. The element aaa can be replaced by bbb,
but vice-versa is not permissible.
b.xsd
..
<xs:element
name="aaa" type="xs:string"
substitutionGroup="bbb"/>
...
Error
Unhandled Exception: System.Xml.Schema.XmlSchemaException:
Circular substitution group affiliation. An error occurred at
file:///c:/xmlprg/b.xsd(10, 2).
In the xsd file,
the element aaa constitutes a part of the substitutionGroup bbb. Even though
the element aaa has not been referred to anywhere in the file, an exception
shows up. This is because the XML framework detects certain circular
references, which are not acceptable in the least.
The main intent
here is to have the element aaa replace the element bbb, and vice-versa.
However, in XML, circular references are totally debarred.
b.xsd
<xs:schema
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="zzz">
<xs:complexType>
<xs:sequence maxOccurs="unbounded">
<xs:element ref="aaa"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="aaa" type="c1"/>
<xs:element name="bbb" type="c2"
substitutionGroup="aaa"/>
<xs:complexType name="c1">
<xs:sequence>
<xs:element name="ccc"
type="xs:string"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="c2">
<xs:complexContent>
<xs:extension base="c1">
<xs:sequence>
<xs:element name="ddd"
type="xs:string"/>
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>
</xs:schema>
b.xml
<?xml version="1.0"?>
<zzz>
<aaa>
<ccc />
</aaa>
<bbb>
<ccc />
<ddd />
</bbb>
</zzz>
The above example
works in an accomplished manner, since the root element zzz has an element that
refers to the element aaa. This element aaa has a type c1, which holds only the
element ccc. This represents one of the simplest types that can ever be
created. Thereafter, we encounter an element bbb of type c2, and a substitution
group that points to aaa.
No error shows up
when the type c2 derives from the type c1, and when it uses the extension
mechanism to add the element ddd to the type c2. Thus, the type c1 contains
only a single element ccc, whereas the type c2 has the two elements ccc and
ddd.
In the xml file,
the element aaa has one child element ccc. Then, since the element bbb can
replace the element aaa, the element bbb is specified with its two constituent
elements of ccc and ddd.
b.xml
<?xml version="1.0"?>
<zzz>
<aaa>
<ccc />
<ddd />
</aaa>
</zzz>
Error
Element 'aaa' has invalid child element 'ddd'. An error
occurred at file:///C:/xmlprg/b.xml(5, 2).
The 'ddd' element is not declared. An error occurred at
file:///C:/xmlprg/b.xml(5, 2).
The above error
emanates from the fact that the element aaa cannot have a child element ddd.
The element bbb can replace aaa, which in turn can enclose the tag ddd. Thus,
using the substitutable element, we can place multiple child elements within
the tag.
In XML parlance,
the element that can be replaced is called a 'head element'. Thus, substitution
allows one element to replace another.
b.xsd
<xs:schema
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="color"
type="xs:string"/>
<xs:element name="colour"
substitutionGroup="color" type="xs:string"/>
<xs:complexType name="c1">
<xs:sequence>
<xs:element ref="color"/>
</xs:sequence>
</xs:complexType>
<xs:element name="american" type="c1"
/>
<xs:element name="british"
substitutionGroup="american" />
</xs:schema>
b.xml
<?xml version="1.0"?>
<american>
<color/>
</american>
b.xml
<?xml version="1.0"?>
<british>
<colour/>
</british>
b.xml
<?xml version="1.0"?>
<british>
<color/>
</british>
Using the
substitution group, applications that cater to a wider audience, can be
created. For instance, the Americans spell the word colour as 'color', whereas
the British spell it as 'colour'.
To accommodate
both these spellings, we firstly create two global elements named 'color' and
'colour'. We make the element color as the group for the element of colour. As
mentioned earlier, only global elements can be used in a substitutionGroup.
Then, a type c1
is created, which has an element that references color. Here, colour can also
be used in place of color, because of the substitution group. The root element
is specified as american having the type c1, so that it encloses both 'color'
and 'colour' as its child elements.
Finally, one more
global element called british is created. It has the same substitution group as
american. Thus, now american and british are uniformly applicable in all
circumstances.
Three XML files
with different permutations and combinations have been stipulated above, though
there could have been more. Thus, more the number of substitution groups, the
larger would be the possible combinations. The applications of the substitution
group are curtailed only by your imagination.
b.xsd
...
<xs:element name="colour"
substitutionGroup="color" />
Since both the
elements of 'colour' belong to the substitution group named color, they have
the same type by default. Hence, the type attribute can be eliminated, as shown
above.
b.xsd
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="zzz">
<xs:complexType>
<xs:sequence>
<xs:element ref="aaa"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="aaa"
type="xs:string"/>
<xs:element
name="bbb" type="xs:string" substitutionGroup="aaa"
/>
<xs:element
name="ccc" type="xs:string"
substitutionGroup="bbb" />
</xs:schema>
b.xml
<?xml version="1.0"?>
<zzz>
<ccc/>
</zzz>
In the above
example, aaa is the head element, and the element bbb is used to substitute it.
Next, the element ccc is used to substitute the element bbb.
Thus, wherever
aaa can be used, bbb can be used too; and wherever bbb can be used, the element
of ccc can be used too. Resultantly, wherever aaa can be used, ccc too can be
used, as is evident in the above xml file.
If you replace
ccc with aaa or bbb in the xml file, no errors will result.
b.xsd
<?xml version="1.0"?>
<xs:schema
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="zzz">
<xs:complexType>
<xs:sequence>
<xs:element ref="aaa"
maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="aaa" abstract="true"
type="xs:string"/>
<xs:element
name="bbb" substitutionGroup="aaa"
type="xs:string"/>
<xs:element name="ccc" substitutionGroup="aaa"
type="xs:string"/>
</xs:schema>
b.xml
<?xml version="1.0"?>
<zzz>
<bbb />
<ccc />
<ccc />
</zzz>
The abstract
attribute used in one of the previous chapters is used here too, with
substitution groups.
The root element
zzz has a child element that refers to aaa. But, this element aaa cannot be
used since the abstract attribute is set to 'true'. Its maxOccurs attribute is
set to 'unbounded' to facilitate the multiple occurrences of the element. Then,
two more global elements named bbb and ccc are created, both of which have
their substitution groups as aaa.
This allows the
replacement of the element aaa with the element bbb or ccc, as many times as
desired as clearly depicted in the xml file. Whenever the abstract property of
an element is set to true, it cannot be used directly, though some other
element can be used in its place.
b.xsd
<xs:schema
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="zzz">
<xs:complexType>
<xs:sequence>
<xs:element name="aaa" type="c2"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:complexType name="c1">
<xs:sequence>
<xs:element name="bbb"
type="xs:string"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="c2">
<xs:complexContent>
<xs:extension base="c1">
<xs:sequence>
<xs:element name="ccc"
type="xs:string"/>
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>
</xs:schema>
b.xml
<?xml version="1.0" ?>
<zzz>
<aaa>
<bbb/>
<ccc/>
</aaa>
</zzz>
In the above
example, the root element zzz contains an element aaa of type c2. This type c2
in turn derives from type c1, which has an element bbb. The type c2 has the
type c1 as its base type. It adds one more element ccc to the type c2. This is
nothing different from what we already know.
Modify the
complexType definition for c1 by adding the attribute 'final' with a value of
'extension' assigned to it.
<xs:complexType name="c1"
final="extension">
On doing so, the
following exception is thrown:
Error
Unhandled Exception: System.Xml.Schema.XmlSchemaException:
Base type is final extension. An error occurred at file:///c:/xmlprg/b.xsd(14,
2).
The 'final'
attribute determines the constraints to be applied to the type while deriving
other types. Since the value assigned
to 'final' is 'extension', the type cannot be used to extend other types. Thus,
no type can now extend from this type.
Change the
attribute value from 'extension' to 'restriction' and rewrite complexType c2 as
follows:
b.xsd
<xs:complexType name="c2">
<xs:complexContent>
<xs:restriction base="c1">
</xs:restriction>
</xs:complexContent>
</xs:complexType>
The restriction
element is used to restrict the entities. However, on modifying the complex
type, the following exception is thrown:
Error
Unhandled Exception: System.Xml.Schema.XmlSchemaException:
Base type is final restriction. An error occurred at
file:///c:/xmlprg/b.xsd(14, 2).
Thus, a type can
be extended or restricted by another type.
<xs:complexType name="c1"
final="#all">:
The #all value
applies to both, extension as well as restriction. And the same error is
reported for both extension and restriction.
<xs:schema
xmlns:xs="http://www.w3.org/2001/XMLSchema"
finalDefault="#all">
In the original
program, add the attribute of finalDefault.
This attribute
has the same functionality as the final attribute. However, 'finalDefault'
works at the element level, whereas
'final' operates on the global level.
The ensuing
effect of the attribute finalDefault on the schema is that, the attribute
final=#all is added to all the elements that can accept such an attribute.
Everything that can be done at a global level, can however be undone at the
element level.
We had briefly
touched upon the 'fixed' attribute earlier with reference to an element. Now,
let us use 'fixed' in the context of derivations and data facets.
b.xsd
<xs:schema
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="zzz">
<xs:complexType>
<xs:sequence>
<xs:element name="aaa" type="c1"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:simpleType name="c1">
<xs:restriction base="xs:string">
<xs:length value="3" fixed="true"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="c2">
<xs:restriction base="c1">
<xs:pattern value="[A-Z]{3}"/>
</xs:restriction>
</xs:simpleType>
</xs:schema>
b.xml
<?xml version="1.0" ?>
<zzz>
<aaa>ABC</aaa>
</zzz>
The above xsd
file has a root element zzz, which has a child element aaa of type c1. This
type is a simple type. It uses restriction to restrict the length to 3. There
is one more type c2, which again is a simpleType and derives from the type c1.
The pattern
restricts the values that the type c2 can handle, upto 3 capital letters only.
We do not use this type at all. In the xml file, since the element aaa contains
3 capital letters, all is hunky-dory.
Modify the type
c2 as follows:
b.xsd
<xs:simpleType name="c2">
<xs:restriction base="c1">
<xs:pattern value="[A-Z]{3}"/>
<xs:length value="3"/>
</xs:restriction>
</xs:simpleType>
Error
Unhandled Exception: System.Xml.Schema.XmlSchemaException:
Base type has {fixed} equal to true. An error occurred at
file:///c:/xmlprg/b.xsd(17, 2).
On adding the
data facet to the simpleType c2, an error occurs. This ensues because in the
type c1, the fixed parameter is assigned the value of 'true', which signifies
that no derived type can change the data facet value. The error occurs despite
the length remaining the same.
A derived type
cannot modify the value of the data facets. It can change all the other data
facets, except the one having the attribute of fixed=true.
b.xsd
<xs:schema
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="zzz">
<xs:complexType>
<xs:sequence>
<xs:element name="aaa" type="c2"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:simpleType name="c1">
<xs:restriction base="xs:string">
<xs:length value="3" fixed="true"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="c2">
<xs:restriction base="c1">
<xs:pattern value="[A-Z]{4}"/>
</xs:restriction>
</xs:simpleType>
</xs:schema>
b.xml
<?xml version="1.0" ?>
<zzz>
<aaa>ABC</aaa>
</zzz>
b.xml
<?xml version="1.0" ?>
<zzz>
<aaa>ABCD</aaa>
</zzz>
Error
The 'aaa' element has an invalid value according to its data
type. An error occurred at file:///c:/xmlprg/b.xml(3, 12).
The glitch with
the XML Schema world is that it does not perform any error checks for
inconsistency.
In the above
example, the element is derived from the type c2, which in turn restricts the
type c1. In the type c1, the length is restricted to 3, while in the type c2,
the pattern is restricted to four capital letters. Both these conditions need
to be satisfied simultaneously.
Since both these
conditions cannot be true concurrently, the above two XML files generate
errors. This is because, each of them satisfy only one condition at a time.
The XML Schema
world does not validate such logically inconsistent behaviour.
b.xsd
<xs:schema
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="zzz">
<xs:complexType>
<xs:sequence>
<xs:element name="aaa" type="c1" />
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:complexType name="c1" >
<xs:sequence>
<xs:element name="bbb"
type="xs:string"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="c2">
<xs:complexContent>
<xs:extension base="c1">
<xs:sequence>
<xs:element name="ccc"
type="xs:string"/>
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>
</xs:schema>
b.xml
<?xml version="1.0"?>
<zzz
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<aaa xsi:type="c2">
<bbb />
<ccc />
</aaa>
</zzz>
In the above xsd
file, the root element zzz has a child element aaa of type c1, which in turn
has an element bbb. Moreover, there exists a complexType c2 that extends the
type c1 and the element ccc.
In the xml file,
the xsi:type is used to change the type of aaa from c1 to c2. If the above
program does not appear comprehensible and logical to you, please refer to the
programs explained earlier. The pertinent question at this stage is - How do we
prevent the XML user from changing the type c1 to the type c2 at runtime, or at
the time of creating the xml file?
Error
Element 'aaa' has xsi:type derivation blocked. An error
occurred at file:///c:/xmlprg/b.xml(3, 2).
The 'aaa' element is not declared. An error occurred at
file:///c:/xmlprg/b.xml(3, 2).
This can be
achieved by adding the attribute block=extension in the xsd file. This ensures
that the xsi:type feature is blocked in the xml file. Thus, the user is
forbidden from changing the run time type of the element. Every feature offered by the XML world can
be 'blocked', by implementing the blocking facility.
The xsi:type can
also be initialized to the derived type.
Changing the
above line to
<xs:complexType
name="c1" block="restriction">
generates no errors, since the block applies
to 'restriction' only. The #all blocks the usage of both, the extension as well
as the restriction in a type.
<xs:complexType name="c2"
block="extension">
On eliminating
the block attribute from the type c1 and assigning it to the type c2, no errors
are reported. This is because the block attribute does not work with
retrospective effect. An exception would have occured in the xml file, had we
created an element with the type of c2 and then, extended the type c3 from the
type c2, followed by a change in the type to c3.
<xs:schema
xmlns:xs="http://www.w3.org/2001/XMLSchema"
blockDefault="extension">
In the XML world,
there exists an attribute called blockDefault at the schema level. Initializing
this attribute to 'all' is akin to setting the block attribute individually for
all elements, wherever it is applicable.
b.xsd
<xs:schema
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="zzz" type="c2" />
<xs:complexType name="c1">
<xs:sequence>
<xs:element name="aaa" type="xs:string"
minOccurs="0"/>
<xs:element name="bbb"
type="xs:string"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="c2">
<xs:complexContent>
<xs:restriction base="c1">
<xs:sequence>
<xs:element name="bbb" type="xs:string"/>
</xs:sequence>
</xs:restriction>
</xs:complexContent>
</xs:complexType>
</xs:schema>
b.xml
<?xml version="1.0"?>
<zzz>
<bbb/>
</zzz>
When the
restriction clause is used, it must be implemented for all the elements that
are present in the base type. In the above example, even though the aaa element
is not repeated, all goes well. This happens because the attribute minOccurs
has a value of 0 by default.
Thus, it does not
have to occur in the base type c1. The default elements do not require to be placed
in the derived type.
<xs:element name="aaa"
type="xs:string"/>
Removal of the
minOccurs attribute from the element aaa, as shown above, results in the
particle error.
<xs:element name="aaa" type="xs:string"
minOccurs="0" maxOccurs="0"/>
If the elements
are disabled, i.e. if the minOccurs and maxOccurs are both assigned a value of
0, then they still have to appear in the type c2, using the restriction
mechanism.
b.xsd
<xs:complexType name="c2">
<xs:complexContent>
<xs:restriction base="c1">
<xs:sequence>
<xs:element name="aaa"
type="xs:string"/>
<xs:element name="bbb"
type="xs:string"/>
</xs:sequence>
</xs:restriction>
</xs:complexContent>
</xs:complexType>
However,
introducing the element aaa in type c2, as seen above, displays the same old
particle error. Thus, nobody can ever use an element whose minOccurs and
maxOccurs, both have a value of 0. In the world of restriction, each and every
element that is present in the base type, must be repeated in the derived type
also, whether we like it or not.
At this juncture,
let us clear the air with regard to declarations and definitions. A declaration
is used for creating elements and attributes. These declarations are visible in
the xml file or in the instance document. Whatever does not find a place in the
instance document is called a definition.
Thus, simple
types, complex types, attribute groups, et al, that are not present in the
instance document, fall in the realm of definitions. In our book, both these
terms have been used interchangeably.