Click here to Skip to main content
15,883,901 members
Articles / Programming Languages / XML
Article

Simplifying Serialization and De-serialization Processes With XSD.EXE

Rate me:
Please Sign up or sign in to vote.
2.13/5 (11 votes)
30 Jan 20062 min read 129.1K   978   31   12
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.

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.

XML
<?xml version="1.0" encoding="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:

C#
[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.

C#
///////////Syntax of xsd.exe/////////
XSD.EXE file.xsd /classes /language:[language]

The output class is as follows:

C#
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:

C#
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 )
    {
        //log exception
    }
}

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:

C#
public delegate void ValidationEventHandler(object sender, 
                     ValidationEventArgs e);

The complete code is:

C#
StringBuilder alValidationErrors =new StringBuilder();
[WebMethod]
public bool ProcessRequest(string strEMPDet)
{
    EmployeeType objEmp=new EmployeeType();
    try
    {
        string strXSDFile = 
          ConfigurationSettings.AppSettings.Get("XSDPath" );;
        string strRequestXSDNameSpace="";
        //Read in the input XML in a TextReader...
        TextReader tr = (TextReader)new StringReader(strEMPDet);
    
        //Create a validating XML reader and validate...
        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() ){}
        //Now deserialize.
        objEmp = ( EmployeeType ) ( new XmlSerializer( 
                   typeof( EmployeeType ) ) ).Deserialize( tr );
    }
    catch( Exception ex)
    {
        //logging
        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:

  1. Building the class to hold the incoming data is easy.
  2. 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.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Web Developer
United States United States
Mr.Y.M.Gopala Krishna Reddy is working as Associate in a leading MNC.His area's of intrest are ReverseEngineering,WebServices and Developing applications using DotNet.

Comments and Discussions

 
Questiona string can't be longer than 30chars, what sould I do? Pin
tapgyn31-Aug-09 10:27
tapgyn31-Aug-09 10:27 
GeneralUnable to find a version of the runtime to run this application Pin
tuxolino29-Jun-07 0:28
tuxolino29-Jun-07 0:28 
GeneralRe: Unable to find a version of the runtime to run this application Pin
Y.M.Gopala Krishna Reddy alias Murali31-Jul-07 2:23
Y.M.Gopala Krishna Reddy alias Murali31-Jul-07 2:23 
GeneralXmlIgnoreAttribute [modified] Pin
Pingu2217-May-07 4:30
Pingu2217-May-07 4:30 
GeneralRe: XmlIgnoreAttribute Pin
Y.M.Gopala Krishna Reddy alias Murali31-Jul-07 2:31
Y.M.Gopala Krishna Reddy alias Murali31-Jul-07 2:31 
GeneralPopulating the class with XML data Pin
san.diego22-Jan-07 11:34
san.diego22-Jan-07 11:34 
GeneralRe: Populating the class with XML data Pin
Y.M.Gopala Krishna Reddy alias Murali31-Jul-07 2:36
Y.M.Gopala Krishna Reddy alias Murali31-Jul-07 2:36 
QuestionIsn't this a lot of work? Pin
Jim Crafton31-Jan-06 4:00
Jim Crafton31-Jan-06 4:00 
AnswerRe: Isn't this a lot of work? Pin
BoneSoft13-Dec-06 7:25
BoneSoft13-Dec-06 7:25 
I've found that most situation that warrent XML serialization are when you have and XSD or XML in a specific format that you need to work with programatically. Or if you have a model that represents information like configuration information that you want to serialize to an XML config file. But still this does seem like the hard way to use it. And XSD.exe is not the best solution for generating code from XML or XSD. I prefer working with a tool like Skeleton Crew[^]. Then there is very little work you have to do the turn XML into object or visa-versa.



Try code model generation tools at BoneSoft.com.

QuestionYou're the famous bowler, right? Pin
gxdata30-Jan-06 19:43
gxdata30-Jan-06 19:43 
AnswerRe: You're the famous bowler, right? Pin
Y.M.Gopala Krishna Reddy alias Murali31-Jan-06 18:31
Y.M.Gopala Krishna Reddy alias Murali31-Jan-06 18:31 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.