Introduction
XSD.EXE is an XML Schema Definition tool that generates XML schema or common language runtime classes from XDR, XML, and XSD files, or from classes in a runtime assembly.
An XML-schema is a document that describes the valid format of an XML data-set. This definition includes what elements are (and are not) allowed at any point, what the attributes for any element may be, the number of occurrences of elements, etc.
Deserialization Process
Let us assume you are building a web service, which takes XML (in the form of string) as input, and shown below is the schema of the data that is to be exchanged between the clients and your web service.
="1.0" ="UTF-8"
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:complexType name="EmployeeType">
<xsd:sequence>
<xsd:element name="EmployeerID" type="xsd:int" />
<xsd:element name="Name" type="NameType" />
<xsd:element name="SSN"
type="xsd:string" minOccurs="0" />
<xsd:element name="CurrentAddress"
type="AddressType" />
<xsd:element name="PreviousAddress"
type="AddressType"
minOccurs="0" maxOccurs="2" />
<xsd:element name="DriverLicense"
type="xsd:string" minOccurs="0" />
<xsd:element name="Phone"
type="PhoneType"
minOccurs="0" maxOccurs="3" />
<xsd:element name="DOB"
type="xsd:string" minOccurs="0" />
<xsd:element name="YOB"
type="xsd:string" minOccurs="0" />
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="NameType">
<xsd:annotation>
<xsd:documentation />
</xsd:annotation>
<xsd:sequence>
<xsd:element name="Surname"
type="xsd:string"></xsd:element>
<xsd:element name="First"
type="xsd:string"></xsd:element>
<xsd:element name="Middle" minOccurs="0"
type="xsd:string"></xsd:element>
<xsd:element name="Gen" minOccurs="0"
type="xsd:string"></xsd:element>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="AddressType">
<xsd:sequence>
<xsd:element name="StreetNumber" minOccurs="0"
type="xsd:int"></xsd:element>
<xsd:element name="StreetName"
type="xsd:string"></xsd:element>
<xsd:element name="City"
type="xsd:string"></xsd:element>
<xsd:element name="State"
type="xsd:string"></xsd:element>
<xsd:element name="Zip"
type="xsd:string"></xsd:element>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="PhoneType">
<xsd:sequence>
<xsd:element name="Type" minOccurs="0"
type="xsd:string"></xsd:element>
<xsd:element name="Number" type="xsd:string" />
</xsd:sequence>
</xsd:complexType>
<xsd:element name="EmpType"
type="EmployeeType"></xsd:element>
</xsd:schema>
To deserialize, first we need to build a class as below:
[System.Xml.Serialization.XmlRootAttribute("EmpType",
Namespace="", IsNullable=false)]
public class EmployeeType
{
[System.Xml.Serialization.XmlElementAttribute(
Form=System.Xml.Schema.XmlSchemaForm.Unqualified)]
public int EmployeerID;
[System.Xml.Serialization.XmlElementAttribute(
Form=System.Xml.Schema.XmlSchemaForm.Unqualified)]
public NameType Name;
. . . . . .
. . . . . .
. . . . . .
}
public class NameType
{
[System.Xml.Serialization.XmlElementAttribute(
Form=System.Xml.Schema.XmlSchemaForm.Unqualified)]
public string Surname;
. . . . . .
. . . . . .
. . . . . .
}
public class PhoneType
{
[System.Xml.Serialization.XmlElementAttribute(
Form=System.Xml.Schema.XmlSchemaForm.Unqualified)]
public string Type;
[System.Xml.Serialization.XmlElementAttribute(
Form=System.Xml.Schema.XmlSchemaForm.Unqualified)]
public string Number;
}
public class AddressType
{
[System.Xml.Serialization.XmlElementAttribute(
Form=System.Xml.Schema.XmlSchemaForm.Unqualified)]
public int StreetNumber;
. . . . . .
. . . . . .
. . . . . .
}
Building such a class by seeing the XML schema is a time consuming and error prone process. An alternate approach is to use XSD.EXE.
First, build the class using the XSD.EXE tool provided by the .NET framework.
XSD.EXE file.xsd /classes /language:[language]
The output class is as follows:
using System.Xml.Serialization;
[System.Xml.Serialization.XmlRootAttribute(
"EmpType", Namespace="", IsNullable=false)]
public class EmployeeType
{
[System.Xml.Serialization.XmlElementAttribute(
Form=System.Xml.Schema.XmlSchemaForm.Unqualified)]
public int EmployeerID;
[System.Xml.Serialization.XmlElementAttribute(
Form=System.Xml.Schema.XmlSchemaForm.Unqualified)]
public NameType Name;
[System.Xml.Serialization.XmlElementAttribute(
Form=System.Xml.Schema.XmlSchemaForm.Unqualified)]
public string SSN;
[System.Xml.Serialization.XmlElementAttribute(
Form=System.Xml.Schema.XmlSchemaForm.Unqualified)]
public AddressType CurrentAddress;
[System.Xml.Serialization.XmlElementAttribute("PreviousAddress",
Form=System.Xml.Schema.XmlSchemaForm.Unqualified)]
public AddressType[] PreviousAddress;
[System.Xml.Serialization.XmlElementAttribute(
Form=System.Xml.Schema.XmlSchemaForm.Unqualified)]
public string DriverLicense;
[System.Xml.Serialization.XmlElementAttribute("Phone",
Form=System.Xml.Schema.XmlSchemaForm.Unqualified)]
public PhoneType[] Phone;
[System.Xml.Serialization.XmlElementAttribute(
Form=System.Xml.Schema.XmlSchemaForm.Unqualified)]
public string DOB;
[System.Xml.Serialization.XmlElementAttribute(
Form=System.Xml.Schema.XmlSchemaForm.Unqualified)]
public string YOB;
}
public class NameType
{
[System.Xml.Serialization.XmlElementAttribute(
Form=System.Xml.Schema.XmlSchemaForm.Unqualified)]
public string Surname;
[System.Xml.Serialization.XmlElementAttribute(
Form=System.Xml.Schema.XmlSchemaForm.Unqualified)]
public string First;
[System.Xml.Serialization.XmlElementAttribute(
Form=System.Xml.Schema.XmlSchemaForm.Unqualified)]
public string Middle;
[System.Xml.Serialization.XmlElementAttribute(
Form=System.Xml.Schema.XmlSchemaForm.Unqualified)]
public string Gen;
}
public class PhoneType
{
[System.Xml.Serialization.XmlElementAttribute(
Form=System.Xml.Schema.XmlSchemaForm.Unqualified)]
public string Type;
[System.Xml.Serialization.XmlElementAttribute(
Form=System.Xml.Schema.XmlSchemaForm.Unqualified)]
public string Number;
}
public class AddressType
{
[System.Xml.Serialization.XmlElementAttribute(
Form=System.Xml.Schema.XmlSchemaForm.Unqualified)]
public int StreetNumber;
[System.Xml.Serialization.XmlIgnoreAttribute()]
public bool StreetNumberSpecified;
[System.Xml.Serialization.XmlElementAttribute(
Form=System.Xml.Schema.XmlSchemaForm.Unqualified)]
public string StreetName;
[System.Xml.Serialization.XmlElementAttribute(
Form=System.Xml.Schema.XmlSchemaForm.Unqualified)]
public string City;
[System.Xml.Serialization.XmlElementAttribute(
Form=System.Xml.Schema.XmlSchemaForm.Unqualified)]
public string State;
[System.Xml.Serialization.XmlElementAttribute(
Form=System.Xml.Schema.XmlSchemaForm.Unqualified)]
public string Zip;
}
If you see the file generated by the XSD.EXE tool, it has added a boolean variable StreetNumberSpecified
, which indicates whether the StreetNumber
element was supplied in the input or not. So whenever we are about to use the StreetNumber
, first we need to check StreetNumberSpecified
, and if it is true then we can use the StreetNumber
variable. Similarly, it has added a boolean variables for other elements whose minOccurs="0�
and whose data type is int
. If the data type is string
then it will not add the boolean variable that corresponds to the string
variable.
Now, add this class to your web service. Then, change the deserialization process as follows:
public string ProcessRequest (string strEMPDet)
{
try
{
string strEMPDet =
ConfigurationSettings.AppSettings.Get("XSDPath");
XmlValidatingReader vr = new
XmlValidatingReader(strEMPDet, XmlNodeType.Element);
vr.ValidationType = ValidationType.Schema;
vr.Schemas.Add( ��, strXSDFilePath );
while( vr.Read() )
{
}
}
catch( XMLException ex )
{
}
}
The validating reader class is inherited from an XML reader. The validating reader examines and validates each single piece of XML according to the requested validation type. The XmlValidatingReader
class does not explicitly provide a single method good at validating the whole content of a document, instead it validates reader works incrementally, node by node, as the underlying reader proceeds. If just write a try catch
block we can�t track all the validation errors, i.e., we can't trap all the nodes that are not following the schema. In order to track messages and detects errors (all nodes), the application must define an event handler. If a validating reader happens to work on a badly-formed XML document, no event is fired but an XmlException
exception is raised.
The handler for the event has the following signature:
public delegate void ValidationEventHandler(object sender,
ValidationEventArgs e);
The complete code is:
StringBuilder alValidationErrors =new StringBuilder();
[WebMethod]
public bool ProcessRequest(string strEMPDet)
{
EmployeeType objEmp=new EmployeeType();
try
{
string strXSDFile =
ConfigurationSettings.AppSettings.Get("XSDPath" );;
string strRequestXSDNameSpace="";
TextReader tr = (TextReader)new StringReader(strEMPDet);
XmlParserContext context = new XmlParserContext(null,
null, "", XmlSpace.None );
XmlValidatingReader vr = new
XmlValidatingReader(strEMPDet,
XmlNodeType.Element, context );
vr.ValidationType = ValidationType.Schema;
vr.Schemas.Add( strRequestXSDNameSpace, strXSDFile );
vr.ValidationEventHandler += new
ValidationEventHandler(this.ValidationEventHandle );
while( vr.Read() ){}
objEmp = ( EmployeeType ) ( new XmlSerializer(
typeof( EmployeeType ) ) ).Deserialize( tr );
}
catch( Exception ex)
{
return false;
}
return true;
}
private void ValidationEventHandle (object sender, ValidationEventArgs args)
{
alValidationErrors.Append(args.Message + Environment.NewLine);
}
With this approach, we can find out the list of all nodes that are not following the XSD.
The advantages of this approach are:
- Building the class to hold the incoming data is easy.
- Whenever there is a change in schema, we need to update the file.xsd alone, no need to change the deserialization process and rebuild the application.