5.
Namespaces
The subject of
namespace comes to the fore essentially when the tags created by one user need
to be differentiated from the tags created by another user. This is achieved
austerely by assigning a name to the tags. This name is the namespace prefix,
i.e. the name of the namespace. In the earlier programs, we had come across a
tag called xs:schema. Here, xs is the name of the namespace prefix, and schema
is the tag name.
This topic could
pack an entire chapter by itself, because every entity that is created in the
schema world is always associated with a namespace. This does not hold credence
in the DTD world. Thus, the concept of a namespace is of prime importance,
since it is the solitary means of differentiating between the tags created by
different users. DTDs have no concern with namespaces, since they were invented
much before the concept of namespaces was conceived. The word 'namespace' is
synonymous with 'namespace prefix'. Thus, for all practical purposes, they can
be used interchangeably.
For instance, the
tag xs:schema is vastly at variance with vijay:schema, because the former stems
from the namespace xs, while the latter originates from the namespace vijay.
The xs namespace is present somewhere in this big mighty world, and its precise
location is revealed by the xmlns:xs 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="xs:string"
/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
b.xml
<?xml version="1.0" ?>
<zzz>
<aaa />
</zzz>
The xmlns entity
is a reserved word, which is followed by a colon sign. The name of the
namespace is specified after the colon. The value assigned to the namespace is
known as a Uniform Resource Identifier or URI. It is similar to a URL, though
some dissimilarities do exist between them.
Very often, the
value assigned is http://www.w3.org/2001/XMLSchema . This site contains the
rules that are applicable to this namespace. Technically speaking, this is
merely a convention and not a rule.
If the URI
http://www.w3.org/2001/XMLSchema is designated as the default namespace, as has
been done in the next program, and then, if a tag is specified without a
namespace, it is assumed to belong to the default namespace. Here, the string
need not be prefaced by the namespace prefix, since by default, all tags are
considered to originate from the default namespace, unless stated otherwise.
b.xsd
<schema
xmlns="http://www.w3.org/2001/XMLSchema">
<element name="zzz">
<complexType>
<sequence>
<element name="aaa" type="string"/>
</sequence>
</complexType>
</element>
</schema>
b.xml
<?xml version="1.0" ?>
<zzz >
<aaa />
</zzz>
The above example
has been repeated for the sole purpose of clarifying a few intricate notions.
The root element zzz has a child element aaa. Now, initiate a few changes in
the xsd file as given below.
b.xsd
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="ttt">
<xs:element name="zzz">
<xs:complexType>
<xs:sequence>
<xs:element name="aaa" type="xs:string"
/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
When the
attribute targetNamespace is assigned a value of ttt, the following exceptions
get generated:
Error
Could not find schema information for the element 'zzz'. An
error occurred at file:///c:/xmlprg/b.xml(2, 2).
Could not find schema information for the element 'aaa'. An
error occurred at file:///c:/xmlprg/b.xml(3, 2).
The data type of
the targetNamespace is a string that represents a URI reference. This reference
is the namespace that all the schema entities eventually relate to. The errors
occur in the above case because the element zzz now belongs to the namespace
ttt, which has not been implemented in the xml file. Thus, the xml file has to be modified so that the element zzz
originates from the ttt namespace.
b.xml
<?xml version="1.0" ?>
<ttt:zzz >
<aaa />
</ttt:zzz>
Error
Unhandled Exception: System.Xml.XmlException: 'ttt' is an
undeclared namespace.
The first thought
that crosses the mind is that ttt should be used as a prefix for the element
zzz. However, on doing so, an error message is generated, which conveys that it
is oblivious to the location of the ttt namespace. Modify the xml file to
contain the following statements:
b.xml
<?xml version="1.0" ?>
<uuu:zzz xmlns:uuu="ttt">
<aaa />
</uuu:zzz>
The reserved
xmlns namespace is used to point the prefix uuu to the URI ttt. Since the
element zzz belongs to the ttt namespace, we have randomly chosen uuu as the
namespace prefix with the URI of ttt. Now, both the targetNamespace and the uuu
namespace prefix contain the same URI of ttt. Therefore, no errors are
perceived.
The namespace URI
ttt can now be packed with the types created in the xsd file. In order to refer
to these types, the namespace prefix will have to be used to access them. This
is akin to using the namespace xs: while referring to the types present in the
XML Schema namespace. Thus, the same rules that we conform to currently, have
to be observed while referring to the types created in other namespaces.
Everything in the
XML world relates to a namespace. By specifying a namespace with the
targetNamespace attribute, all the types created there on, now belong to the
above namespace. Modify the aaa statement in the xml file to the following:
b.xml
...
<uuu:aaa />
...
Error
Element 'ttt:zzz' has invalid child element 'ttt:aaa'.
Expected 'aaa'. An error occurred at file:///C:/xmlprg/b.xml(3, 2).
The 'ttt:aaa' element is not declared. An error occurred at
file:///C://xmlprg/b.xml(3, 2).
The aaa element
reports an error when it is prefaced with the namespace prefix uuu. Read on
further to lay bare the rationale behind this.
A schema is a
collection of types and elements that belong to the namespace determined by the
targetNamespace attribute. The default value is null. Therefore, in the xml
file, it is possible to use the elements and types created in this schema
without employing any prefix.
Without the
targetNamespace attribute, it would be an arduous task to differentiate between
types that have the same name, but have been created in different schema files.
The
targetNamespace attribute identifies the XML Schema vocabulary to which the
complexType element belongs. It is a very rudimentary task to create our own
complexType element with the targetNamespace attribute set to another target.
This target can
be completely at variance with the complexType created in the xsd namespace.
b.xsd
<schema xmlns="http://www.w3.org/2001/XMLSchema"
xmlns:vvv="http://www.sonal.com/"
targetNamespace="http://www.sonal.com/" elementFormDefault="unqualified"
attributeFormDefault="unqualified">
<element name="zzz" type="vvv:c1"/>
<element name="ddd" type="string"/>
<complexType name="c1">
<sequence>
<element name="bbb" type="vvv:c2"/>
<element ref="vvv:ddd"
minOccurs="0"/>
</sequence>
</complexType>
<complexType name="c2">
<sequence>
<element name="ccc" type="string"/>
</sequence>
</complexType>
</schema>
b.xml
<?xml version="1.0"?>
<uuu:zzz xmlns:uuu="http://www.sonal.com/">
<bbb>
<ccc>Mukhi</ccc>
</bbb>
<uuu:ddd> Ha ha </uuu:ddd>
</uuu:zzz>
In the above
program, the default namespace represents the XML Schema. Hence, the schema and
the other tags need not be prefaced. The namespace prefix vvv points to the URI
http://www.sonal.com.
Thus, elements or
types prefaced by vvv belong to the above URI. The targetNamespace is also
assigned the same URI. As stated earlier, a URI is similar to a URL.
On changing the
vvv attribute to www.sonal1.com, the following exception gets thrown:
Error
Unhandled Exception: System.Xml.Schema.XmlSchemaException:
Type 'http://www.sonal1.com/:c1' is not declared. An error occurred at
file:///c:/xmlprg/b.xsd(4, 2).
The
elementFormDefault and attributeFormDefault are not required since they are set
to their default value of 'unqualified'. As is customary, the document starts
with the root element zzz, having the type c1. This type consists of an element
bbb of type c1, which in turn has the elements ccc and ddd.
The element zzz
refers to the type as vvv:c1 and not as c1, since the type c1 now belongs to
the namespace vvv, which correspondingly points to the URI www.sonal.com. The
element bbb also refers to the type as vvv:c2, and not as c2. The second
element in the complex type refers to the element name ddd as vvv:ddd.
You are requested
to undo the errors prior to implementing the new updates. If we transform the
type of element zzz from vvv:c1 to c1, the following exception gets thrown:
b.xsd
<element name="zzz" type="c1"/>
Error
Unhandled Exception: System.Xml.Schema.XmlSchemaException:
Type 'http://www.w3.org/2001/XMLSchema:c1' is not declared. An error occurred
at file:///c:/xmlprg/b.xsd(4, 2).
This error occurs
because the system expects the type c1 to originate from the XML namespace, but
this is not the way things happen. Remember that xs is the default namespace.
In the xml file,
only the child elements of the schema zzz and ddd are 'qualified'. The others,
such as bbb and ccc, which are part of the complexType c1 and c2, are not
qualified by the namespace prefix. If we do qualify them, as seen in the
example below, an exception gets thrown.
b.xml
<?xml version="1.0"?>
<uuu:zzz xmlns:uuu="http://www.sonal.com/">
<uuu:bbb>
<uuu:ccc>Mukhi</uuu:ccc>
</uuu:bbb>
<uuu:ddd> Ha ha </uuu:ddd>
</uuu:zzz>
Error
Element 'http://www.sonal.com/:zzz' has invalid child element
'http://www.sonal.com/:bbb'. Expected 'bbb'. An error occurred at
file:///C:/xmlprg/b.xml(3, 2).
The 'http://www.sonal.com/:bbb' element is not declared. An
error occurred at file:///C:/xmlprg/b.xml(3, 2).
The 'http://www.sonal.com/:ccc' element is not declared. An
error occurred at file:///C:/xmlprg/b.xml(4, 2).
The error states
that the bbb and ccc elements are not declared. Now, dispose of the uuu prefix
from the elements bbb and ccc, and alter the value of the attribute
elementFormDefault from 'unqualified' to 'qualified'. On doing so, the
following error is generated:
b.xsd
elementFormDefault="qualified"
Error
Element 'http://www.sonal.com/:zzz' has invalid child element
'http://www.sonal.com/:bbb'. Expected 'bbb'. An error occurred at
file:///C:/xmlprg/b.xml(3, 2).
The 'http://www.sonal.com/:bbb' element is not declared. An
error occurred at file:///C:/xmlprg/b.xml(3, 2).
The 'http://www.sonal.com/:ccc' element is not declared. An
error occurred at file:///C:/xmlprg/b.xml(4, 2).
In order to purge
the above error, prefix the elements bbb and ccc with uuu. This is reflected in
the xml file that ensues.
b.xml
<?xml version="1.0"?>
<zzz xmlns="http://www.sonal.com/">
<bbb>
<ccc>Mukhi</ccc>
</bbb>
<ddd> Ha ha </ddd>
</zzz>
In the above xml
file, the attribute elementFormDefault has been set to the value of
"qualified". Therefore, every element has to be prefixed with the
name of the namespace. In order to evade repetition of this action for each and
every element, the default namespace is set to www.sonal.com using the reserved
xmlns attribute.
Thus, the
elementFormDefault is applicable only to the xml file, which employs the
elements, and not to the xsd file. The namespace prefix is obligatory, as in
vvv:c1.
We reiterate that
the attribute can be assigned only one of the two values of 'qualified' or
'unqualified'. The default value is 'unqualified'. If the value of
'unqualified' is employed, then the elements from the target namespace, such as
bbb and ccc, need not be qualified by the namespace prefix.
On the contrary,
the value of 'qualified' makes an imposition that the elements in the xml file
have to be preceded by the namespace prefix. The names of the namespace prefix
are inconsequential, as is amply evident in the xsd file. Here, vvv is used in
the XSD file and uuu is used in the xml file. What is of prime significance is
the URI, which must be identical in both the cases, or else, an exception will
get thrown.
The global
default value of 'qualified' can be modified, using the form attribute in the
element statement.
b.xsd
<element name="bbb" type="vvv:c2"
form="unqualified"/>
Error
Element 'http://www.sonal.com/:zzz' has invalid child element
'http://www.sonal.
com/:bbb'. Expected 'bbb'. An error occurred at
file:///c:/xmlprg/b.xml(3, 2).
The 'http://www.sonal.com/:bbb' element is not declared. An
error occurred at file:///c:/xmlprg/b.xml(3, 2).
The 'http://www.sonal.com/:ccc' element is not declared. An
error occurred at file:///c:/xmlprg/b.xml(4, 2).
For the element
bbb, the value of the attribute form is set to 'unqualified'. This implies that
the name of the element need not be qualified with the namespace prefix. The
solitary means of eschewing the error is by knocking off the uuu prefix. Thus,
any global level activity can be undone at the individual level.
The
attributeFormDefault is to attributes what the elementFormDefault is to
elements.
This attribute
provides a direction or a rule for the xml file or the instance document. The
rule states that if elements from a particular schema are to be used, the
namespace prefix must be specified in the targetNamespace attribute.
Now, let us
revisit some of the finer aspects of namespaces. The fundamental objective of
namespaces is to reference the definitions and declarations that have been
created in disparate namespaces.
In the above
illustration, the elements zzz and ddd are included in the schemas target
namespace, whereas the string, the element and the complexType are not
prefixed, since they belong to the default xs namespace.
The default XML
Schema is termed as the 'schema of schemas'. In both the files, viz xml and
xsd, the namespace prefix is not as crucial as the URI. The URI need not
necessarily point to any physical location. By default, the locally defined
elements in the xsd file, such as bbb and ccc, do not require any namespace
prefix, as we have seen earlier.
The zzz and ddd
elements are global elements. They are created as the schema or as the parent
element. The bbb and ccc elements are created within the complexType element,
and thus, they are its child elements. It is sagacious to create more local
elements, since in their case, the xml file does not need a namespace prefix.
Also, creation of valid xml files becomes a breeze.
Common sense
dictates that the root element should be made global, whereas all others should
be made local, so that only a single prefix becomes essential. Thus, in the
above instance, the ddd element should be made local.
The other
alternative is to make all the elements global and then, declare the default
namespace as the target namespace in the xsd file. This obviates the need for
the namespace prefix. The vital point is that you can either make all the
elements or only a single element global; anything else would impose an
excessive burden on the creator of the xml file.
In the next
example, all the elements have been made global, so that the namespace prefixes
can be completely eluded.
b.xsd
<schema xmlns="http://www.w3.org/2001/XMLSchema"
xmlns:vvv="http://www.sonal.com/"
targetNamespace="http://www.sonal.com/">
<element name="zzz" type="vvv:c1"/>
<element name="ddd" type="string"/>
<element name="ccc" type="string"/>
<element name="bbb" type="vvv:c2"/>
<complexType name="c1">
<sequence>
<element ref="vvv:bbb"/>
<element ref="vvv:ddd" minOccurs="0"/>
</sequence>
</complexType>
<complexType name="c2">
<sequence>
<element ref="vvv:ccc"/>
</sequence>
</complexType>
</schema>
b.xml
<?xml version="1.0"?>
<zzz xmlns="http://www.sonal.com/">
<bbb>
<ccc>Mukhi</ccc>
</bbb>
<ddd> Ha ha </ddd>
</zzz>
The above
instance is free of errors. The default namespace and the vvv prefix remain
unaltered, but the elementFormDefault is eliminated, so that its value remains
as 'unqualified'. Then, a global element zzz is created, which refers to the
type c1 with the namespace prefix. In turn, this type refers to the two global
elements of bbb and ddd.
The element bbb
refers to the type vvv:c2, which in turn refers to the global element ccc. The
point to be noted here is that all the elements are global. Moreover, none of
the elements are created in the complexType. Had this been the case, then all
the elements so created would have become local instead of global; also, the
problems plaguing the namespace prefix would have cropped up here.
The xml file has
a simple default namespace. Hence, all the elements are global. The only
drawback of a global element is that there can be only one instance of such an
element, whereas a local element can have multiple instances. The name of a
local element includes the name of the element that it belongs to.
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:element name="bbb" type="c2" />
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:complexType name="c1">
<xs:sequence>
<xs:element name="ccc" type="xs:string"
/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="c2">
<xs:sequence>
<xs:element name="ccc" type="xs:integer"
/>
</xs:sequence>
</xs:complexType>
</xs:schema>
b.xml
<?xml version="1.0"?>
<zzz>
<aaa>
<ccc>Mukhi</ccc>
</aaa>
<bbb>
<ccc>100</ccc>
</bbb>
</zzz>
In order to
corroborate the above point, the above example has a root element containing
two child elements, viz. aaa of type c1 and bbb of type c2. Both these types
have the same element ccc, but of type string and integer, respectively.
There is no scope
for ambiguity, since these elements belong to different types, and they appear
under different parents viz. aaa and bbb, respectively. Also, there cannot be
two global elements, both named ccc, as there would be no means of distinguishing
one from the other.
b.xsd
<schema xmlns="http://www.w3.org/2001/XMLSchema"
xmlns:vvv="http://www.sonal.com/"
targetNamespace="http://www.sonal.com/"
elementFormDefault="qualified"
attributeFormDefault="unqualified">
<element name="zzz">
<complexType>
<attribute name="a1" type="string"
form="qualified"/>
</complexType>
</element>
</schema>
b.xml
<?xml version="1.0"?>
<zzz xmlns="http://www.sonal.com/"
a1="hi" />
Error
The 'a1' attribute is not declared. An error occurred at
file:///c:/xmlprg/b.xml(2, 36).
Attributes
conduct themselves in a slightly different manner. In the above file, the root
element zzz has an attribute named a1. The targetNamespace is assigned the
value of sonal and the attributeFormDefault is specified as 'unqualified'.
However, in the case of the attribute a1, the form attribute overrides the
value of unqualified, and mandates that the attribute be qualified with the
namespace prefix.
The error occurs
in spite of having the default namespace of www.sonal.com. This occurs because
the xmlns attribute for default namespaces applies only to elements and not to
attributes. As is evident, the element zzz passes through serenely, but the
attribute a1 has to be prefixed with the namespace; in the absence of which, an
error is reported.
b.xml
<?xml version="1.0"?>
<zzz xmlns="http://www.sonal.com/"
xmlns:ttt="http://www.sonal.com/" ttt:a1="hi" />
The error flees
when a namespace prefix ttt pointing to the URI www.sonal.com is created.
Here, the same
rules of local and global apply. The XML-Namespaces specification does not
assign a default namespace for the attributes. Here, neither an explicit nor an
implicit default namespace is applied to the references.
Schema
Definitions across Files
b.xsd
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:include schemaLocation="b1.xsd"/>
<xs:element name="zzz" type="c1"/>
<xs:complexType name="c1">
<xs:sequence>
<xs:element name="aaa" type="c2"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="c3" />
</xs:schema>
b1.xsd
<xs:schema
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:complexType name="c2">
<xs:sequence>
<xs:element name="bbb"
type="xs:string"/>
<xs:element name="ccc"
type="xs:string"/>
</xs:sequence>
</xs:complexType>
</xs:schema>
b.xml
<?xml version="1.0"?>
<zzz>
<aaa>
<bbb />
<ccc />
</aaa>
</zzz>
As always, the
file b.xsd commences with the good old schema element, but without any extra
attributes tagging along with it. Then a pristine element called 'include' is
introduced, wherein the schemaLocation attribute is initialized to b1.xsd,
which is the name of a file. The mission of the 'include' element is to merge
the contents specified in the file with the current schema.
Thus, the
contents of the file b1.xsd can now be accessed in the current schema. The root
element zzz in the file b.xsd is of type c1, which in turn contains an element
aaa of type c2. There is an empty complexType c3, but there is no type named c2
anywhere in the file b.xsd. However, if you look at the file b1.xsd, it
contains a complexType c2, which in turn contains two elements named bbb and
ccc. Hence, the file passes through successfully, without any error.
While
programming, all types are practically placed in a separate file. Then, this
file is simply assigned to the 'include' element in the xsd file, as a result
of which, all the types are made available to the elements in the file.
b1.xsd
<xs:element name="ccc" type="c3"/>
In the b1.xsd
file, change the definition of element ccc by assigning it the type c3 instead
of xs:string. This does not generate any error even though the xsd file does
not contain the type c3. This is because when the system encounters the
'include' element, it simply merges the contents of that file with the current
main schema. However, it does not resolve type references initially.
Thus, all the
types created in b.xsd can be accessed in the file b1.xsd, and vice-versa. We
can have an infinite number of 'include' statements placed sequentially in the
xsd file. But, ensure that they are not placed after the statement 'element
name="zzz"'. Further, they should be located ahead of the
'complexType name="c1"' statement. Nonconformity to these rules would
lead to the following exception:
Exception
Unhandled Exception: System.Xml.Schema.XmlSchemaException:
The include element cannot appear at this location. An error occurred at
file:///c:/xmlprg/b.xsd(3, 2).
Very often, all
the 'include' statements in the xsd file are normally placed at the beginning.
<xs:include schemaLocation="b1.xsd"/>
<xs:include schemaLocation="b1.xsd"/>
Inclusion of the
same file twice does not generate any errors. It appears as though one of them
has simply been ignored. Moreover, even if we specify the name of an xsd file
that does not exist in the schemaLocation, no error is tossed up.
Move the file
b1.xsd to the folder, c:\inetpub\wwwroot. This is the root directory for IIS or
Personal Web Server. On doing so, the statement given below shall execute
flawlessly.
b.xsd
<xs:include
schemaLocation="http://localhost/b1.xsd"/>
b.xsd
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:vvv="sonal" targetNamespace="sonal">
<xs:include schemaLocation="b1.xsd"/>
<xs:element name="zzz" type="vvv:c1"/>
<xs:complexType name="c1">
<xs:sequence>
<xs:element name="aaa" type="vvv:c2"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="c3" />
</xs:schema>
b1.xsd
<xs:schema
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:vvv="sonal" targetNamespace="sonal">
<xs:complexType name="c2">
<xs:sequence>
<xs:element name="bbb"
type="xs:string"/>
<xs:element name="ccc"
type="xs:string"/>
</xs:sequence>
</xs:complexType>
</xs:schema>
b.xml
<?xml version="1.0"?>
<ttt:zzz xmlns:ttt="sonal">
<aaa>
<bbb />
<ccc />
</aaa>
</ttt:zzz>
The file b.xsd
has been modified slightly. Firstly, the target namespace is changed to sonal.
Then, a namespace prefix vvv is created, which points to the URI sonal.
Resultantly, the type c1 now becomes vvv:c1. Also, unlike the earlier example,
there is no default namespace in the file.
The file b1.xsd
remains unaltered, except for the namespace, which now points to sonal.
Although it may be redundant, its presence in the file does not cause any
tribulations. Moreover, since the namespace is vvv, the type c2 is referred to
as vvv:c2 in the file b.xsd.
Since zzz is a
global element in the xsd file, the newly created namespace prefix ttt has to
be attached only to the zzz element in the xml file.
If the
targetNamespace attribute is changed to sonal1 in the schema element within the
b1.xsd file, an exception is generated. This stems from the fact that the
'include' element can include a file only if it originates from the same
namespace.
In a case where
the namespaces are dissimilar; i.e. one is sonal from the file b.xsd, while the
other is sonal1 from the file b1.xsd, the include fails. This happens because
the 'include' statement cannot possibly include anything from a schema that
contains another namespace. To circumvent the above obstacle, the 'import'
statement can be used in place of the 'include' statement. The 'import'
statement is equipped to handle diverse namespaces.
Schemas spread
over multiple files result in ease of maintenance as they restrict access and
also enhance readability. Thus, all type declarations should be placed in their
own files.
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:element name="bbb" type="c1" />
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:complexType name="c1">
<xs:sequence>
<xs:element name="ccc"
type="xs:string"/>
<xs:element name="ddd"
type="xs:string"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="c2">
<xs:complexContent>
<xs:extension base="c1">
<xs:sequence>
<xs:element name="eee" type="xs:string"/>
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>
<xs:complexType name="c3">
<xs:complexContent>
<xs:extension base="c1">
<xs:sequence>
<xs:element name="fff"
type="xs:string"/>
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>
</xs:schema>
b.xml
<?xml version="1.0"?>
<zzz>
<aaa>
<ccc />
<ddd />
</aaa>
<bbb>
<ccc />
<ddd />
</bbb>
</zzz>
This program
indeed is a long drawn out one, but nonetheless, it is interesting and useful.
The root tag zzz
contains two child elements aaa and bbb, both of which have the same user
defined complexType c1. Thus, both aaa and bbb embody identical content that is
contained in the type c1, viz. the elements ccc and ddd.
The complexType
c2 commences with a complexContent element and then, it extends the type c1. It
also appends a fresh element eee to the two existing elements ccc and ddd that
come from the extended type.As a result, the type c2 has three elements, viz.
bbb, ccc and eee.
Following the
same modus operandi, we create a type c3, which also extends from type c1 and
adds an element fff. Thus, the complexType c3 has three elements, viz. ccc, ddd
and fff. For the time being, the types c2 and c3 are not being used at all.
The xml file
contains two child elements aaa and bbb, which correspondingly contain the tags
ccc and ddd. Therefore, no errors are visible. After all, all's well that ends
well!
b.xml
.....
<aaa>
<ccc />
<ddd />
<eee />
</aaa>
...
Error
Element 'aaa' has invalid child element 'eee' . An error
occurred at file:///c:/xmlprg/b.xml(6, 2).
The 'eee' element is not declared. An error occurred at
file:///c:/xmlprg/b.xml(6, 2).
However, adding
the element eee within element aaa in the xml file b.xml, generates the above
error. This is apparent since there is no element named eee in type c1. In
fact, it is present in type c2.
b.xml
<?xml version="1.0"?>
<zzz
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<aaa xsi:type="c2">
<ccc />
<ddd />
<eee />
</aaa>
<bbb xsi:type="c3">
<ccc />
<ddd />
<fff />
</bbb>
</zzz>
The namespace
prefix xsi is added to the xml file, and it points to its URI. Thereafter, in
the element aaa, the type attribute from the xsi namespace is initialized to
the type c2. This act permits the use of element eee in the element aaa.
Similarly, the type attribute in the bbb element is initialized to c3. Thus,
the addition of the fff element springs no error.
You would surely
appreciate that it is easy to dynamically change the run type of the element as
follows:
* From c1 to c2
in the case of element aaa.
* From c1 to c3
in the case of element bbb.
b.xsd
...
<xs:complexType name="c3">
<xs:sequence>
<xs:element name="fff"
type="xs:string"/>
</xs:sequence>
</xs:complexType>
...
Error
Element 'bbb' has xsi:type derivation blocked. An error
occurred at file:///c:/xmlprg/b.xml(8, 2).
On rewriting the
complexType c3 as shown in the preceding program, the above error is reported.
The error lucidly apprizes us that unless the type is 'extended', the use of
xsi:type is forbidden.
To sum it up, an
element can be derived from a certain type c1. Then, in the xml file, its type
can be altered to another type by using the xsi:type attribute. This
modification is possible only if the type that is used extends from the type
c1, from which the element was originally created.
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="ccc"
type="xs:string"/>
<xs:element name="ddd"
type="xs:string"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="c2">
<xs:complexContent>
<xs:extension base="c1">
<xs:sequence>
<xs:element name="eee"
type="xs:string"/>
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>
<xs:complexType name="c3">
<xs:complexContent>
<xs:extension base="c2">
<xs:sequence>
<xs:element name="fff"
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="c3">
<ccc />
<ddd />
<eee />
<fff />
</aaa>
</zzz>
In the above
example, the element aaa has a type of c1, which contains the two elements ccc
and ddd. Then, the type c2 is created, which extends c1 and also encloses the
element eee. In addition to this, another type c3 is created, which now extends
the type c2. The type c3 thus represents four child elements viz. ccc, ddd, eee
and fff.
In the xml file,
the type attribute is initialized to the type c3, and not to c2. No error is
reported since the type c2 in turn extends type c1. Thus indirectly, type c3
extends type c1. This is perfectly valid since the final type is c1.
This feature is
visible where the base type is an Address.
The type contains fields that comprise of addresses. Then, a distinctive
type, enclosing the unique types that extend this base type, can be created for
each country. This is a perfect instance of a base type and a derived type.
The derived type
is utilized either in the xml file or in the instance document, by implementing
the xsi:type attribute.
b.xsd
<xs:schema
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xs1="http://www.w3.org/2001/XMLSchema"
xmlns="http://www.w3.org/2001/XMLSchema">
<xs:element name="zzz" />
</xs:schema>
b.xml
<?xml version="1.0"?>
<zzz />
In the above xsd
file, the xs prefix as well as the xs1 prefix, both point to the same URI.
Further, the default namespace also points to it. Despite considerable
redundancy, no errors are reported.
b.xsd
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xs1="http://www.w3.org/2001/XMLSchema"
xmlns="http://www.w3.org/2001/XMLSchema">
<xsd1:element name="zzz" />
</schema>
Error
Unhandled Exception: System.Xml.XmlException: The 'xs:schema'
start tag on line '1' doesn't match the end tag of 'schema' in file
'file:///c:/xmlprg/b.xsd'. Line 3, position 3.
The use of xs1,
or the absence of a namespace prefix in the xsd file, is legally permissible.
But, commencing the schema element with an xs prefix and ending it without a
prefix is not allowed, even though the default prefix is the XML Schema URI.
Therefore, the above error is reported. The only rationale for this could be
that the XML world is a stickler for rules.
Whenever a
namespace prefix is omitted, the default namespace is referred to. This
signifies that every schema belongs to some namespace or the other.
The
targetNamespace attribute is used to set the value of the default namespace.
b.xsd
<xs:schema
xmlns:xs="http://www.w3.org/2001/XMLSchema"
elementFormDefault="qualified">
<xs:element name="zzz" />
</xs:schema>
b.xml
<?xml version="1.0"?>
<zzz />
No errors are
perceived, even when the attribute elementFormDefault is specified as
'qualified' and the instance document or xml file do not use it. This is
because the targetNamespace has a default value of null, i.e. an empty string.
Rewriting the
above line as depicted in
b.xsd
<xs:schema
xmlns:xs="http://www.w3.org/2001/XMLSchema"
elementFormDefault="qualified" targetNamespace="">
would accomplish
the same result, since the targetNamespace is an empty string. However,
modifying the tagetNamespace to hold a space, as demonstrated in
b.xsd
<xs:schema
xmlns:xs="http://www.w3.org/2001/XMLSchema"
elementFormDefault="qualified" targetNamespace=" ">
throws the
following exception
Error
Unhandled Exception: System.Xml.Schema.XmlSchemaException:
TargetNamespace ' ' is invalid URI. An
error occurred at file:///c:/xmlprg/b.xsd(1, 2).
The XML world
strictly abides by its rules. The specifying of spaces as the value of the URI
generates the above error, because the file does not adhere to the rules
related to the naming of a URI.
In the instance
document, whether the elementFormDefault attribute has been used or not, is
insignificant, since all the elements get validated anyway. This attribute
merely saves us the hassle of qualifying all the elements or just the global
elements.
Let us now cast a
fleeting glance at the virtues and weaknesses of specifying the
elementFormDefault as qualified or unqualified. If the elementFormDefault is
specified as unqualified, then only the global elements have to be qualified in
the instance document. The complexities governing the namespaces in the xsd
file are entirely concealed.
However, problems
arise when changes are made to the schema, such as making the local
declarations as global. In such cases, the instance document, i.e. the xml file
must adapt to these changes. On the other hand, assigning the value of
qualified to the attribute elementFormDefault mandates that all elements in the
instance document must be qualified.
The silver lining
is that the instance document is impervious to any changes made in the local or
global declarations. However, the user gets exposed to the namespace
complexities.
One of the harsh
realities of life is that, there is nothing like a perfect solution. So, it is
left to each individual to decide for himself as to which of the two options of
'qualified' and 'unqualified', is a better bet for the elementFormDefault
attribute.