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