Wednesday, November 13, 2013

C# XmlSerialization - Generating XSD from XML, Classes from XSD, Serializing Array of Custom Type and Enumerations etc

Generating XSD from XML:



XSD.exe tool can be used to generate schema file from an XML file. XSD.exe will be available with Visual Studio installation. 


  • Open Visual Studio Command Prompt 
  • Type in the command "xsd <xml file name(including path) to be used for schema generation>"
  • Done. XSD gets generated in the same folder where you XSD command is executed.
Now you have the XSD, What next? 

Note: Generated XSD might not be exactly what you want. It is only according to the XML provided. Enumeration Types or Complex Types might not be created in XSD as you are expecting. Example: Printer Type below looks like an enumeration field, but it isn't obvious from the given XML file.

Example XML File:

<XmlSerializable xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
   <Printers>
      <Printer Name="Denali" Type="Mfp"/>
      <Printer Name="Garnet" Type="NetworkScanner"/>
   </Printers>
</XmlSerializable>



Generate XSD File:

<?xml version="1.0" encoding="utf-8"?>
<xs:schema id="XmlSerializable" xmlns="" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
  <xs:element name="XmlSerializable" msdata:IsDataSet="true" msdata:UseCurrentLocale="true">
    <xs:complexType>
      <xs:choice minOccurs="0" maxOccurs="unbounded">
        <xs:element name="Printers">
          <xs:complexType>
            <xs:sequence>
              <xs:element name="Printer" minOccurs="0" maxOccurs="unbounded">
                <xs:complexType>
                  <xs:attribute name="Name" type="xs:string" />
                  <xs:attribute name="Type" type="xs:string" />
                </xs:complexType>
              </xs:element>
            </xs:sequence>
          </xs:complexType>
        </xs:element>
      </xs:choice>
    </xs:complexType>
  </xs:element>
</xs:schema>


Generate Class from XSD(Schema file):



Again, XSD utility is our buddy here. Run XSD tool with /classes options and provided XSD generated in previous step as input. There you go, XSD generates classes for you.

Auto generated class will have properties and classes generated the way those were present in XSD. In above example, There would be three classes generated, one "XmlSerializable" element, another for element Printers and another for element Printer. Each of these types will "contain" other type as defined by complex types in XSD. 


That said, most of the day to day development activities involve writing classes by serializable by ourselves instead of defining XSDs.  Let's see in brief about how to write xml serializable class in C#.



Coding a Serializable class:



[Everything pertaining to xml serialization is available under the namespace " System.Xml.Serialization"]

Create a class with properties for data that you want to contain in that class. Each of these property can again be a type that is serializable. Attributes on the top of properties control the way the data gets serialized or organized in the XML file. You can find the complete list of attributes available here. Each type which is part of another serializable type can be thought of as Complex type in XSD.

Note: Adding wrong attributes may result in a different xml than what you expect. Read through use the attributes list and their usage for creating serializable class

Example: Marking a property as XmlArray indicates that the property will hold array of items,where you need also to mark the item type by specifying XmlArrayItem.

Enumeration values can be marked by attribute "XmlEnum". Serializer will then place the Enumeration Type in place of Enumeration value in the Serialized Xml.

Steps involved in serialization:
  1. Create a XML Serializer isntance by proving the type which you are intending to serialize.
  2. Open a stream to the ouput xml file.
  3. Provide this stream and instance to the serialize method of serializer instance created.
  4. Close the stream and serialized data will be in output file mentioned in step 2.
Serializing Code :

XmlSerializable x = new XmlSerializable();
            x.Printers = new Printer[2];

            x.Printers[0] = new Printer();
            x.Printers[0].Type = PrinterType.Mfp;
            x.Printers[0].Name = "Denali";

            x.Printers[1] = new Printer();
            x.Printers[1].Type = PrinterType.NetworkScanner;
            x.Printers[1].Name = "Garnet";

            XmlSerializer serializer = new XmlSerializer(typeof(XmlSerializable));
            XmlWriter writer = XmlWriter.Create("D:\\output.xml");
            serializer.Serialize(writer,x);
            writer.Close();

Serializable Class example which covers serializing a class which contains array of other class type and also enumerations:



    [Serializable]
    [XmlRoot()]
    public class XmlSerializable
    {
        Printer[] printers;

        [XmlArray("Printers")]
        [XmlArrayItem("Printer")] 
        public Printer[] Printers
        {
            get
            {
                return printers;
            }
            set
            {
                printers = value;
            }
        }
    }
   
    [XmlType("Printer")]         
    public class Printer
    {
        PrinterType type;

        [XmlAttribute()]

        public PrinterType Type
        {
            get
            {
                return type;
            }
            set
            {
                type = value;
            }
        }

        [XmlAttribute()]
        public string Name;


    }
 
    public enum PrinterType
    {
        [XmlEnum]
        None =0,
        [XmlEnum]
        Mfp,
        [XmlEnum]
        Sfp,
        [XmlEnum]
        NetworkScanner
    }

No comments:

Post a Comment