7.
Program Generated Schemas
In all the
earlier chapters, the XML Schemas had been written manually. This is because we
wanted to experiment with our own permutations and combinations. Now, we shall
use a program,a.cs to create them. The focal point of this chapter is the
creation of the XML Schema files using a program.
a.cs
using System;
using System.Xml.Schema;
class zzz
{
public static void Main()
{
XmlSchema s = new XmlSchema();
s.Write(Console.Out);
}
}
Output
<?xml version="1.0"
encoding="IBM437"?>
<xs:schema
xmlns:xs="http://www.w3.org/2001/XMLSchema" />
The program
starts out by creating an object 'a', which is an instance of class XmlSchema.
This class represents the schema element that kick starts all the schema files.
All the XML Schema Definition (XSD) language elements are children of the
schema element.
The Write
function writes out the entire schema that is associated with the XmlSchema
object. The Write function has three overloads that accept either a stream, or
a TextWriter, or an XmlTextWriter, as parameters. Out of the varied choice of
outputs available, we employ the standard output, where the output device is
the screen.
The output is an
xsd file where the mandatory XML directive <?xml gets written first, even
though there is no trace of it in the program. There is no way of forestalling
the directive from being written. However, since it is mandatory, it has to be
present. The encoding and version attributes have already been elucidated in the
earlier chapters.
The schema
element gets written next with the default namespace of xs and the XmlSchema
class using the URI of http://www.w3.org/2001/XMLSchema. This URI represents
the rules of the schema world.
a.cs
using System;
using System.Xml.Schema;
class zzz
{
public static void Main()
{
XmlSchema s = new XmlSchema();
XmlSchemaElement e;
e = new XmlSchemaElement();
XmlSchemaObjectCollection sc;
sc = s.Items;
sc.Add(e);
s.Write(Console.Out);
}
}
Output
<?xml version="1.0"
encoding="IBM437"?>
<xs:schema
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element />
</xs:schema>
An XML Schema
encompasses various elements. Thus, the next logical step is to add an element
to the xsd file. In order to achieve this, a class XmlSchemaElement is used, which
represents an element called 'element'. This is similar to the XmlSchema class
that represents an element called 'schema'. Subsequent to its creation, a new
instance of the class is required to be added to the schema element.
As mentioned
earlier, every element has to be a part of a child of the root schema element.
The Items property of the XmlSchema class is of type XmlSchemaObjectCollection,
which is a collection class. Thus, the Add function contained in this class is
utilized to store all the entities associated with the schema element.
If we attempt to
display the contents of the schema, an empty element tag shall be flashed,
which symbolizes an error. So, why did the framework choose to ignore this
error?
This can be
attributed to the fact that the schema has not been compiled. It is only after
the schema gets compiled that such errors will get reported. Since the
XmlSchema class was solicited to insert an element, it obliged without carrying
out any scrutiny for errors.
a.cs
using System;
using System.Xml.Schema;
class zzz
{
public static void Main()
{
XmlSchema s = new XmlSchema();
XmlSchemaElement e ;
e = new XmlSchemaElement();
XmlSchemaObjectCollection sc;
sc = s.Items;
sc.Add(e);
ValidationEventHandler v = new ValidationEventHandler(abc);
s.Compile(v);
s.Write(Console.Out);
}
public static void abc(object s, ValidationEventArgs a)
{
Console.WriteLine(a.Message);
}
}
Output
The required attribute 'name' is missing.
<?xml version="1.0"
encoding="IBM437"?>
<xs:schema
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element />
</xs:schema>
A delegate object
ValidationEventHandler is created and is passed the name of the function abc,
which shall get called on every occasion that an error occurs. This function
merely displays the value in the Message property. The Compile function, as is
evident from its name, compiles the XML Schema Definition language XSD Schema
Object Model (SOM) into schema information.
To begin with, it
checks the syntax and semantic content of the schema file or SOM. Note that
this error check is performed prior to the compilation. Since no name has been
assigned to the element, the function abc reports an error.
a.cs
using System;
using System.Xml.Schema;
using System.Xml;
class zzz
{
public static void Main()
{
XmlSchema s = new XmlSchema();
XmlSchemaElement e ;
e = new XmlSchemaElement();
e.Name = "vijay";
e.SchemaTypeName = new XmlQualifiedName("string",
"http://www.w3.org/2001/XMLSchema");
XmlSchemaObjectCollection sc;
sc = s.Items;
sc.Add(e);
ValidationEventHandler v = new ValidationEventHandler(abc);
s.Compile(v);
s.Write(Console.Out);
}
public static void abc(object s, ValidationEventArgs a)
{
Console.WriteLine(a.Message);
}
}
Output
<?xml version="1.0"
encoding="IBM437"?>
<xs:schema
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="vijay"
type="xs:string" />
</xs:schema>
To rectify the
above error, merely an element name is required. So, using the Name property,
the element is assigned the name 'vijay'. No type is specified for an element;
therefore, the default type of ur-type comes into play. If the type has to be
specified, then the XmlSchemaTypeName member has to be used.
The
XmlQualifiedName class takes two parameters, viz. a string and the name of the
namespace that the type originates from. The default namespace is the
fountainhead of the string type, and therefore, there exists no namespace
prefix for the type string.
e.SchemaTypeName = new XmlQualifiedName
("xs:string","http://www.w3.org/2001/XMLSchema");
Output
Invalid 'type' attribute - The ':' character, hexadecimal
value 0x3A, cannot be included in a name..
<?xml version="1.0"
encoding="IBM437"?>
<xs:schema
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="vijay"
type="xs:xsd_x003A_string" />
</xs:schema>
The first
parameter to the constructor of class XmlQualifiedName is the local name, while
the second parameter is the namespace. Both of these must be specified
separately.
In the
constructor only the type must be specified. There is no rationale behind
furnishing the namespace, followed by a colon, and then by a type.
e.SchemaTypeName = new XmlQualifiedName("c1",
"b1.xsd");
Output
Type 'b1.xsd:c1' is not declared.
<?xml version="1.0"
encoding="IBM437"?>
<xs:schema
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="vijay"
xmlns:q1="b1.xsd" type="q1:c1" />
</xs:schema>
The above error
message imparts substantial amount of information. The type c1 stems from the
namespace b1.xsd.
In the xsd file,
the type is prefaced with q1 and the schema element, the namespace prefix q1
points to the URI b1.xsd. The Compile function comprehends and interprets the
namespaces.
a.cs
using System;
using System.Xml.Schema;
using System.Xml;
class zzz
{
public static void Main()
{
XmlSchema s = new XmlSchema();
XmlSchemaElement e ;
e = new XmlSchemaElement();
e.Name = "vijay";
e.SchemaTypeName = new XmlQualifiedName("string",
"http://www.w3.org/2001/XMLSchema");
XmlSchemaObjectCollection sc;
sc = s.Items;
sc.Add(e);
XmlSchemaElement e1 = new XmlSchemaElement();
sc.Add(e1);
e1.Name = "sonal";
e1.SubstitutionGroup = new XmlQualifiedName("vijay");
e1.SchemaTypeName = new XmlQualifiedName("string",
"http://www.w3.org/2001/XMLSchema");
ValidationEventHandler v = new ValidationEventHandler(abc);
s.Compile(v);
s.Write(Console.Out);
}
public static void abc(object s, ValidationEventArgs a)
{
Console.WriteLine(a.Message);
}
}
Output
<?xml version="1.0"
encoding="IBM437"?>
<xs:schema
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="vijay"
type="xs:string" />
<xs:element name="sonal"
substitutionGroup="vijay" type="xs:string" />
</xs:schema>
The xsd file now
has two elements: the first one is 'vijay' and the second one is 'sonal'. For
the second element, the name property in the XmlSchemaElement is set to sonal
and the substitutionGroup property is set to vijay using the XmlQualifiedName
object.
It is for these
very reasons that the xsd file displays the element sonal with the substitution
group as vijay, and the type as string. Thus, the above program demonstrates
how a property can be assigned for each and every attribute of the element.
a.cs
using System;
using System.Xml.Schema;
using System.Xml;
class zzz
{
public static void Main()
{
XmlSchema s = new XmlSchema();
XmlSchemaElement e ;
e = new XmlSchemaElement();
e.Name = "vijay";
XmlSchemaObjectCollection sc;
sc = s.Items;
sc.Add(e);
XmlSchemaComplexType t = new XmlSchemaComplexType();
e.SchemaType = t;
ValidationEventHandler v = new ValidationEventHandler(abc);
s.Compile(v);
s.Write(Console.Out);
}
public static void abc(object s, ValidationEventArgs a)
{
Console.WriteLine(a.Message);
}
}
Output:
<?xml version="1.0"
encoding="IBM437"?>
<xs:schema
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="vijay">
<xs:complexType />
</xs:element>
</xs:schema>
In the above
instance, the name of the new XmlElement is set to vijay. It obviously has no
type, but the SchemaType property is set to an object t, which is an instance
of an XmlSchemaComplexType. Therefore, in the output, we notice that the
element is followed by an empty complexType element.
The Block
property of the XmlSchemaElement can contain only the following values: Enum,
Empty, None, Extension, Restriction, Union and List. All these values
facilitate either restriction or extension. Likewise, the Constraints property
can have the following three values: XmlSchemaKey, XmlSchemaKeyref and
XmlSchemaUnique.
a.cs
using System;
using System.Xml.Schema;
using System.Xml;
class zzz
{
public static void Main()
{
XmlSchema s = new XmlSchema();
XmlSchemaElement e ;
e = new XmlSchemaElement();
e.Name = "vijay";
XmlSchemaObjectCollection sc;
sc = s.Items;
sc.Add(e);
XmlSchemaComplexType t = new XmlSchemaComplexType();
e.SchemaType = t;
XmlSchemaChoice c = new XmlSchemaChoice();
t.Particle = c;
c.MinOccurs = 0;
c.MaxOccursString = "unbounded";
XmlSchemaElement e1 = new XmlSchemaElement();
c.Items.Add(e1);
e1.Name = "sonal";
e1.SchemaTypeName = new XmlQualifiedName("string",
"http://www.w3.org/2001/XMLSchema");
ValidationEventHandler v = new ValidationEventHandler(abc);
s.Compile(v);
s.Write(Console.Out);
}
public static void abc(object s, ValidationEventArgs a) {
Console.WriteLine(a.Message);
}
}
Output
<?xml version="1.0"
encoding="IBM437"?>
<xs:schema
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="vijay">
<xs:complexType>
<xs:choice minOccurs="0"
maxOccurs="unbounded">
<xs:element name="sonal"
type="xs:string" />
</xs:choice>
</xs:complexType>
</xs:element>
</xs:schema>
Here onwards, the
program assumes slightly more complex hues. Let us inspect the final xsd file.
The element named vijay is followed by a complexType, which in turn is followed
by a choice element, whose minOccurs and maxOccurs attributes have been set to
0 and 'unbounded', respectively. The element sonal, whose type is a string,
lies within the choice.
In order to build
the above xsd file, the Name property of XmlSchemaElement 'e' is set to vijay,
and is then added to the Items collection. Thereafter, to ensure that a
complexType element follows it, the SchemaType is set to an
XmlSchemaComplexType object. This has already been witnessed in the previous
example. Subsequently, an object 'c' of type XmlSchemaChoice is created, and
the property Particle of the complexType class is initialized to this newly
created object.
Thus, here we
have a choice element as a child of the complexType. To jog your memory, this
property can have only four types of elements following it, viz. group,
sequence, all and a choice. The Particle property has a data type of
XmlSchemaParticle. The XmlSchemaChoice and the other three classes derive from
XmlSchemaParticle.
Simultaneously,
the MinOccurs and the MaxOccurs properties of the choice element are set to 0
and unbounded, respectively. The maxOccurs also has a maxOccursString property
that permits its usage as the single value of 'unbounded'. As mentioned
earlier, the maxOccurs value is a union of numbers and a string.
Then, the second
XmlSchemaElement e1 is created and its name is set to 'sonal'. Thereafter, it
is added to the Items collection of the choice and not to the element called
'vijay'. Hence, this element now falls under the choice element. The xsd file
is the xsd representation of these statements.
a.cs
…
c.MaxOccursString = "unbounded";
c.MaxOccurs = 10;
Output
…
<xs:choice minOccurs="0"
maxOccurs="10">
…
One more line of
code is initiated in the above program, wherein the property MaxOccurs is
initialized to 10. The Compile function uses the last MaxOccurs type of
property, and hence, ‘maxOccurs="10" ‘ gets written to the xsd file.
a.cs
using System;
using System.Xml;
using System.Xml.Schema;
class zzz
{
public static void Main()
{
XmlSchema s = new XmlSchema();
XmlSchemaSimpleType t = new XmlSchemaSimpleType();
t.Name = "c1";
XmlSchemaSimpleTypeRestriction r = new
XmlSchemaSimpleTypeRestriction();
r.BaseTypeName = new XmlQualifiedName("string",
"http://www.w3.org/2001/XMLSchema");
XmlSchemaEnumerationFacet e1 = new
XmlSchemaEnumerationFacet();
e1.Value = "sonal";
r.Facets.Add(e1);
XmlSchemaEnumerationFacet e2 = new
XmlSchemaEnumerationFacet();
e2.Value = "Neha";
r.Facets.Add(e2);
t.Content = r;
s.Items.Add(t);
ValidationEventHandler v = new ValidationEventHandler(abc);
s.Compile(v);
s.Write(Console.Out);
}
public static void abc(object s, ValidationEventArgs a)
{
Console.WriteLine(a.Message);
}
}
Output
<?xml version="1.0"
encoding="IBM437"?>
<xs:schema
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:simpleType name="c1">
<xs:restriction base="xs:string">
<xs:enumeration value="sonal" />
<xs:enumeration value="Neha" />
</xs:restriction>
</xs:simpleType>
</xs:schema>
The program
brings about the creation of an xsd file with a simple type named c1, followed
by a restriction element whose base type is string. The above string is
restricted to the two values of 'sonal' and 'neha'. This is achieved with the
help of the enumeration element.
The basilisk gaze
now shifts to the C# program. Every element in the schema world has a
corresponding class that can comprehend it.
Thus, the class
XmlSchemaSimpleType can understand and handle the simpleType element. The name
property is set to c1. Thereafter, an XmlSchemaSimpleType object is created,
since the restriction element has to be a child of the simpleType.
In our particular
case, the restriction element that is represented by the class XmlSchemaSimpleTypeRestriction,
is employed to restrict a string. The property BaseTypeName is set to an
XmlQualifiedName object.
Then, an object
e1 is created as an instance of the class XmlSchemaEnumerationFacet, which
represents the enumerator element. This enumerator element requires a value.
Therefore, the value property is set to sonal. The
XmlSchemaSimpleTypeRestriction class has a property called Facets, which is of
type XmlSchemaObjectCollection. It has the Add function, which keeps track of
the multiple facets that the restriction can handle.
Within the
restriction, the following eleven facets types are allowed:
XmlSchemaLengthFacet, XmlSchemaMinLengthFacet, XmlSchemaMaxLengthFacet,
XmlSchemaPatternFacet, XmlSchemaEnumerationFacet, XmlSchemaMaxInclusiveFacet, XmlSchemaMaxExclusiveFacet,
XmlSchemaMinInclusiveFacet, XmlSchemaMinExclusiveFacet,
XmlSchemaFractionDigitsFacet and XmlSchemaTotalDigitsFacet.
After the
addition of the multiple facets, the next task is to associate the Content of
the simple type with the restriction. The Content property of type
XmlSchemaSimpleTypeContent is initialized to the restriction object. The other
two possible values are list and union. Finally, using the Add function, the
simpleType element is added to the Items collection of the XmlSchema.
a.cs
using System;
using System.Xml;
using System.Xml.Schema;
class zzz
{
public static void Main()
{
XmlSchema s = new XmlSchema();
XmlSchemaAttribute a = new XmlSchemaAttribute();
s.Items.Add(a);
a.Name = "a1";
a.SchemaTypeName = new XmlQualifiedName("integer",
"http://www.w3.org/2001/XMLSchema");
ValidationEventHandler v = new ValidationEventHandler(abc);
s.Compile(v);
s.Write(Console.Out);
}
public static void abc(object s, ValidationEventArgs a)
{
Console.WriteLine(a.Message);
}
}
Output
<?xml version="1.0"
encoding="IBM437"?>
<xs:schema
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:attribute name="a1"
type="xs:integer" />
</xs:schema>
The above example
basically creates an attribute using the class XmlSchemaAttribute. The
attribute is also added to the Items collection in a manner akin to the other
elements. The attribute is assigned the name a1 of type integer.
a.cs
using System;
using System.Xml;
using System.Xml.Schema;
class zzz
{
public static void Main()
{
XmlSchema s = new XmlSchema();
XmlSchemaGroup g = new XmlSchemaGroup();
s.Items.Add(g);
g.Name = "g1";
XmlSchemaSequence se= new XmlSchemaSequence();
g.Particle = se;
XmlSchemaElement e = new XmlSchemaElement();
se.Items.Add(e);
e.Name = "aaa";
XmlSchemaComplexType t = new XmlSchemaComplexType();
s.Items.Add(t);
t.Name = "c1";
XmlSchemaGroupRef g1= new XmlSchemaGroupRef();
t.Particle = g1;
g1.RefName = new XmlQualifiedName("g1");
ValidationEventHandler v = new ValidationEventHandler(abc);
s.Compile(v);
s.Write(Console.Out);
}
public static void abc(object s, ValidationEventArgs a)
{
Console.WriteLine(a.Message);
}
}
Output
<?xml version="1.0"
encoding="IBM437"?>
<xs:schema
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:group name="g1">
<xs:sequence>
<xs:element name="aaa" />
</xs:sequence>
</xs:group>
<xs:complexType name="c1">
<xs:group ref="g1" />
</xs:complexType>
</xs:schema>
a.cs
using System;
using System.Xml;
using System.Xml.Schema;
class zzz
{
public static void Main()
{
XmlSchema s = new XmlSchema();
XmlSchemaElement e = new XmlSchemaElement();
s.Items.Add(e);
e.Name = "vijay";
XmlSchemaAnnotation a = new XmlSchemaAnnotation();
e.Annotation = a;
XmlSchemaDocumentation d= new XmlSchemaDocumentation();
a.Items.Add(d);
XmlDocument dc = new XmlDocument();
XmlNode n;
n = dc.CreateTextNode("sonals husband");
XmlNode [] na = new XmlNode[1];
na[0] = n;
d.Markup = na;
XmlSchemaAppInfo ap = new XmlSchemaAppInfo();
a.Items.Add(ap);
XmlDocument dc1 = new XmlDocument();
XmlNode n1;
n1 = dc1.CreateTextNode("how are you");
XmlNode [] na1 = new XmlNode[1];
na1[0] = n1;
ap.Markup = na1;
ValidationEventHandler v = new ValidationEventHandler(abc);
s.Compile(v);
s.Write(Console.Out);
}
public static void abc(object s, ValidationEventArgs a)
{
Console.WriteLine(a.Message);
}
}
Output
<?xml version="1.0"
encoding="IBM437"?>
<xs:schema
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="vijay">
<xs:annotation>
<xs:documentation>sonals
husband</xs:documentation>
<xs:appinfo>how are you</xs:appinfo>
</xs:annotation>
</xs:element>
</xs:schema>
The annotation
element, which has not been touched upon so far, deals with documentation. This
element describes the user-defined elements. Programmers abhor the idea of
inserting comments into their code. This is one of the fundamental reasons for
taking up the annotation element much later in the day.
The annotation
must be the child of an element, which in our case is the element vijay. Thus,
an element 'e' with the name vijay is created first. Then, an instance 'a' of
the class XmlSchemaAnnotation is created and associated with the Annotation
property of the element 'e'. An annotation element can contain two other child
elements, viz. appinfo elements and documentation elements.
An appinfo
element is essentially used to accommodate information used by various
applications. On the other hand, the documentation element stores information
aimed at the naïve users who may risk venturing forth to read the code.
An
XmlSchemaDocumentation class represents a documentation element, which is 'd'
in this program. This documentation element is added to the XmlSchemaAnnotation
object 'a', since the annotation has to keep track of the documentation object.
This documentation object requires some text or markup representing its
content. Therefore, the XmlDocument object 'dc' is used, since it represents
the content placed between tags or elements.
The object 'dc'
has a function called CreateTextNode, which is passed the text that is to be
used as markup. The return object is an XmlNode that eventually represents the
text.
Then, an array
with an arraysize of 1 and of type XmlNode is created, whose first and only
member is initialized to the XmlNode object 'n'. The Markup property of the
documentation object 'd' is then initialized to this XmlNode array 'n'. An
array is used whenever multiple members of the same type are required.
The appinfo
element is represented by an XmlSchemaAppInfo object named 'ap'. This object is
initialized to the Items collection of the annotation object 'a'. This is
because an annotation object can have only two children, viz. the documentation
and the appinfo objects. So, just as before, the XmlNode object is created, and
thereafter, the Markup property of the appinfo object is used to specify the
content.
a.cs
using System;
using System.Xml;
using System.Xml.Schema;
class zzz
{
public static void Main()
{
XmlSchema s = new XmlSchema();
XmlSchemaElement e = new XmlSchemaElement();
s.Items.Add(e);
e.Name = "vijay";
XmlSchemaAnnotation a = new XmlSchemaAnnotation();
e.Annotation = a;
XmlSchemaDocumentation d= new XmlSchemaDocumentation();
a.Items.Add(d);
XmlDocument dc = new XmlDocument();
XmlNode n,n1;
n = dc.CreateTextNode("sonal ");
n1 = dc.CreateTextNode("Bye Bye");
XmlNode [] na = new XmlNode[2];
na[0] = n;
na[1] = n1;
d.Markup = na;
ValidationEventHandler v = new ValidationEventHandler(abc);
s.Compile(v);
s.Write(Console.Out);
}
public static void abc(object s, ValidationEventArgs a)
{
Console.WriteLine(a.Message);
}
}
Output
<?xml version="1.0"
encoding="IBM437"?>
<xs:schema
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="vijay">
<xs:annotation>
<xs:documentation>sonalBye Bye</xs:documentation>
</xs:annotation>
</xs:element>
</xs:schema>
The earlier
program is updated now, wherein the array is extended to hold two XmlNode
structures. Thus, the array of XmlNode objects that is passed to the property
Markup, contains two bits. This does not result in the creation of two separate
documentation elements within the xsd file; instead, it spawns a single string
with all the individual contents concatenated together.
a.cs
using System;
using System.Xml;
using System.Xml.Schema;
class zzz
{
public static void Main()
{
XmlSchema s = new XmlSchema();
XmlSchemaElement e = new XmlSchemaElement();
s.Items.Add(e);
e.Name = "zzz";
XmlSchemaAnnotation a = new XmlSchemaAnnotation();
s.Items.Add(a);
ValidationEventHandler v = new ValidationEventHandler(abc);
s.Compile(v);
s.Write(Console.Out);
}
public static void abc(object s, ValidationEventArgs a)
{
Console.WriteLine(a.Message);
}
}
Output
<?xml version="1.0"
encoding="IBM437"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="zzz" />
<xs:annotation />
</xs:schema>
In the above
example, the annotation element is added to the schema and not to the element.
As an outcome of this, it becomes a child of the schema element. This brings
the annotation as well as the element to the same level, i.e. as children of
the schema.
a.cs
using System;
using System.Xml;
using System.Xml.Schema;
class zzz
{
public static void Main()
{
XmlSchema s = new XmlSchema();
XmlSchemaElement e = new XmlSchemaElement();
s.Items.Add(e);
e.Name = "zzz";
s.Items.Add(e);
ValidationEventHandler v = new ValidationEventHandler(abc);
s.Compile(v);
s.Write(Console.Out);
}
public static void abc(object s, ValidationEventArgs a)
{
Console.WriteLine(a.Message);
}
}
Output
Global element 'zzz' has already been declared.
<?xml version="1.0"
encoding="IBM437"?>
<xs:schema
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="zzz" />
<xs:element name="zzz" />
</xs:schema>
The xsd file gets
created, notwithstanding any errors that may or may not occur. In the above
example, the element zzz is added twice using the Items collection. This
results in an error, since two elements with the same name cannot co-exist at
the same level. Despite this, the xsd file shows two zzz elements, but the abc
function displays an error message.
Henceforth, we
shall employ an altogether distinctive method for reading an existing xsd file.
Since an xsd file is eventually an xml file, the XmlTextWriter class is used to
read an xml file and fragment it into its constituent components. Thus, we
shall now read an xsd file as an xml file and simultaneously, display it
contents.
A salient point
to be committed to memory is that the file being read or written to is an xml
file and not an XML Schema file. Nonetheless, the API is exceptionally
powerful, since it understands XML Schemas, unlike the approach adopted
presently.
a.cs
using System;
using System.IO;
using System.Xml;
using System.Xml.Schema;
public class zzz
{
public static void Main()
{
XmlTextWriter t;
t= new XmlTextWriter(Console.Out);
t.Formatting = Formatting.Indented;
t.Indentation = 2;
XmlSchemaCollection sc = new XmlSchemaCollection();
sc.Add(null, "b.xsd");
foreach(XmlSchema s in sc)
{
Console.WriteLine("..." + s.SourceUri+ " " +
XmlSchema.Namespace + " " + s.TargetNamespace);
t.WriteStartElement("schema", XmlSchema.Namespace);
t.WriteAttributeString("targetNamespace",
s.TargetNamespace);
t.WriteEndElement();
}
}
}
Output
...file:///c:/xmlprg/b.xsd http://www.w3.org/2001/XMLSchema
<schema targetNamespace=""
xmlns="http://www.w3.org/2001/XMLSchema" />
The XmlTextWriter
object 't' is conversant with writing an xml file to the disk or elsewhere. The
device chosen here is that of Console. The nitty-gritties of the XmlTextWriter
class shall not be touched upon, since they have been dealt with
comprehensively in our first book on XML. The properties of Formatting and
Indentation are used to make the xml file more readable.
The Add function
is used to add the schema files to the XmlSchemaCollection class. In this
program, we have only added the file b.xsd. Then, using the 'foreach' construct
on the XmlSchemaCollection object, an XmlSchema object that represents the
schema file, is returned. The only schema in the collection viz. b.xsd, is
represented by the XmlSchema object named 's'.
The SourceURI
property provides the name of the xsd file associated with the XmlSchema object
s. The Namespace property is like a normal URI. It is associated with the class
and not with the object. Since no target namespace is given in the xsd file,
the TargetNamespace property displays a value of null. As mentioned earlier,
the XmlTextWriter replicates the contents of the file, where the XmlSchema
object 's' represents the actual contents.
The function
WriteStartElement takes two parameters, viz. the name of the element and the
namespace that the function belongs to. For the first parameter, the name of
the element is specified as schema. For the second parameter, the familiar
namespace that holds the namespace is specified.
In order to
specify the attribute targetNamespace, the function WriteAttributeString is
employed. This function takes the attribute as its first parameter. This
attribute is part of the last element that has been written but not closed yet,
which in our case is schema. Our targetNamespace is an empty string. Then, the
element is closed using the function WriteEndElement.
If you were to
observe closely, you would discern that the schema element has no namespace
prefixes such as xs: or xs:. Instead,
it uses the xmlns to specify the default namespace as the namespace. In the
earlier programs, there existed a class that represented a schema element.
Moreover, the end of schema was not considered imperative.
In the ultimate
analysis, what emerges is that all the classes that represent the various
elements are finally replaced by the two functions named WriteStartElement and
WriteEndElement.
a.cs
using System;
using System.IO;
using System.Xml;
using System.Xml.Schema;
public class zzz
{
public static void Main()
{
XmlTextWriter t;
t= new XmlTextWriter(Console.Out);
t.Formatting = Formatting.Indented;
t.Indentation = 2;
XmlSchemaCollection sc = new XmlSchemaCollection();
sc.Add(null, "b.xsd");
foreach(XmlSchema s in sc)
{
Console.WriteLine("..." + s.SourceUri+ " " +
XmlSchema.Namespace + " " + s.TargetNamespace);
t.WriteStartElement("xs:schema");
t.WriteAttributeString("xmlns:xs",
"http://www.w3.org/2001/XMLSchema");
t.WriteAttributeString("targetNamespace",
"");
t.WriteEndElement();
}
}
}
Output
...file:///c:/xmlprg/b.xsd http://www.w3.org/2001/XMLSchema
<xs:schema
xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="" />
An alternate way
of writing the same program is by omitting the namespace that the element
belongs to. Instead, the element name can be prefaced with the namespace
prefix. However, the attribute of xmlns:xs must be added with the XML namespace
value. The WriteAttributeString function expects a name and a value, but does
not expect any parameter for the
namespace.
a.cs
using System;
using System.IO;
using System.Xml;
using System.Xml.Schema;
public class zzz
{
public static void Main()
{
XmlTextWriter t;
t= new XmlTextWriter(Console.Out);
t.Formatting = Formatting.Indented;
t.Indentation = 2;
XmlSchemaCollection sc = new XmlSchemaCollection();
sc.Add(null, "b.xsd");
foreach(XmlSchema s in sc)
{
Console.WriteLine("..." + s.SourceUri+ " " +
XmlSchema.Namespace + " " + s.TargetNamespace);
t.WriteStartElement("schema", XmlSchema.Namespace);
t.WriteAttributeString("targetNamespace",
s.TargetNamespace);
foreach(XmlSchemaInclude include in s.Includes)
{
t.WriteStartElement("include", XmlSchema.Namespace);
t.WriteAttributeString("schemaLocation",
include.SchemaLocation);
t.WriteEndElement();
}
t.WriteEndElement();
}
}
}
b.xsd
<xs:schema
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:include schemaLocation="a1.bsd" />
<xs:include schemaLocation="a2.bsd" />
</xs:schema>
Output
...file:///c:/xmlprg/b.xsd http://www.w3.org/2001/XMLSchema
<schema targetNamespace=""
xmlns="http://www.w3.org/2001/XMLSchema"/>
<include
schemaLocation="a1.bsd" />
<include
schemaLocation="a2.bsd" />
</schema>
a.cs
using System;
using System.IO;
using System.Xml;
using System.Xml.Schema;
public class zzz
{
public static void Main()
{
XmlTextWriter t;
t= new XmlTextWriter(Console.Out);
t.Formatting = Formatting.Indented;
t.Indentation = 2;
XmlSchemaCollection sc = new XmlSchemaCollection();
sc.Add(null, "b.xsd");
foreach(XmlSchema s in sc)
{
Console.WriteLine("..." + s.SourceUri+ " " +
XmlSchema.Namespace + " " + s.TargetNamespace);
t.WriteStartElement("schema", XmlSchema.Namespace);
t.WriteAttributeString("targetNamespace",
s.TargetNamespace);
foreach(XmlSchemaInclude i in s.Includes)
{
t.WriteStartElement("include", XmlSchema.Namespace);
t.WriteAttributeString("schemaLocation",
i.SchemaLocation);
t.WriteEndElement();
}
t.WriteEndElement();
}
}
}
Output
...file:///c:/xmlprg/b.xsd http://www.w3.org/2001/XMLSchema
<schema targetNamespace=""
xmlns="http://www.w3.org/2001/XMLSchema">
<include
schemaLocation="a2.bsd" />
<include
schemaLocation="a1.bsd" />
</schema>
The xsd file can
contain multiple 'import' or 'include' elements to usher in the varied types
from other files. For this purpose, the XmlSchema class has a property called
Includes, which is of type XmlSchemaObjectCollection. Its indexer returns an
XmlSchemaInclude object that furnishes information related to the 'include' or
the 'import' element.
The 'foreach'
construct is used to iterate over the collection class, wherein the 'include'
element is written out using the WriteStartElement function. Thereafter, only
the value of the schemaLocation attribute is written with the help of the
WriteAttributeString function.
The value of this
attribute is stored in the property SchemaLocation of the XmlSchemaInclude
class. The last EndElement function is used with the basic purpose of writing
the end tag for the schema element.
a.cs
using System;
using System.IO;
using System.Xml;
using System.Xml.Schema;
public class zzz
{
public static void Main()
{
XmlTextWriter t;
t= new XmlTextWriter(Console.Out);
t.Formatting = Formatting.Indented;
t.Indentation = 2;
XmlSchemaCollection sc = new XmlSchemaCollection();
sc.Add(null, "b.xsd");
foreach(XmlSchema s in sc)
{
Console.WriteLine(s.Items.Count);
t.WriteStartElement("schema", XmlSchema.Namespace);
t.WriteAttributeString("targetNamespace",
s.TargetNamespace);
foreach(object i in s.Items)
{
if ( i is XmlSchemaElement)
{
XmlSchemaElement e = (XmlSchemaElement) i ;
t.WriteStartElement("element", XmlSchema.Namespace);
if (e.Name != null)
t.WriteAttributeString("name", e.Name);
if (!e.SchemaTypeName.IsEmpty)
{
t.WriteStartAttribute("type", null);
t.WriteQualifiedName(e.SchemaTypeName.Name,
e.SchemaTypeName.Namespace);
t.WriteEndAttribute();
}
t.WriteEndElement();
}
}
t.WriteEndElement();
}
}
}
b.xsd
<xs:schema
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="zzz"
type="xs:string" />
<xs:element name="yyy"
type="xs:string" />
</xs:schema>
Output
2
<schema targetNamespace=""
xmlns="http://www.w3.org/2001/XMLSchema">
<element name="zzz" type="string"
/>
<element name="yyy" type="string"
/>
</schema>
The Items
collection has a property called Count, which gives a count of the number of
items present in the xsd file. Given that the xsd file has two elements, the
Count property returns a value of 2. The schema element is not counted as a
valid element.
Then, using the
'foreach' construct, each one of the items in the collection is accessed. Since
these items may be of any type, they are received as a type object.
Using the 'if'
statement, a verification is carried out to ascertain if this object is indeed
of type XmlSchemaElement element. If the condition is true, it implies that the
element has been targeted, and therefore, the tag element is printed using the
WriteStartElement function. But prior to this, the value of 'i' is stored in an
object into 'e', which is an XmlSchemaElement.
The second check
is performed on the name property. If it is not null, then the attribute 'a' is
written with the name equal to the value of the property name in the
XmlSchemaElement. This check is indispensable, since there is a possibility of
using the 'ref' attribute instead.
Finally, a check
is performed on the SchemaTypeName. Contingent upon whether it is empty or
otherwise, the name of the attribute type is written. The other function that
is pressed into action is the WriteQualifiedName function, which contains the
name of the attribute string and the namespace from which it originates.
This function is
astute enough to establish the fact that the name string shall automatically be
prefaced by the default xsd prefix. Hence, it writes the attribute as string
and not as xs:string. The WriteEndAttribute function is needed to conclude the
start of the attribute. Lastly, to end the element called 'element', the
WriteEndElement function is used.
a.cs
using System;
using System.IO;
using System.Xml;
using System.Xml.Schema;
public class zzz
{
public static void Main()
{
XmlTextWriter t;
t= new XmlTextWriter(Console.Out);
t.Formatting = Formatting.Indented;
t.Indentation = 2;
XmlSchemaCollection sc = new XmlSchemaCollection();
sc.Add(null, "b.xsd");
foreach(XmlSchema s in sc)
{
Console.WriteLine(s.Items.Count);
t.WriteStartElement("schema", XmlSchema.Namespace);
t.WriteAttributeString("targetNamespace",
s.TargetNamespace);
foreach(object i in s.Items)
{
if ( i is XmlSchemaComplexType)
{
XmlSchemaComplexType c = (XmlSchemaComplexType)i;
t.WriteStartElement("complexType",
XmlSchema.Namespace);
t.WriteAttributeString("name", c.Name);
if (c.Particle != null)
{
if (c.Particle is XmlSchemaSequence)
{
t.WriteStartElement("sequence", XmlSchema.Namespace);
t.WriteEndElement();
}
}
t.WriteEndElement();
}
if ( i is XmlSchemaElement)
{
XmlSchemaElement e = (XmlSchemaElement ) i ;
t.WriteStartElement("element", XmlSchema.Namespace);
if (e.Name != null)
t.WriteAttributeString("name", e.Name);
if (!e.SchemaTypeName.IsEmpty)
{
t.WriteStartAttribute("type", null);
t.WriteQualifiedName(e.SchemaTypeName.Name,
e.SchemaTypeName.Namespace);
t.WriteEndAttribute();
}
t.WriteEndElement();
}
}
t.WriteEndElement();
}
}
}
b.xsd
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="zzz"
type="xs:string" />
<xs:complexType name="c1" >
<xs:sequence>
</xs:sequence>
</xs:complexType>
</xs:schema>
Output
2
<schema targetNamespace=""
xmlns="http://www.w3.org/2001/XMLSchema">
<element name="zzz" type="string"
/>
<complexType name="c1">
<sequence />
</complexType>
</schema>
The above program
is the concluding example of this series. The element is given a type of
complexType. As a consequence, the Items collection now contains an element as
well as a complex type. Therefore, the return value of 2 is obtained.
The 'if'
statement ascertains whether 'i' is an XmlSchemaComplexType element or not.
Then, it casts the object value, as was done previously. Thereafter, the tag
complexType is written along with the attribute name.
As mentioned
earlier, the Particle property can either be a sequence, a choice, a group, or
all of these. If it is not null, it is indicative of the presence of a valid
Particle. It is then ascertained whether this Particle is an XmlSchemaSequence
or not; if it is so, then the sequence element is written out.
We would
recommend the use of the earlier API in lieu of this method, since it can
understand and appreciate schemas, whereas this one can only comprehend XML.
The API enjoys intrinsic knowledge of the schema world, which may ironically
prove to be its biggest stumbling block.
a.cs
public class zzz
{
public int a1;
}
>csc /t:library a.cs
This creates a
dll file named a.dll. We then run the xsd program on a.dll using the command
> xsd a.dll
This command
creates a file called schema0.xsd. The contents of this file are displayed
below.
schema0.xsd
<?xml version="1.0" encoding="utf-8"?>
<xs:schema elementFormDefault="qualified"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="zzz" nillable="true"
type="zzz" />
<xs:complexType name="zzz">
<xs:sequence>
<xs:element
minOccurs="1" maxOccurs="1" name="a1"
type="xs:int" />
</xs:sequence>
</xs:complexType>
</xs:schema>
The schema tag is
created with the attributes of elementFormDefault having a value of qualified
and with the default namespace of xs . The class zzz results in the creation of
an element called zzz, with the nillable attribute set to true. This element
has a complexType of zzz.
Thus, a C# class
becomes an element as well as a type, both bearing the same name. The
complexType is followed by a sequence and then, by an element with an int
variable named a1. It is amply evident that its type is an int, and the values
assigned to the maxOccurs and minOccurs attributes are their default values,
which have been stated expressly.
a.cs
using System.Xml.Serialization;
public class zzz
{
[System.Xml.Serialization.XmlIgnoreAttribute()]
public int a1;
}
schema0.xsd
<?xml version="1.0" encoding="utf-8"?>
<xs:schema elementFormDefault="qualified"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="zzz" nillable="true"
type="zzz" />
<xs:complexType name="zzz" />
</xs:schema>
In the C#
program, an attribute called XmlIgnoreAttribute has been inserted from the
namespace System.Xml.Serialization . This attribute is entrusted with the onus
of ensuring that the variable that follows it is neither written nor serialized
to the disk. As an outcome of this, we find no mention of the variable a1
within the complexType zzz in the xsd file.
The C# class
places some attributes on the members of the class prior to the creation of a
dll. The dll file could even have been created by Visual Basic for all that we
care. Then, the xsd program is beckoned to generate a schema file.
The schema file
generated by the xsd file has a distinct appearance owing to the use of
attributes like Serialization. This schema file can be used for myriad
purposes, such as developing Web Services, etc.
a.cs
using System.Xml.Serialization;
using System.Xml;
using System.Xml.Schema;
[System.Xml.Serialization.XmlRootAttribute(ElementName="zzz1",
Namespace="ttt", IsNullable=true )]
public class zzz
{
public int a1;
}
schema0.xsd
<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:tns="ttt"
elementFormDefault="qualified" targetNamespace="ttt"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="zzz1" nillable="true"
type="tns:zzz" />
<xs:complexType name="zzz">
<xs:sequence>
<xs:element
minOccurs="1" maxOccurs="1" name="a1"
type="xs:int" />
</xs:sequence>
</xs:complexType>
</xs:schema>
The
XmlRootAttribute can only be placed before one of the following: a class, a
structure, an enum and an interface. It identifies the aforementioned four
entities as the root or top-level elements of an XML-document instance. Akin to
all other attribute classes, it too has to be derived from the Attribute. This
class is basically used to determine the manner in which the xsd program
generates the root element.
The ElementName
property is set to zzz1. Thus, in the schema that is generated, the element
name has been changed to zzz1, but the complexType name is retained as zzz,
which is the name of the class. The elementFormDefault property takes the
default value of 'qualified'.
Owing to the
property Namespace, the targetNamespace that was null earlier, is now amended
to ttt. Thus, every entity created in this xsd file, such as the complexType
zzz, is prefaced with the namespace prefix q1. This prefix is created using the
xmlns attribute with a value of ttt. It is created in the element zzz1, and not
in the prefix. The property IsNullable represents the attribute of xsi:nil.
a.cs
using System.Xml.Serialization;
using System.Xml;
using System.Xml.Schema;
public class zzz
{
[System.Xml.Serialization.XmlRootAttribute ()]
public int a1;
}
Error
a.cs(6,2): error CS0592: Attribute
'System.Xml.Serialization.XmlRootAttribute' is not valid on this declaration
type. It is valid on 'class, struct, enum, interface, return' declarations
only.
The attribute
class identifies the precise location wherein a newly created attribute can be
used. The XmlRootAttribute can only be used on the aforementioned four
entities.
a.cs
using System.Xml.Serialization;
using System.Xml;
using System.Xml.Schema;
public class zzz
{
public int a1;
}
public class yyy
{
public int a2;
}
schema0.xsd
<?xml version="1.0" encoding="utf-8"?>
<xs:schema elementFormDefault="qualified"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="zzz" nillable="true"
type="zzz" />
<xs:complexType name="zzz">
<xs:sequence>
<xs:element minOccurs="1"
maxOccurs="1" name="a1" type="xs:int" />
</xs:sequence>
</xs:complexType>
<xs:element name="yyy" nillable="true"
type="yyy" />
<xs:complexType name="yyy">
<xs:sequence>
<xs:element
minOccurs="1" maxOccurs="1" name="a2"
type="xs:int" />
</xs:sequence>
</xs:complexType>
</xs:schema>
There are two
classes in the dll file, viz. a zzz class and a yyy class. Therefore, two
elements of zzz and yyy are seen in the xsd file. The zzz element has a type of
zzz, while the yyy element has a type of yyy. Thus, there could exist as many
classes as one desires, but the general rule that never ceases to apply is that
each class becomes an element and a type.
a.cs
using System.Xml.Serialization;
using System.Xml;
using System.Xml.Schema;
public class zzz
{
public yyy a1;
}
public class yyy
{
public int a2;
}
schema0.xsd
<?xml version="1.0" encoding="utf-8"?>
<xs:schema elementFormDefault="qualified"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="zzz" nillable="true"
type="zzz" />
<xs:complexType name="zzz">
<xs:sequence>
<xs:element
minOccurs="1" maxOccurs="1" name="a1"
type="xs:int" />
</xs:sequence>
</xs:complexType>
<xs:element name="yyy" nillable="true"
type="yyy" />
<xs:complexType name="yyy">
<xs:sequence>
<xs:element
minOccurs="1" maxOccurs="1" name="a2"
type="xs:int" />
</xs:sequence>
</xs:complexType>
</xs:schema>
In a.cs, the
variable a1 in the class zzz is declared to be of type yyy, instead of an int.
This change is witnessed in the xsd file, where the type of the element named
a1 is changed from int to yyy. The other modification is visually apparent. In
normal cases, the element yyy comes first, followed by its complex type.
However, in the above case, this sequence has been reversed.
a.cs
using System.Xml.Serialization;
using System.Xml;
using System.Xml.Schema;
public class zzz
{
[System.Xml.Serialization.XmlElementAttribute(ElementName="aa"
, Namespace="ttt")]
public int a1;
}
schema0.xsd
<?xml version="1.0" encoding="utf-8"?>
<xs:schema elementFormDefault="qualified"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:import namespace="ttt" />
<xs:element name="zzz" nillable="true"
type="zzz" />
<xs:complexType name="zzz">
<xs:sequence>
<xs:element minOccurs="1" maxOccurs="1"
xmlns:q1="ttt" ref="q1:aa" />
</xs:sequence>
</xs:complexType>
</xs:schema>
schema1.xsd
<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:tns="ttt"
elementFormDefault="qualified" targetNamespace="ttt"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="aa" type="xs:int" />
</xs:schema>
In the C#
program, the XmlElementAttribute is placed over the element a1. The ElementName
property is set to aa. Hence, in the xsd file schema1.xsd, the element name
changes from a1 to aa. The Namespace property is set to ttt. This leads to the
import element being added to the scheam0.xsd file, with the namespace
attribute set to ttt.
In the
complexType zzz, there is an element that refers to q1:aa. This element is not
present in the file, and yet no errors are generated, since the xmlns attribute
points the q1 namespace prefix to ttt.
In schema1.xsd,
the targetNamespace is set to ttt. It contains one element, which is present in
namespace aa. Thus, all the items present in the other namespace are posited in
a separate file.
a.cs
using System.Xml.Serialization;
using System.Xml;
using System.Xml.Schema;
public class zzz
{
[System.Xml.Serialization.XmlElementAttribute(Namespace="ttt")]
public int a1;
[System.Xml.Serialization.XmlElementAttribute(Namespace="uuu")]
public int a2;
}
schema0.xsd
<?xml version="1.0" encoding="utf-8"?>
<xs:schema elementFormDefault="qualified"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:import namespace="ttt" />
<xs:import namespace="uuu" />
<xs:element name="zzz" nillable="true"
type="zzz" />
<xs:complexType name="zzz">
<xs:sequence>
<xs:element minOccurs="1" maxOccurs="1"
xmlns:q1="ttt" ref="q1:a1" />
<xs:element minOccurs="1" maxOccurs="1"
xmlns:q2="uuu" ref="q2:a2" />
</xs:sequence>
</xs:complexType>
</xs:schema>
schema1.xsd
<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:tns="ttt"
elementFormDefault="qualified" targetNamespace="ttt"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="a1" type="xs:int" />
</xs:schema>
schema2.xsd
<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:tns="uuu" elementFormDefault="qualified"
targetNamespace="uuu"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="a2" type="xs:int" />
</xs:schema>
In the above
instance, the elements a1 and a2 belong to separate namespaces ttt and uuu. In
the schema0.xsd file, the two import elements refer to the namespaces ttt and
uuu. The first element in the sequence refers to the element a1 using the
namespace prefix q1, which points to the namespace ttt.
In much the same
way, the second element uses the namespace prefix q2 to refer to the element
a2. Further, q2 is initialized to the namespace uuu, using the xmlns attribute.
The namespace ttt dwells in the file schema1.xsd, which contains a single
element named a1. The file schema2.xsd contains the namespace uuu and the
element a2.
Thus, if the
elements emanate from a 100 disparate namespaces in the C# program, then there
would exist 100 distinct xsd files, one for each statement. Then, the import
statements shall usher them all in.
a.cs
using System.Xml.Serialization;
using System.Xml;
using System.Xml.Schema;
public class zzz
{
[System.Xml.Serialization.XmlElementAttribute(DataType="positiveInteger")]
public string a1;
}
schema0.xsd
<?xml version="1.0" encoding="utf-8"?>
<xs:schema elementFormDefault="qualified"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="zzz" nillable="true"
type="zzz" />
<xs:complexType name="zzz">
<xs:sequence>
<xs:element minOccurs="0" maxOccurs="1"
name="a1" type="xs:positiveInteger" />
</xs:sequence>
</xs:complexType>
</xs:schema>
The type of the
element is changed from a string to a positiveInteger by using the DataType
property. As an outcome of this modification, the type of the element a1
transforms from a string into a positive integer in the xsd file. Thus, it sets
the type in the xml file and not in the C# program.
There is a
mammoth table in the 'help' section of the property DataType, which furnishes
all the details of the various XML data types and their .NET equivalents. For
the most part, the .Net data types are strings.
a.cs
using System.Xml.Serialization;
using System.Xml;
using System.Xml.Schema;
public class zzz
{
[System.Xml.Serialization.XmlElementAttribute(DataType="boolean")]
public string a1;
}
Error
Error: There was an error processing 'a.dll'.
-There was an error
reflecting 'zzz'.
-'boolean' is an
invalid value for the XmlElementAttribute.DataType property. boolean can not be
converted to System.String.
The xsd program
generates an error while trying to convert a boolean into a String. The table
very lucidly states that both, the XML data type and the .Net data type should
be strings. Thus, just any two types cannot be randomly brought together and
expected to work with each other. As a prerequisite, a conversion between the
two types should be achievable. This error is an xsd error and not a C#
compiler error.
a.cs
public class zzz
{
public string [] a1;
}
schema0.xsd
<?xml version="1.0" encoding="utf-8"?>
<xs:schema elementFormDefault="qualified"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="zzz" nillable="true"
type="zzz" />
<xs:complexType name="zzz">
<xs:sequence>
<xs:element minOccurs="0" maxOccurs="1"
name="a1" type="ArrayOfString" />
</xs:sequence>
</xs:complexType>
<xs:complexType name="ArrayOfString">
<xs:sequence>
<xs:element minOccurs="0"
maxOccurs="unbounded" name="string"
nillable="true" type="xs:string" />
</xs:sequence>
</xs:complexType>
</xs:schema>
The C# program
has a variable a1, whose type is an array of strings. This variable in the xsd
file becomes a type ArrayOfString. The complexType is a sequence containing one
element that has a minOccurs value of zero, which implies that the element does
not have to be present. It also has a maxOccurs value of 'unbounded'.
Thus, an array is
represented by a complexType, where the element can occur from zero to infinite
number of times. It imbibes the name of the data type of the array in the C#
program.
a.cs
public class zzz
{
public string a1
{
get
{
int i;
return "";
}
set
{
System.Console.WriteLine("hell");
}
}
}
schema0.xsd
<?xml version="1.0" encoding="utf-8"?>
<xs:schema elementFormDefault="qualified"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="zzz" nillable="true"
type="zzz" />
<xs:complexType name="zzz">
<xs:sequence>
<xs:element minOccurs="0" maxOccurs="1"
name="a1" type="xs:string" />
</xs:sequence>
</xs:complexType>
</xs:schema>
What works for a
variable also works for a property. In the above C# program, a1 is declared as
a property called string, which becomes an element a1 in the xsd program. For
the user of a class, there is no possible means of distinguishing between a
property and a variable.
Variables have
fallen out of favour, while the properties are in vogue today, wherein code is
executed using a 'set' or a 'get' for the value of a property.
The property a1
contains a variable called i along with the WriteLine function. None of this
gets reflected in the XML Schema file.
a.cs
public class zzz
{
public string a1
{
set
{
System.Console.WriteLine("hell");
}
}
}
schema0.xsd
<?xml version="1.0" encoding="utf-8"?>
<xs:schema elementFormDefault="qualified"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="zzz" nillable="true"
type="zzz" />
<xs:complexType name="zzz" />
</xs:schema>
The property a1
in the C# program has only a 'set' accessor; hence, its value cannot be read.
Since its value can only be set, the property is not added into the schema
file.
a.cs
public class zzz
{
public string a1
{
get
{
return "";
}
}
}
The property with a 'get' accessor too is not added to the xsd
file.
a.cs
public class zzz
{
public void abc()
{
}
}
schema0.xsd
<?xml version="1.0" encoding="utf-8"?>
<xs:schema elementFormDefault="qualified"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="zzz" nillable="true"
type="zzz" />
<xs:complexType name="zzz" />
</xs:schema>
None of the code
present in the C# program is reflected in the XML Schema. Thus, the above
function abc finds no mention in the XML Schema file.
a.cs
public class zzz
{
int i;
}
schema0.xsd
<?xml version="1.0" encoding="utf-8"?>
<xs:schema elementFormDefault="qualified"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="zzz" nillable="true"
type="zzz" />
<xs:complexType name="zzz" />
</xs:schema>
The variable i
does not become an element in the xsd file since it is private to the class.
Only members that are public find a mention in the XML Schema file.
a.cs
public class zzz
{
int i;
}
public class yyy : zzz
{
int j;
}
schema0.xsd
<?xml version="1.0" encoding="utf-8"?>
<xs:schema elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="zzz" nillable="true"
type="zzz" />
<xs:complexType name="zzz" />
<xs:element name="yyy" nillable="true"
type="yyy" />
<xs:complexType name="yyy">
<xs:complexContent mixed="false">
<xs:extension base="zzz" />
</xs:complexContent>
</xs:complexType>
</xs:schema>
The class yyy
derives from the class zzz. This results in the conversion of the zzz class
into an element named zzz, having a data type of zzz. The class yyy becomes an
element of type yyy.
Now comes the
cropper. The complexType yyy has a complexContent element, which does not
permit content between tags, since the mixed attribute has a value of false.
This type now extends the class zzz, since the base attribute is initialized to
zzz. The derived class in C# is represented by the extension element in the xsd
world.
a.cs
interface iii
{
int i
{
get;
set;
}
}
public class yyy : iii
{
public int i
{
get {return 0;}
set {}
}
}
schema0.xsd
<?xml version="1.0" encoding="utf-8"?>
<xs:schema elementFormDefault="qualified"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="yyy" nillable="true"
type="yyy" />
<xs:complexType name="yyy">
<xs:sequence>
<xs:element
minOccurs="1" maxOccurs="1" name="i"
type="xs:int" />
</xs:sequence>
</xs:complexType>
</xs:schema>
The .cs file now
has an interface called iii with a property named 'i'. This property must be
present in the class yyy, since the class yyy extends from this interface. This
relationship is not stored in the xsd file, because interfaces have no
equivalence in the Schema world.
Thus, the usage
of one or more interfaces in the class yyy definition shall never get reflected
in the xsd file. There is no way of discerning as to which element originates
from which interface.
We have no reason
to fret in this regard, since interfaces have to be implemented in the class.
Moreover, the extension mechanism cannot have more than one base at a given
time.
a.cs
public enum zzz
{
a1=10,a2
}
schema0.xsd
<?xml version="1.0" encoding="utf-8"?>
<xs:schema elementFormDefault="qualified"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="zzz" type="zzz" />
<xs:simpleType name="zzz">
<xs:restriction base="xs:string">
<xs:enumeration value="a1" />
<xs:enumeration value="a2" />
</xs:restriction>
</xs:simpleType>
</xs:schema>
An enum is a type
whose value is restricted. The enum zzz gets converted to an element zzz and a
simpleType zzz. This type is restricted by the string type, and it uses the
enumeration element to specify the valid values.
a.cs
public struct zzz
{
public int i;
}
schema0.xsd
<?xml version="1.0" encoding="utf-8"?>
<xs:schema elementFormDefault="qualified"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="zzz" type="zzz" />
<xs:complexType name="zzz">
<xs:sequence>
<xs:element
minOccurs="1" maxOccurs="1" name="i"
type="xs:int" />
</xs:sequence>
</xs:complexType>
</xs:schema>
C# is extremely
stringent about the disparity between value types structures and reference types
classes.
In the .cs file,
even though the struct zzz has an int, the schema file retains it as an element
and a complex type. Thus, there is no difference between a structure 'i' and a
class 'n' in the Schema world