Using the XmlSerializer, you can generate more than one XML stream with the same set of classes. You might want to do this because two different XML Web services require the same basic information, with only slight differences. For example, imagine two XML Web services that process orders for books, and thus both require ISBN numbers. One service uses the tag <ISBN> while the second uses the tag <BookID>. You have a class named Book that contains a field named ISBN. When an instance of the Book class is serialized, it will, by default, use the member name (ISBN) as the tag element name. For the first XML Web service, this is as expected. But to send the XML stream to the second XML Web service, you must override the serialization so that the tag's element name is BookID.
Create an instance of the XmlElementAttribute class.
Set the ElementName of the XmlElementAttribute to "BookID".
Create an instance of the XmlAttributes class.
Add the XmlElementAttribute object to the collection accessed through the XmlElements property of XmlAttributes .
Create an instance of the XmlAttributeOverrides class.
Add the XmlAttributes to the XmlAttributeOverrides, passing the type of the object to override and the name of the member being overridden.
Create an instance of the XmlSerializer class with XmlAttributeOverrides.
Create an instance of the Book class, and serialize or deserialize it.
public class SerializeOverride() { // Creates an XmlElementAttribute with the alternate name. XmlElementAttribute myElementAttribute = new XmlElementAttribute(); myElementAttribute.ElementName = "BookID"; XmlAttributes myAttributes = new XmlAttributes(); myAttributes.XmlElements.Add(myElementAttribute); XmlAttributeOverrides myOverrides = new XmlAttributeOverrides(); myOverrides.Add(typeof(Book), "ISBN", myAttributes); XmlSerializer mySerializer = new XmlSerializer(typeof(Book), myOverrides) Book b = new Book(); b.ISBN = "123456789" // Creates a StreamWriter to write the XML stream to. StreamWriter writer = new StreamWriter("Book.xml"); mySerializer.Serialize(writer, b); }
The XML stream might resemble the following.
<Book> <BookID>123456789</BookID> </Book>
Using the XmlElementAttribute attribute to change the name of an XML element is not the only way to customize object serialization. You can also customize the XML stream by deriving from an existing class and instructing the XmlSerializerinstance how to serialize the new class.
For example, given a Book class, you can derive from it and create an ExpandedBook class that has a few more properties. However, you must instruct the XmlSerializer to accept the derived type when serializing or deserializing. This can be done by creating a XmlElementAttribute instance and setting its Type property to the derived class type. Add theXmlElementAttribute to a XmlAttributes instance. Then add the XmlAttributes to a XmlAttributeOverrides instance, specifying the type being overridden and the name of the member that accepts the derived class. This is shown in the following example.
public class Orders { public Book[] Books; } public class Book { public string ISBN; } public class ExpandedBook:Book { public bool NewEdition; } public class Run { public void SerializeObject(string filename) { // Each overridden field, property, or type requires // an XmlAttributes instance. XmlAttributes attrs = new XmlAttributes(); // Creates an XmlElementAttribute instance to override the // field that returns Book objects. The overridden field // returns Expanded objects instead. XmlElementAttribute attr = new XmlElementAttribute(); attr.ElementName = "NewBook"; attr.Type = typeof(ExpandedBook); // Adds the element to the collection of elements. attrs.XmlElements.Add(attr); // Creates the XmlAttributeOverrides instance. XmlAttributeOverrides attrOverrides = new XmlAttributeOverrides(); // Adds the type of the class that contains the overridden // member, as well as the XmlAttributes instance to override it // with, to the XmlAttributeOverrides. attrOverrides.Add(typeof(Orders), "Books", attrs); // Creates the XmlSerializer using the XmlAttributeOverrides. XmlSerializer s = new XmlSerializer(typeof(Orders), attrOverrides); // Writing the file requires a TextWriter instance. TextWriter writer = new StreamWriter(filename); // Creates the object to be serialized. Orders myOrders = new Orders(); // Creates an object of the derived type. ExpandedBook b = new ExpandedBook(); b.ISBN= "123456789"; b.NewEdition = true; myOrders.Books = new ExpandedBook[]{b}; // Serializes the object. s.Serialize(writer,myOrders); writer.Close(); } public void DeserializeObject(string filename) { XmlAttributeOverrides attrOverrides = new XmlAttributeOverrides(); XmlAttributes attrs = new XmlAttributes(); // Creates an XmlElementAttribute to override the // field that returns Book objects. The overridden field // returns Expanded objects instead. XmlElementAttribute attr = new XmlElementAttribute(); attr.ElementName = "NewBook"; attr.Type = typeof(ExpandedBook); // Adds the XmlElementAttribute to the collection of objects. attrs.XmlElements.Add(attr); attrOverrides.Add(typeof(Orders), "Books", attrs); // Creates the XmlSerializer using the XmlAttributeOverrides. XmlSerializer s = new XmlSerializer(typeof(Orders), attrOverrides); FileStream fs = new FileStream(filename, FileMode.Open); Orders myOrders = (Orders) s.Deserialize(fs); Console.WriteLine("ExpandedBook:"); // The difference between deserializing the overridden // XML document and serializing it is this: To read the derived // object values, you must declare an object of the derived type // and cast the returned object to it. ExpandedBook expanded; foreach(Book b in myOrders.Books) { expanded = (ExpandedBook)b; Console.WriteLine( expanded.ISBN + "\n" + expanded.NewEdition); } } }
serialization xml:
<?xml version="1.0" encoding="utf-8"?> <Orders xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <NewBook> <ISBN>123456789</ISBN> <NewEdition>true</NewEdition> </NewBook> </Orders>
the second way is decorating the class with the attributes under the System.Xml.Serialization.
This example includes a utility class with 2 important methods - DeserializeObject and SerializeObject. Both use generics so you pass the target class when calling either method. The XML sample can be deserialized to create a Person object. Alternatively, an existing Person object can be serialized to create a similar XML structure.
using System; using System.IO; using System.Text; using System.Xml; using System.Xml.Serialization; public class XMLSerializationUtility { public static T DeserializeObject<T>( Encoding encoding, string xml ) { try { using (MemoryStream memoryStream = new MemoryStream( StringToByteArray( encoding, xml ) ) ) { using ( XmlTextWriter xmlTextWriter = new XmlTextWriter( memoryStream, encoding ) ) { XmlSerializer xmlSerializer = new XmlSerializer( typeof( T ) ); return (T)xmlSerializer.Deserialize( memoryStream ); } } } catch { return default( T ); } } public static string SerializeObject<T>( Encoding encoding, T obj ) { try { MemoryStream memoryStream = new MemoryStream(); using ( XmlTextWriter xmlTextWriter = new XmlTextWriter( memoryStream, encoding ) ) { XmlSerializer xmlSerializer = new XmlSerializer( typeof( T ) ); xmlSerializer.Serialize( xmlTextWriter, obj ); memoryStream = (MemoryStream)xmlTextWriter.BaseStream; } return ByteArrayToString( encoding, memoryStream.ToArray() ); } catch { return string.Empty; } } private static Byte[] StringToByteArray( Encoding encoding, string xml ) { return encoding.GetBytes( xml ); } private static string ByteArrayToString( Encoding encoding, byte[] byteArray ) { return encoding.GetString( byteArray ); } } Person class: using System; using System.Xml.Serialization; [XmlRoot( "person" ) ] public class Person { private Guid _id; [XmlAttribute( "id" )] public Guid ID; { get { return _id; } set { _id = value; } } private string _name; [XmlElement( "Name" )] public string Name; { get { return _name; } set { _name = value; } } private DateTime _dateOfBirth; [XmlElement( "dob" )] public DateTime DateOfBirth; { get { return _dateOfBirth; } set { _dateOfBirth = value; } } }
xml is just as following.
<?xml version="1.0" encoding="utf-8"?> <person id="0ADD2974-B14E-440B-B435-C0AF65E57ACF"> <name>Andrew Gunn</name> <dob>1985-08-08T12:00:00Z</dob> </person>
//Deserialize string XML into a Person object Person person = XMLSerializationUtility.DeserializeObject<Person>( Encoding.UTF8, xml ); //Serialize a Person object into string XML string xml = XMLSerializationUtility.SerializeObject<Person>( Encoding.UTF8, Person );