Using XML Schema Import and Export for XmlSerializer


In a previous post, I outlined how you could import and export the XML schema for a type that you’re serializing with DataContractSerializer. Here’s how to do the same thing if you’re serializing objects with XmlSerializer:


 


static void RoundTripXmlMetadata(Type type)


{


    XmlSchemas schemas = new XmlSchemas();


    XmlSchemaExporter exporter = new XmlSchemaExporter(schemas);


 


    //Import the type as an XML mapping


    XmlTypeMapping mapping = new XmlReflectionImporter().ImportTypeMapping(type);


 


    //Export the XML mapping into schemas


    exporter.ExportTypeMapping(mapping);


 


    //Print out the schemas


    foreach (object schema in schemas)


    {


        ((XmlSchema)schema).Write(Console.Out);


        Console.WriteLine(“\n”);


    }


 


    Console.WriteLine(“——————————————-“);


 


    //Compile the schemas into one logical schema


    schemas.Compile((o, args) => Console.WriteLine(args.Message), true);


    XmlSchemaImporter importer = new XmlSchemaImporter(schemas);


 


    //Import the schema element back into an XML mapping


    mapping = importer.ImportTypeMapping(new XmlQualifiedName(mapping.ElementName, mapping.Namespace));


 


    //Create a CompileUnit and CodeNamespace to contain the generated code


    CodeCompileUnit compileUnit = new CodeCompileUnit();


    CodeNamespace compileNs = new CodeNamespace();


    compileUnit.Namespaces.Add(compileNs);


    XmlCodeExporter codeGenerator = new XmlCodeExporter(compileNs);


 


    //Export the XML mapping into code


    codeGenerator.ExportTypeMapping(mapping);


 


    //Generate C# code for the compile unit and print it out


    CSharpCodeProvider provider = new CSharpCodeProvider();


    provider.GenerateCodeFromCompileUnit(compileUnit, Console.Out, null);


}


 


I’ve tried to add comments to explain what’s happening. Essentially, we go through the following process when generating the schemas:


 


CLR type => XML mapping => Xml Schemas


 


and the following process when generating code:


 


Xml Schemas => XML mapping => C# code


 


And when we try running the type Dog defined below


 


public class Animal


{


    public int age = 4;


    public string name = “Rusty”;


}


 


public class Dog : Animal


{


    public DogBreed breed = DogBreed.LabradorRetriever;


}


 


public enum DogBreed {


    GermanShepherd,


    LabradorRetriever


}


 


Through the method, we get the following output:


 


<?xml version=”1.0″ encoding=”IBM437″?>


<xs:schema elementFormDefault=”qualified” xmlns:xs=”http://www.w3.org/2001/XMLSc


hema”>


  <xs:element name=”Dog” nillable=”true” type=”Dog” />


  <xs:complexType name=”Dog”>


    <xs:complexContent mixed=”false”>


      <xs:extension base=”Animal”>


        <xs:sequence>


          <xs:element minOccurs=”1″ maxOccurs=”1″ name=”breed” type=”DogBreed” />


        </xs:sequence>


      </xs:extension>


    </xs:complexContent>


  </xs:complexType>


  <xs:complexType name=”Animal”>


    <xs:sequence>


      <xs:element minOccurs=”1″ maxOccurs=”1″ name=”age” type=”xs:int” />


      <xs:element minOccurs=”0″ maxOccurs=”1″ name=”name” type=”xs:string” />


    </xs:sequence>


  </xs:complexType>


  <xs:simpleType name=”DogBreed”>


    <xs:restriction base=”xs:string”>


      <xs:enumeration value=”GermanShepherd” />


      <xs:enumeration value=”LabradorRetriever” />


    </xs:restriction>


  </xs:simpleType>


</xs:schema>


 


——————————————-


//——————————————————————————


 


// <auto-generated>


//     This code was generated by a tool.


//     Runtime Version:4.0.30319.1


//


//     Changes to this file may cause incorrect behavior and will be lost if


//     the code is regenerated.


// </auto-generated>


//——————————————————————————


 


 


 


 


/// <remarks/>


[System.CodeDom.Compiler.GeneratedCodeAttribute(“Serialization”, “0.0.0.0”)]


[System.SerializableAttribute()]


[System.Diagnostics.DebuggerStepThroughAttribute()]


[System.ComponentModel.DesignerCategoryAttribute(“code”)]


[System.Xml.Serialization.XmlRootAttribute(Namespace=””, IsNullable=true)]


public partial class Dog : Animal {


 


    private DogBreed breedField;


 


    /// <remarks/>


    public DogBreed breed {


        get {


            return this.breedField;


        }


        set {


            this.breedField = value;


        }


    }


}


 


/// <remarks/>


[System.CodeDom.Compiler.GeneratedCodeAttribute(“Serialization”, “0.0.0.0”)]


[System.SerializableAttribute()]


public enum DogBreed {


 


    /// <remarks/>


    GermanShepherd,


 


    /// <remarks/>


    LabradorRetriever,


}


 


/// <remarks/>


[System.Xml.Serialization.XmlIncludeAttribute(typeof(Dog))]


[System.CodeDom.Compiler.GeneratedCodeAttribute(“Serialization”, “0.0.0.0”)]


[System.SerializableAttribute()]


[System.Diagnostics.DebuggerStepThroughAttribute()]


[System.ComponentModel.DesignerCategoryAttribute(“code”)]


public partial class Animal {


 


    private int ageField;


 


    private string nameField;


 


    /// <remarks/>


    public int age {


        get {


            return this.ageField;


        }


        set {


            this.ageField = value;


        }


    }


 


    /// <remarks/>


    public string name {


        get {


            return this.nameField;


        }


        set {


            this.nameField = value;


        }


    }


}


 


Notice that the generated types look very similar to the types we started out with. In fact, as far as XmlSerializer is concerned, those types are equivalent. If you create an instance of your original class and an instance of the roundtripped class with the same values, you’ll get exactly the same XML output on the wire. That’s the guarantee that metadata roundtrips provide.

Comments (0)

Skip to main content