3.
Attributes
The behaviour of
the elements can be changed depending on the values assigned to the attributes.
Unlike an element, an attribute may or may not occur. But when the attributes
are present, they rule the existence of the element. For instance, an element
can occur in an xml file, provided the value of the attribute minOccurs is 1 or
more. By default, both minOccurs and maxOccurs have a value of 1. Therefore,
they can be utilized only once.
This chapter
looks at the different attributes that can be assigned to the elements in the
xsd file and how they affect each of them.
b.xml
<?xml version="1.0"?>
<zzz aa="hi"/>
b.xsd
<?xml version="1.0" encoding="utf-8"?>
<xs:schema
xmlns:xs="http://www.w3.org/2001/XMLSchema" >
<xs:element name="ppp">
<xs:complexType >
<xs:attribute name="aa">
<xs:simpleType>
<xs:restriction base="xs:integer">
</xs:restriction>
</xs:simpleType>
</xs:attribute>
</xs:complexType>
</xs:element>
<xs:element name="zzz">
<xs:complexType>
<xs:attribute ref="aa" />
</xs:complexType>
</xs:element>
</xs:schema>
a.cs
using System;
using System.Xml;
using System.Xml.Schema;
public class zzz
{
public static void Main()
{
XmlTextReader r = new XmlTextReader("b.xml");
XmlValidatingReader v = new XmlValidatingReader(r);
v.ValidationType = ValidationType.Schema;
XmlSchemaCollection c;
c = v.Schemas;
c.Add(null, "b.xsd");
v.ValidationEventHandler += new ValidationEventHandler(abc);
while(v.Read()) ;
}
public static void abc(object s, ValidationEventArgs a)
{
Console.WriteLine(a.Message);
}
}
Error
Unhandled Exception: System.Xml.Schema.XmlSchemaException:
The 'aa' attribute is not declared. An error occurred at
file:///c:/xmlprg/b.xsd(15, 2).
In the xsd file,
element ppp propels forward with a complex type, which has an attribute called
aa located within it. Since it is sited within the element ppp, it can only be
referenced by elements within ppp. An attempt to access it from within the element
zzz generates an exception, as shown above. If the attribute is made global, as
is seen in the earlier examples, then it can be accessed from zzz too.
We would
recommend that the attributes of minOccurs and maxOccurs should be initialized
when the frequency of occurrence is being decided. The syntax for specifying
the frequency of attributes is at great variance from that of the elements.
The program a.cs
has been reproduced here. This program displays the error messages if any while
validating the xml file with the schema definition.
b.xsd
<?xml version="1.0" encoding="utf-8"?>
<xs:schema
xmlns:xs="http://www.w3.org/2001/XMLSchema" >
<xs:element name="zzz">
<xs:complexType>
<xs:attribute name="aa" type="xs:string"
/>
</xs:complexType>
</xs:element>
</xs:schema>
b.xml
<?xml version="1.0"?>
<zzz />
The above example
does not display any error because by default, the use of the attribute is
optional. Thus, it is at the discretion of the coder to either insert an
attribute aa with the element zzz, or to desist from doing so.
Modify the
attribute line in the xsd file to the following:
b.xsd
....
<xs:attribute name="aa" type="xs:string"
use="prohibited"/>
b.xml
<?xml version="1.0"?>
<zzz aa="hi"/>
Error
The 'aa' attribute is not allowed. An error occurred at
file:///c:/xmlprg/b.xml(2, 6).
The 'use'
attribute assumes one of the three different values. The first such value is
'prohibited'. It forbids the presence of the attribute definition, as notified
by the error message.
Thus, if an
attribute is created, and for some reason, it is not required, it can be marked
as 'prohibited'.
b.xsd
...
<xs:attribute name="aa" type="xs:string"
use="optional"/>
By default, the
'use' attribute has the value of 'optional'. Thus, in the above xsd file, it is
redundant to assign the value of 'optional' to the 'use' attribute. The
'optional' value leaves the discretion to the user to implement the attribute
with the element.
On numerous
occasions, the attribute is not implemented. In such cases, the element must
have a default value. This feature is implemented by assigning a value to the
default attribute. The default attribute can be assigned a value only when its
use is optional.
b.xsd
...
<xs:attribute name="aa" type="xs:string"
default="sonal"/>
b.xsd
...
<xs:attribute name="aa" type="xs:string"
use="required" />
The required
clause mandates the use of the attribute. Besides, if the 'value' attribute is
present together with it, then the attribute that is present must have the
value contained in the 'value' attribute. The attribute can be assigned a value
if the 'value' attribute is not used.
An attribute
coalesces a name and a type. The type definition for the type can either be a
simple type or a built-in data type. The types can be present either with a
global scope or can be located within complex types.
b.xsd
<?xml version="1.0" encoding="utf-8"?>
<xs:schema
xmlns:xs="http://www.w3.org/2001/XMLSchema" >
<xs:element name="zzz">
<xs:complexType>
<xs:attribute name="aa" type="xs:integer"
/>
</xs:complexType>
</xs:element>
</xs:schema>
b.xml
<?xml version="1.0"?>
<zzz aa="10 23 45"/>
Error
The 'aa' attribute has an invalid value according to its data
type. An error occurred at file:///c:/xmlprg/b.xml(2, 6).
The above xml
file contains the values 10 23 45. These values do not match the data type
integer, since an integer is made up of only a single number.
b.xsd
<?xml version="1.0" encoding="utf-8"?>
<xs:schema
xmlns:xs="http://www.w3.org/2001/XMLSchema" >
<xs:element name="zzz">
<xs:complexType>
<xs:attribute name="aa">
<xs:simpleType>
<xs:list itemType="xs:integer"/>
</xs:simpleType>
</xs:attribute>
</xs:complexType>
</xs:element>
</xs:schema>
In the above
example, the attribute tag does not terminate on the same line. Instead, it has
a simpleType following it. Within this element, a list element is specified,
with the itemType attribute pointing to a datatype.
The example
justifies that attribute 'aa' can now embody a list of integer values. Thus,
the list created in the xml file can contain integers such as 10, 23 and 45.
This attribute can either have a built-in type or a simpleType created
elsewhere.
b.xsd
<?xml version="1.0" encoding="utf-8"?>
<xs:schema
xmlns:xs="http://www.w3.org/2001/XMLSchema" >
<xs:simpleType name="ttt">
<xs:restriction base="xs:integer">
<xs:maxInclusive value="1000"/>
</xs:restriction>
</xs:simpleType>
<xs:element name="zzz">
<xs:complexType>
<xs:attribute name="aa">
<xs:simpleType>
<xs:list itemType="ttt"/>
</xs:simpleType>
</xs:attribute>
</xs:complexType>
</xs:element>
</xs:schema>
b.xml
<?xml version="1.0"?>
<zzz aa="10 23 45"/>
Here, the
itemType attribute is not an integer but a user defined simpleType ttt. This
type permits integer values that lie within the upper limit of 1000.
Note that the
type is specified as ttt and not as xs:ttt, since the xs namespace does not
contain the type ttt.
b.xml
<?xml version="1.0"?>
<zzz aa="1100 23 45"/>
Error
The 'aa' attribute has an invalid value according to its data
type. An error occurred at file:///c:/xmlprg/b.xml(2, 6).
The above xml
file spawns the following error since the first value is larger than 1000.
These error checks can be incorporated with effortless ease.
b.xsd
<?xml version="1.0" encoding="utf-8"?>
<xs:schema
xmlns:xs="http://www.w3.org/2001/XMLSchema" >
<xs:element name="zzz">
<xs:complexType>
<xs:attribute name="aa">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:enumeration value="b1"/>
<xs:enumeration value="b2"/>
<xs:enumeration value="b3"/>
</xs:restriction>
</xs:simpleType>
</xs:attribute>
</xs:complexType>
</xs:element>
</xs:schema>
b.xml
<?xml version="1.0"?>
<zzz aa="b3"/>
While stipulating
the value of an element or an attribute, we may wish to restrict the choice to
just a couple of options. The enumeration element helps us in achieving this.
The xsd file has
three enumerations, each containing three different values of b1, b2 and b3,
which can be assigned to the attribute aa. This element has to be placed within
the 'restriction' element since the base data type can be specified along with
such an element. Also, the restriction falls within the category of a
simpleType element.
This is yet
another way of regulating the data that the type can represent.
b.xml
<?xml version="1.0"?>
<zzz aa="b4"/>
Error
The 'aa' attribute has an invalid value according to its data
type. An error occurred at file:///c:/xmlprg/b.xml(2, 6).
The above xml
file spews forth the following error because the valid or acceptable values are
b1, b2 or b3, whereas the string b4 does not fall within this range of
acceptable values for the attribute aa.
This facet cannot
confine the data carried by the boolean data type. But, the various values
assigned to the multiple enumeration types must be unique, or else an error
emanates.
b.xsd
<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
>
<xs:element name="zzz">
<xs:complexType>
<xs:attribute name="aa">
<xs:simpleType>
<xs:union memberTypes="bb cc" />
</xs:simpleType>
</xs:attribute></xs:complexType>
</xs:element>
<xs:simpleType name="bb">
<xs:restriction base="xs:integer">
<xs:maxInclusive value="100"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="cc">
<xs:restriction base="xs:string">
<xs:enumeration value="b1"/>
<xs:enumeration value="b2"/>
<xs:enumeration value="b3"/>
</xs:restriction>
</xs:simpleType>
</xs:schema>
The above program
demonstrates how a range of values can be used for an attribute. Thus, either a
number less than 100, or the words b1, b2 or b3 can be entered.
The two XML files
given below satisfy all the conditions.
b.xml
<?xml version="1.0"?>
<zzz aa="12"/>
The integer value
is less than 100.
b.xml
<?xml version="1.0"?>
<zzz aa="b2"/>
The value has to
be either b1, or b2 or b3.
b.xml
<?xml version="1.0"?>
<zzz aa="1200"/>
This xml file
fails the test, since the value is greater than 100, and hence, it is out of
the range.
b.xml
<?xml version="1.0"?>
<zzz aa="b4"/>
The value of b4
does not fit the bill either.
b.xml
<?xml version="1.0"?>
<zzz aa="12 b4"/>
The value assigned
to the attribute may either be less than 100, or may be any one of the values
b1, b2 or b3. It cannot have two values assigned to it.
Now, let us
unravel the xsd file. Within the simpleType, a new element called 'union' has
been employed :
<xs:union memberTypes="bb cc" />
A union is like marriage. My wife and me, are
two separate entities, but have a common bond of love.
The memberTypes
attribute specifies the list of types that the attribute can contain. In our
case, the value of the attribute can emanate either from the type bb or the
type cc, but not from both. Thereafter,
the simpleType, bb and cc are defined in the file, as specified earlier.
Thus, a union is
a compilation of values from a data source. It forms a catalogue of all the
values that the individual data types can possess. Using a built-in type, such
as a string, would defeat the very purpose of having such a structure, since
any string value can then be used.
b.xsd
<?xml version="1.0" encoding="utf-8"?>
<xs:schema
xmlns:xs="http://www.w3.org/2001/XMLSchema" >
<xs:element name="zzz">
<xs:complexType>
<xs:attribute name="aa">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:pattern value="[A-Z]{2}-[0-9]"/>
</xs:restriction>
</xs:simpleType>
</xs:attribute>
</xs:complexType>
</xs:element>
</xs:schema>
b.xml
<?xml version="1.0"?>
<zzz aa="AB-5"/>
There are myriad
features that can be used to assign values to attributes. The one used in the
above example is called a 'pattern'. This facet has a value attribute and is
passed a regular expression.
A regular
expression consists of queer looking characters, which specify in a generic
terms, as to what the user can key in. Because of the above pattern, the
attribute aa can only have values consisting of two capital letters of the
alphabet, followed by a minus sign, and finally followed by a single numeric
digit. This is a tall order indeed.
Now. Let us
examine the regular expression "[A-Z]{2}-[0-9]".
The syntax [A-Z]
symbolizes a capital letter between A and Z. The number 2 within the curly
braces {2} signifies 2 occurrences of the previous kind, thus representing 2
capital letters. Symbols such as - have no special significance and are taken
at face value. Finally, the expression ends with a single digit ranging between
0 and 9, represented by [0-9].
People have
written volumes on 'regular expressions'. We have also done so in one of our earlier
books. This explains our reluctance to expound the whole concept all over
again.
The core logic
here is that whenever a value has to match a specific pattern, a regular
expression is used. Thus, it becomes much easier to verify the user's inputs, such
as a valid E-Mail address. Some examples of invalid values for the attribute aa
are:
- AB2 The
minus sign is missing.
- AB-
There is no ending digit.
- aB-3 The
small letter 'a' has been used in lieu
of the capital letter
'A'.
b.xsd
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:pattern value="[A-Z]{2}-[0-9]"/>
<xs:pattern value="[a-z]{2}"/>
</xs:restriction>
</xs:simpleType>
b.xml
<?xml version="1.0"?>
<zzz aa="AB-5"/>
b.xml
<?xml version="1.0"?>
<zzz aa="ab"/>
Both xml files
sail through smoothly since two pattern elements are provided to the
simpleType. No limit has been stipulated for it. As a result, as many elements
as deemed necessary can be provided to the restriction element. The first
regular expression is maintained as before, whereas the second one, which is
assigned to the second pattern, permits only two lower case characters.
Thus, we may
assign the following to the attribute:
Two capital letters.
A minus sign.
A number or two lower case letters.
In the last case,
any one of the two values is acceptable.
If the facet in
the restriction is the same as above, then it would suffice even if one of them
matches.
b.xsd
<xs:restriction base="xs:string">
<xs:pattern value="[A-Z]{2}-[0-9]|[a-z]{2}"/>
</xs:restriction>
The above pattern
element has the same effect as the earlier one. The OR sign | allows you to
choose the way you would wish to place values in a single element.
You are rendered
the flexibility of writing your pattern values either on a single line or
spread over multiple lines. The only problem foreseen with the above approach
is that if the 'space' character is used as a separator, then the xml file must
also contain the same space. So, it is preferred not to include any spaces.
The | sign does
not hold any significance for an enumeration. Thus, it cannot be used to
separate the individual values of an enumeration. If we have multiple
enumerator elements, they act like a logical OR.
b.xsd
<?xml version="1.0" encoding="utf-8"?>
<xs:schema
xmlns:xs="http://www.w3.org/2001/XMLSchema" >
<xs:element name="zzz">
<xs:complexType>
<xs:attribute name="aa">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:length value="2"/>
<xs:length value="2"/>
</xs:restriction>
</xs:simpleType>
</xs:attribute>
</xs:complexType>
</xs:element>
</xs:schema>
Error
Unhandled Exception: System.Xml.Schema.XmlSchemaException:
This is a duplicate Length constraining facet. An error occurred at
file:///c:/xmlprg/b.xsd(9, 2).
Facets such as
the enumerator and the pattern cannot be repeated multiple times.
b.xsd
<xs:restriction base="xs:string">
<xs:pattern value="[A-Z]{3}"/>
<xs:length value="2"/>
</xs:restriction>
The above xsd
file generates an error, because barring the pattern and the enumeration, all
the others follow the logical 'and'. All of them must necessary result in a
value of 'true'.
In the above
case, both the conditions have to be true, so that the overall result is also
'true'. However, logically this appears improbable. This is because, the first
condition necessitates the presence of the 3 capital letters, while the second
condition demands that the length should be 2. Both these conditions cannot be
true simultaneously.
b.xsd
<xs:restriction base="xs:string">
<xs:pattern value="[a-z]{2}"/>
<xs:enumeration value="bb"/>
<xs:enumeration value="cc"/>
</xs:restriction>
b.xml
<?xml version="1.0"?>
<zzz aa="bb"/>
An application of
common sense is imperative while using the facets together. The above xml file
works with the xsd file since only one of the enumerations from bb and cc is
permitted. Also, since the pattern permits opting for any two small letters,
both the conditions have been satisfied. Earnestly speaking, there really
exists no requirement for the pattern.
Thus, the thumb
rule is that you may have as many enumerators and patterns as you desire, but
you need to be conservative in your use of other facets, since they are ANDed
with each other.
The XML world is
indifferent towards the logical consistency of your statements.
The simpleType
elements are employed to extend or restrict an already existing built-in type.
Similarly, complexTypes are pressed into action when elements are required.
Both, attributes and content are handled in a similar manner by the simpleType
as well as the complexType. There is no other Type element in the Schema world.
Different
built-in types have diverse number of facets. The string type has six facets,
viz. length, minLength, maxLength, pattern, enumeration and whitespace. The
integer has eight facets, viz. totalDigits, maxInclusive, maxExclusive,
minExclusive, minInclusive, pattern, whitespace and enumeration. The last three
are common with the string type.
Thus, the general
guideline for dealing with the simpleType element is that, it is employed to
restrict a built-in type or a simple type. It hires the different facets to do
so. In the case of simple types, the attributes work in the manner similar to
the one described earlier.
An element can be
followed by either a simple type or a complex type. The restriction element is used to restrict either the range of
values or the number of occurrences.
b.xsd
<?xml version="1.0" encoding="utf-8"?>
<xs:schema
xmlns:xs="http://www.w3.org/2001/XMLSchema" >
<xs:element name="zzz">
<xs:complexType>
<xs:attribute name="aa">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:length value="3"/>
</xs:restriction>
</xs:simpleType>
</xs:attribute>
</xs:complexType>
</xs:element>
</xs:schema>
b.xml
<?xml version="1.0"?>
<zzz aa="ABC"/>
The length
attribute determines the length of the value of the attribute. If the value
entered is 3, then exactly 3 characters can be entered. Thus, aa="AB"
produces an error.
b.xsd
<xs:restriction base="xs:string">
<xs:maxLength value="3"/>
</xs:restriction>
Alternatively,
the maxLength facet determines the maximum number of characters that can be
typed in. Therefore, in the above case, the count of the characters cannot
exceed 3.
However,
aa="ab" or aa="abc" shall not give out any error
whatsoever. But, to assign a value of "abcd" would prove erroneous,
since there are more than 3 characters.
Similarly, the
minLength facet determines the minimum number of characters.
b.xsd
<?xml version="1.0" encoding="utf-8"?>
<xs:schema
xmlns:xs="http://www.w3.org/2001/XMLSchema" >
<xs:element name="zzz">
<xs:complexType>
<xs:attribute
name="aa" type="dd"/>
</xs:complexType>
</xs:element>
<xs:simpleType name="bb">
<xs:restriction base="xs:string">
<xs:enumeration value="b1"/>
<xs:enumeration value="b2"/>
<xs:enumeration value="b3"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="cc">
<xs:list itemType="bb"/>
</xs:simpleType>
<xs:simpleType name="dd">
<xs:restriction base="cc">
<xs:length value="2"/>
</xs:restriction>
</xs:simpleType>
</xs:schema>
b.xml
<?xml version="1.0"?>
<zzz aa="b1 b2"/>
From here on,
life takes a considerably complicated turn. Earlier, we had learnt about a simple
list with multiple values. Then, we progressed on to an enumeration that
rendered the option of choosing one out of the many values. The list did not
impose any restriction on either the data used or the number of selected items.
The above program
illustrates how multiple values can be chosen from a pre-ordained list. Also,
it ensures that only a limited number of values are selected.
The values in the
list are b1, b2 and b3, out of which any two could be selected. The value
"b1 b2 b3" is not permitted, since in this case, all the three
options have been selected. The value ''1 b4'' satisfies only one of the
conditions, i.e. there must be two values present. However, b4 is an invalid
value since it does not belong to the list.
The value of "b1 b2" meets all the requisite conditions.
Hence, no errors are encountered.
Now, let us
unearth as to how the xsd file implements the above complex condition.
The attribute aa
is of type dd, which is a user-defined data type. Thus, the conditions placed
on dd would determine what the user is allowed to key in as the value of the
attribute aa. A type bb is created, which accepts only three values, viz. b1,
b2 and b3, using the familiar enumeration element.
Then, the type cc
is created, which accepts a list with the itemType as bb. Thus, cc can only
accept the three values of b1, b2 and b3. Any element or attribute that is of
type cc can use any of these three values. However, no restriction is imposed
on their length.
Finally, another
type, i.e. dd is created with the restriction element based on cc. The length
facet is added to it, so that the number of occurrences is restricted to two.
In a list, the length attribute corresponds to the number of individual items,
and not to the actual length of its content.
To achieve this
result, three different levels need to be implemented. Firstly, the number of
possibilities is to be restricted. Secondly, the user key should be empowered
to enter multiple values. Thirdly, the number of values that can be selected,
should be restricted.
b.xsd
<?xml version="1.0" encoding="utf-8"?>
<xs:schema
xmlns:xs="http://www.w3.org/2001/XMLSchema" >
<xs:element name="zzz">
<xs:complexType>
<xs:attribute name="aa" type="ee" />
</xs:complexType>
</xs:element>
<xs:simpleType name="bb">
<xs:restriction base="xs:integer">
<xs:maxInclusive value="100"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="cc">
<xs:restriction base="xs:string">
<xs:enumeration value="b1"/>
<xs:enumeration value="b2"/>
<xs:enumeration value="b3"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="dd">
<xs:union memberTypes="bb cc" />
</xs:simpleType>
<xs:simpleType name="ee">
<xs:list itemType="dd" />
</xs:simpleType>
</xs:schema>
b.xml
<?xml version="1.0"?>
<zzz aa="b1 b2"/>
Since the
attribute aa is of the data type ee, it would have the same constraints that
govern ee. The type bb accepts numbers less than 100, while the type cc accepts
the values b1, b2 or b3. The type dd is a union of bb and cc. Resultantly, the
type dd can opt from the list of bb members and cc members.
Since the element
ee can accept only one type, the element list is provided with a type dd, which
obtains its members from the type bb and cc. This list element can then contain
as many values as it desires, so long as it meets the constraint imposed by the
type dd, i.e. the number should be less than 100, or it should be one of the
following - b1, b2 and b3.
b.xml
<?xml version="1.0"?>
<zzz aa="b1 34 b2 b3 28 67"/>
b.xml
<?xml version="1.0"?>
<zzz aa="b1 67"/>
The
abovementioned values of the attribute do not generate any error since the
requisite condition has been met. The data must either follow the rules of type
bb or of type cc.
b.xml
<?xml version="1.0"?>
<zzz aa="b1 67 789"/>
b.xml
<?xml version="1.0"?>
<zzz aa="b11 67 "/>
The above tosses
an error at us. It is because, in the first case, the value 789 is not less
than 100, while in the second case, the value b11 does not belong to the list
of values of b1, b2 and b3.
b.xsd
<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
>
<xs:element name="zzz">
<xs:complexType>
<xs:attribute name="aa" type="ff" />
</xs:complexType>
</xs:element>
<xs:simpleType name="bb">
<xs:restriction base="xs:integer">
<xs:maxInclusive value="100"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="cc">
<xs:restriction base="xs:string">
<xs:enumeration value="b1"/>
<xs:enumeration value="b2"/>
<xs:enumeration value="b3"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="dd">
<xs:list itemType="bb" />
</xs:simpleType>
<xs:simpleType name="ee">
<xs:list itemType="cc" />
</xs:simpleType>
<xs:simpleType name="ff">
<xs:union memberTypes="dd ee" />
</xs:simpleType>
</xs:schema>
Using the XML
schemas, the values that are incorporated within an element or an attribute,
can be made extremely complex.
The above xsd
file is a reverberation of the previous one, where the list is restricted to
values contained exclusively in either the type bb or the type cc.
b.xml
<?xml version="1.0"?>
<zzz aa="b1 b2"/>
b.xml
<?xml version="1.0"?>
<zzz aa="1 2 30"/>
The xml files
mentioned above, do not generate any error, even though multiple items
originate from either the type bb or the type cc.
b.xml
<?xml version="1.0"?>
<zzz aa="1 2 30 b1"/>
Error
The 'aa' attribute has an invalid value according to its data
type. An error occurred at file:///c:/xmlprg/b.xml(2, 6).
When the items
are blended together, the above error is hurled at us.
In the xsd file,
the attribute aa is of type ff. As before, the type bb can have a value less
than 100, and the type cc can have the value b1 or b2 or b3. Now, the type dd
is a list that derives from bb. Here, we may write as many numbers as deemed
necessary, but each of them must be less than 100.
The type ee is
also a list of type cc. Thus, any combination of the values b1, b2 and b3 can
be entered.
Besides the two
list types of dd and ee, another type called ff is created, which is a union of
dd and ee. The union element authorizes selection from one of the two types.
The final outcome
is that, an option exists for the attribute aa to choose from either the list
of dd or ee. Without the union, the list would have had to be selected from
either bb or cc. As per the option available, only one out of these can be
selected at a time, and not both. Duplicate values are also permissible in a
list.
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:union>
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:enumeration value="g1"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:enumeration value="g2"/>
<xs:enumeration value="g3"/>
</xs:restriction>
</xs:simpleType>
</xs:union>
</xs:simpleType>
</xs:schema>
b.xml
<?xml version="1.0"?>
<zzz>
<aaa>g2</aaa>
</zzz>
A union is merely
a collection of types. Apart from using the approach witnessed above for
creating a union, there is yet another alternative that could be resorted to.
This is showcased in the above xsd file. A simple type c1 starts with the union
element, which in turn is constituted of a number of anonymous simpleType
elements.
Each of these
simpleType elements uses enumeration to restrict the string type used as base.
The only flipside of the above method is that the simple types are incapable of
being reused.
By now, you must
have realized that the maxOccurs attribute takes either a value of 'unbounded'
or that of a positive integer. The only way of implementing this attribute is
by using a union. This has been demonstrated below.
b.xsd
<xs:schema
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="zzz">
<xs:complexType>
<xs:attribute name="maxOccurs1" type="c1"
default="1"/>
</xs:complexType>
</xs:element>
<xs:simpleType name="c1">
<xs:union memberTypes="c2
xs:nonNegativeInteger"/>
</xs:simpleType>
<xs:simpleType name="c2">
<xs:restriction base="xs:string">
<xs:enumeration value="unbounded"/>
</xs:restriction>
</xs:simpleType>
</xs:schema>
b.xml
<?xml version="1.0"?>
<zzz maxOccurs1="unbounded" />
b.xml
<?xml version="1.0"?>
<zzz maxOccurs1="5" />
A simpleType c2
is created by deriving from the string type. However, by using enumeration, its
value is limited to a single value, i.e. 'unbounded'. So, the simple type c1 is
provided a single union element, which takes a value from the following two
types: The type c2 and the built-in type nonNegativeInteger.
Thus, in the xml
file, the attribute maxOccurs1 can now assume either the value of 'unbounded'
(similar to the first case), or a positive integer (like in the second case).
If no value has
been specified, it assumes the default value of 1, since this the value of the
default attribute.
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="c3">
<xs:restriction base="xs:positiveInteger">
<xs:maxInclusive value="50"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="c2">
<xs:list itemType="c3"/>
</xs:simpleType>
<xs:simpleType name="c1">
<xs:restriction base="c2">
<xs:length value="3"/>
</xs:restriction>
</xs:simpleType>
</xs:schema>
b.xml
<?xml version="1.0"?>
<zzz>
<aaa>12 34 44</aaa>
</zzz>
The rules imposed
on the attributes do not change with the elements. What is required is a series
of numbers in the form of a list, as the content of element aaa. However, there
is a ceiling placed on the number of items that can be present in the list,
which is three. Moreover, the numbers must be smaller in value than 50.
The most optimum
way of working on programs is by building error-checks in it, one at a time.
Therefore, we
start by creating a simple type c3, which restricts the type positiveInteger to
a value less than 50, using the maxInclusive attribute. Thus, any entity whose
type is c3, must have a positive integer of less than 50. Then, one more simple
type c2 is created, which uses this type c3 as part of the list item. Thus, the
type c2 can have innumerable positive numbers, provided they are less than 50.
The third
condition was that the length should be 3. To achieve this, a new type c1 is
derived from c2 with the facet length. Thus, by deriving new types, the
existing type can be tailored to suit our needs. Finally, this type is used to
restrict the content that can be carried by the element aaa.
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="c3">
<xs:restriction base="xs:positiveInteger">
<xs:maxInclusive value="50"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="c1">
<xs:restriction>
<xs:simpleType>
<xs:list itemType="c3" />
</xs:simpleType>
<xs:length value="3"/>
</xs:restriction>
</xs:simpleType>
</xs:schema>
The old adage
that there are many ways to skin a cat, is very germane to this case too. The
above xsd program achieves the same result as the previous program, albeit in a
slightly different manner. The simple type c3 restricts the value of a positive
number to less than 50, the type c2 is skipped and then, the type c1 is
created.
The 'restriction'
element introduces an anonymous simpleType that has a list initialized to type
c3. After closing the simple type, the 'length' facet is introduced, which
confines the use of numbers to 3. This has been implemented so that the base
and child simpleType cannot be used simultaneously.
Now, carry out a
few changes. Add a simpleType c2 at the end of the xsd file and then, alter the
restriction element in simpleType c1 to the base of c2.
<xs:simpleType name="c1">
<xs:restriction base="c2">
<xs:simpleType name="c2">
<xs:restriction>
<xs:simpleType>
Error
Unhandled Exception: System.Xml.Schema.XmlSchemaException:
Either the base attribute or the simpleType child must be present, but not
both. An error occurred at file:///c:/xmlprg/b.xsd(20, 2).
The error message
provides ample evidence of the fact that the base attribute and a simpleType
child cannot have the same values concurrently.
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="c3" />
<xs:simpleType name="c2">
<xs:list itemType="c3"/>
</xs:simpleType>
</xs:schema>
Error
Unhandled Exception: System.Xml.Schema.XmlSchemaException:
Type 'c3' is not declared or not a simple type. An error occurred at
file:///c:/xmlprg/b.xsd(10, 2).
In this program,
c3 is made as a complexType instead of a simple Type, and it is used in the
list of types provided to the itemType attribute of the list element. The
exception is thrown since C# scans the list of types and seeks only the simple
types or the built-in types, since they are the ones that qualify to be
specified as types.
It is an exercise
in futility to specify a complex Type, since complex types possess much more
information than mere values, as they are capable of containing elements too.
The following
program solves the problem of representing elements as values of a list.
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="c3">
<xs:list itemType="xs:integer"/>
</xs:simpleType>
<xs:simpleType name="c2">
<xs:list itemType="c3"/>
</xs:simpleType>
</xs:schema>
Error
Unhandled Exception: System.Xml.Schema.XmlSchemaException: A
list data type must be derived from an atomic or union data type. An error
occurred at file:///c:/xmlprg/b.xsd(12, 2).
In the above
program, we create a simpleType c3 that contains a list of integers. No
problems are faced here. Then, a simpleType c2 is created, which holds a list
of type c3.
However, an
exception gets generated because c3 is already a list, and by no means can we
specify a list of lists. The concept of a list of lists cannot be implemented
in a clear-cut manner, since it has myriad dimensions to it.
The list can only
contain 5 facets. The facet of 'length', as we had learnt earlier, specifies
the number of items that the list can have in the xml file. This makes the list
very restrictive. Therefore, minLength and maxLength are used to specify the
minimum and maximum length of the list, respectively. This is followed by the
familiar enumeration and pattern, which have already been discussed earlier.
b.xsd
<?xml version="1.0" encoding="utf-8"?>
<xs:schema
xmlns:xs="http://www.w3.org/2001/XMLSchema" >
<xs:element name="zzz">
<xs:complexType>
<xs:attribute name="aa" type="ff" />
</xs:complexType>
</xs:element>
<xs:simpleType name="bb">
<xs:restriction base="cc" />
</xs:simpleType>
<xs:simpleType name="cc">
<xs:restriction base="bb" />
</xs:simpleType>
</xs:schema>
Error
Unhandled Exception: System.Xml.Schema.XmlSchemaException:
Circular type reference. An error occurred at file:///c:/xmlprg/b.xsd(8, 2).
The XML Validator
can never be caught napping on duty! The exception thrown above establishes
this fact. Here, bb is a simple type, which is made up of type cc. The glitch
is that when the type cc is created, it is based on the type bb. This creates a
circular reference, resulting in the above error.
As an aside, had
we used a restriction of the length facet above, we could have also ensured
that the user only entered a specific number of values, ranging between a
minimum and maximum number of values.
b.xsd
<xs:schema
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name = "zzz">
<xs:complexType>
<xs:sequence minOccurs="0"
maxOccurs="unbounded">
<xs:element name = "aaa" type="xs:string"
minOccurs="0" />
</xs:sequence>
<xs:attribute name="aa" type="xs:string"
/>
</xs:complexType>
</xs:element>
</xs:schema>
b.xml
<?xml version="1.0"?>
<zzz aa="hi">
<aaa> 123 </aaa>
</zzz>
We should have
introduced the above program eons ago. This one exhibits the root element zzz
with a tag aaa and an attribute called aa. This is permissible since the
attribute element cannot be placed outside the complexType, as it belongs to
the element called zzz. So far, the attribute and the element have not been
assigned the same name in the xsd file.
Exploiting our
next surge of creativity, we would like to associate the attribute aa with the
element aaa, and not with zzz. Thus, the tag aaa should be written as: <aaa
aa="no" > 123 </aaa>
It is very easy
to create an element aaa that contains a decimal number or an integer as
follows:
<xs:element name="aaa"
type="xs:decimal"/>
As per our
requirement, now an attribute has to be added to this element aaa. However,
simple built-in types cannot have attributes. Only the complex types have the
privilege of possessing them.
Thus, since the
type decimal is a simple built-in type, it cannot acquire attributes. The only
workable solution to this poser is to have a complexType definition, where the
element aaa can be created or placed with the attribute of aa. As a
consequence, the complex type is created, which derives from or is based upon
the simple type decimal.
b.xsd
<xs:schema
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name = "zzz">
<xs:complexType>
<xs:sequence minOccurs="0"
maxOccurs="unbounded">
<xs:element name="aaa">
<xs:complexType>
<xs:simpleContent>
<xs:extension base="xs:decimal">
<xs:attribute name="aa"
type="xs:string"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:element>
<xs:element name="bbb" type="xs:string"
/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
b.xml
<?xml version="1.0"?>
<zzz>
<aaa aa="hi" > 123 </aaa>
<bbb> bye </bbb>
</zzz>
As always, the
root tag zzz is followed by an anonymous type definition, which embodies all
the contents. The sequence element is used to place the various elements
contained within the type in a specific sequence. Presently, there are only two
elements, out of which, aaa is an open tag and the other one named bbb is a
single tag. The element aa defines an anonymous complexType type.
Upto this point,
the complexType element has had one of the following: a choice, a sequence, an
element and an attribute. Here, we use the element simpleContent to signify
that the new type has no elements, but only character data. Since the type is
employed to extend the simple decimal-type, the 'extension' element is used.
The base
attribute specifies the type that is being extended. Thus, it indicates the
data type of the content. In addition to this, the attribute element is also
specified, so that the aaa element can be extended with these attributes. The
element can extend numerous attribute elements and incorporate all the finer
aspects learnt here. The base attribute determines the data type of the content
of the element aaa.
In the case of
elements, we can have sub-elements within sub-elements. All of them can contain
character data, which can be enveloped within the deepest sub-elements too.
The next program
is an enhancement over the previous one. Here, the root element zzz carries the
element aaa, which in turn, carries an element bbb. You may possibly wonder as
to what is the big deal, since we already have considerable experience in
handling such child elements. The innovative twist here is that we now want to
place some content between these tags.
b.xsd
<xs:schema
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="zzz">
<xs:complexType>
<xs:sequence>
<xs:element name="aaa">
<xs:complexType mixed="true">
<xs:sequence>
<xs:element name="bbb"
type="xs:string"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="ccc"
type="xs:string"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
b.xml
<?xml version="1.0"?>
<zzz>
<aaa> hi
<bbb> bye </bbb>
yes
</aaa>
<ccc> no </ccc>
</zzz>
As before, the
root element zzz is provided with a complexType element to hold all the bits
and pieces.
Then, the two
elements of aaa and ccc are placed in a sequence. Since there are no attributes
that qualify this sequence, these elements must be placed one after the other.
To enable the aaa element to hold a bbb element, a complexType element has to
be specified.
The element bbb
is also placed in a sequence. Even though this sequence element accomplishes
nothing, it must be specified, because a complexType has to be followed by
something other than an element.
After all the
element tags have been closed, we converge all our attention to the complexType
for the aaa element, where the key attribute is defined. The mixed attribute
expressly authorizes the content to be mixed.
Thus, the
character data can now appear between child elements. Therefore, words such as
'hi' can now be specified between the aaa tag and its child bbb.
The default value
is 'false'. Thus, removing the mixed=true attribute from the complex type
element leads to the following exception. :
Error
Element 'aaa' has invalid child element '#PCDATA'. Expected
'bbb'. An error occurred at file:///c:/xmlprg/b.xml(3, 6).
b.xml
<ccc> no </ccc>
bad
</zzz>
Adding 'bad' at
the end of the xml file will yield the same error, since the mixed attribute of
the first complexType is set to 'false' by default. If we now change it to
mixed="true", the error vamooses. The mixed attribute is not
inheritable by the inner complexType elements. Thus, on removing the inner
mixed="true" and retaining the outer one, an exception is thrown,
which is attributed to the presence of the character data 'hi' within the
element aaa.
The mixed model
of the XML Schema world is fundamentally different from the mixed model seen in
XML 1.0. The XML Schema world is very stringent about the sequence and the
number of child elements appearing in either the xml file or the instance
document.
However, this
does not hold true of the older world of xml 1.0, where no rules are enforced
on either the sequence or the number of child elements present in the instance
document.
Thus, XML Schemas
have comprehensive error checks unlike xml 1.0, which gives us lot of leeway.
b.xsd
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="zzz">
<xs:complexType>
<xs:sequence>
<xs:element name="aaa">
<xs:complexType>
<xs:attribute name="a1"
type="xs:string"/>
<xs:attribute name="a2"
type="xs:string"/>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
b.xml
<?xml version="1.0"?>
<zzz>
<aaa a1="hi" a2="bye" />
</zzz>
The above xsd
creates an element aaa within the root. It takes two attributes, viz. a1 and
a2, but without any content.
b.xml
<?xml version="1.0"?>
<zzz>
<aaa a1="hi" a2="bye">
hi
</aaa>
</zzz>
Error
Element cannot contain text or whitespace. Content model is
empty. An error occurred at file:///c:/xmlprg/b.xml(3, 23).
Addition of
character data between the element results in the above exception.
The element aaa
has a complex type with merely two attributes, but without any elements. There
can be no sequence after the complexType, since an order cannot be imposed on
attributes.
It is not evident
from the above, whether we are empowered to have any content between the
elements aaa or not. Let us attempt an innovative approach for creating an
element wherein no content is allowed.
b.xsd
<xs:schema
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="zzz">
<xs:complexType>
<xs:sequence>
<xs:element name="aaa">
<xs:complexType>
<xs:complexContent>
<xs:restriction base="xs:anyType">
<xs:attribute name="a1"
type="xs:string"/>
<xs:attribute name="a2"
type="xs:string"/>
</xs:restriction>
</xs:complexContent>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
The xml file
remains unaltered.
The xsd file
commences with the attributes elements immediately after the complexType, but
now, with the element of complexContent. This element can contain either
extensions or restrictions, and it is used on a complexType, which only
contains mixed content or elements. It can either contain a single restriction
or a single extension.
The restriction
element restricts the contents of the complex type to a subset of what is
permissible. The base type anyType shall be explained in the forthcoming
chapters. The complexContent element is one way of restricting or extending the
content model of the complex type that is being declared. No element content is
introduced. Merely two attributes are provided.
It is entirely
upto the user to select between the following two methods: Either have a
complexType element without any simpleContent, or have a complexContent
element, which is another way of acquiring an element withs no content.