Another C++ XML Serialization Program Example
Create a new CLR console application. You can use the XmlSerializeCP as the project and solution names if you want.
Add the following code that includes the main(). |
|
// XmlSerializeCP.cpp : main project file. // This sample illustrates XML serialization. This sample illustrates using the // XmlSerializer class. Additionally, this sample illustrates simple // serialization as well as attribute and overriding serialization. The sample // illustrates both serialization and deserialization from a file. Note however, // a serialized file can only be deserialized using the same flags. That is if // the flag "/override" was specified during serialization, it must also be present // when deserializing. // // Usage: // executable_file_name [/serialize | /deserialize] // [/simple | /attribute | /override] [/file file.xml] // // /serialize Serialize data to XML // /deserialize Deserialize data from XML // /simple Perform simple XML serialization // /attribute Perform XML serialization with attributes // /override Perform XML serialization with overridden attributes // /file filename File name to serialize to or deserialize from // // Sample usage: // Simple XML serialization // executable_file_name /serialize /simple /file simple.xml // Simple XML deserialization // executable_file_name /deserialize /simple /file simple.xml // Serialize XML with overridden attributes // executable_file_name /serialize /override /file override.xml // Deserialize XML with overridden attributes // executable_file_name /deserialize /override /file override.xml //
#include "stdafx.h"
using namespace System; using namespace System::IO; using namespace System::Xml::Serialization; using namespace System::Data;
/// <summary> /// Simple enumeration for the operation to perform: deserialization or serialization. /// </summary> enum class SerializeOperation { opRead, // Deserialize opWrite // Serialize };
/// <summary> /// Enumeration indicating which class to serialize. /// </summary> enum class SerializeClass { classSimple, classAttribute, classOverride };
/// <summary> /// This is a simple helper class which creates a DataSet and initializes some data /// within it. The DataSet is an address book with two data columns: name and phone number. /// </summary> public ref class XmlAddressBookData { public: static DataSet^ CreateAddressBook() { DataSet^ addressBook; DataTable^ friendsTable; DataColumn^ infoColumn; DataRow^ friendEntry;
// Create a collection, first create the dataset and then the table contained in the dataset Console::WriteLine("Creating a collection..."); addressBook = gcnew DataSet("AddressBook"); friendsTable = gcnew DataTable("Friends");
// Add columns to the data set Console::WriteLine("Adding columns..."); infoColumn = gcnew DataColumn("Name"); friendsTable->Columns->Add(infoColumn); infoColumn = gcnew DataColumn("Number"); friendsTable->Columns->Add(infoColumn); addressBook->Tables->Add(friendsTable);
// Add a few entries to the collection Console::WriteLine("Adding entries..."); friendEntry = friendsTable->NewRow(); friendEntry[0] = "Jim"; friendEntry[1] = "867-5309"; friendsTable->Rows->Add(friendEntry);
friendEntry = friendsTable->NewRow(); friendEntry[0] = "Lance"; friendEntry[1] = "555-4567"; friendsTable->Rows->Add(friendEntry);
friendEntry = friendsTable->NewRow(); friendEntry[0] = "Anthony"; friendEntry[1] = "555-1234"; friendsTable->Rows->Add(friendEntry);
return addressBook; }
/// <summary> /// Routine for displaying the contents of the address book. /// </summary> /// <param name="addressBook">Dataset to print</param> public: static void PrintAddressBook(DataSet^ addressBook) { for each (DataTable^ table in addressBook->Tables) { for each (DataRow^ row in table->Rows) { Console::WriteLine("Name {0}: {1}", row["Name"], row["Number"]); } } } };
/// <summary> /// Simple data structure to be serialize using the XML formatter. This structure contains a collection. /// </summary> public ref class MyXmlSimpleData { public: // Preventing the DateTime class from serialization // XmlSerializer will skip over it. It is failed to serialize DateTime in C++/CLI // Use [XmlIgnore] attribute instead for the XmlSerializer to simply ignore this field. [XmlIgnoreAttribute] DateTime^ CurrentDate; DataSet^ MyAddressBook; array<String^>^ DaysOfTheWeek;
// Private properties won't be serialized private: int MySalary;
/// <summary> /// Default constructor for the MyXmlSimplData class which initializes /// the fields and builds a simple collection of names and phone numbers. /// </summary> public: MyXmlSimpleData() { CurrentDate = DateTime::Today; MySalary = 0; MyAddressBook = XmlAddressBookData::CreateAddressBook();
DaysOfTheWeek = gcnew array<String^>(7); DaysOfTheWeek[0] = "Sunday"; DaysOfTheWeek[1] = "Monday"; DaysOfTheWeek[2] = "Tuesday"; DaysOfTheWeek[3] = "Wednesday"; DaysOfTheWeek[4] = "Thursday"; DaysOfTheWeek[5] = "Friday"; DaysOfTheWeek[6] = "Saturday"; }
/// <summary> /// Simple method to set the private fields value. /// </summary> public: void SetSalary(int data) { MySalary = data; }
/// <summary> /// Displays the values of all member variables including the collection. /// </summary> public: void Print() { Console::WriteLine("MyXmlSimpleData::CurrentDate = {0}", CurrentDate); XmlAddressBookData::PrintAddressBook( MyAddressBook ); Console::WriteLine("MyXmlSimpleData::MySalary = {0}", MySalary);
for(int i=0; i < DaysOfTheWeek->Length ;i++) { Console::WriteLine("DaysOfTheWeek[{0}] = {1}", i, DaysOfTheWeek[i]); } }
/// <summary> /// This routine overrides the default serialization by changing the element name /// for a member variable when it is serialized. This is typically used when the /// same data needs to be serialized to XML with differing XML attributes. /// </summary> /// <param name="fileStream">The FileStream object to serialize the data to</param> public: void OverrideSerialization( FileStream^ fileStream ) { XmlElementAttribute^ xmlElementAttribute = gcnew XmlElementAttribute(); XmlAttributes^ xmlAttributes = gcnew XmlAttributes(); XmlAttributeOverrides^ xmlAttributeOverrides = gcnew XmlAttributeOverrides(); XmlSerializer^ xmlSerializer = nullptr;
// Override the element name for the "CurrentDate" property // Setting XmlIgnore to false overrides the XmlIgnoreAttribute // applied to the "CurrentDate" field, thus it will be serialized and vice versa xmlElementAttribute->ElementName = "Override_Current_Date"; xmlAttributes->XmlIgnore = true; xmlAttributes->XmlElements->Add( xmlElementAttribute ); xmlAttributeOverrides->Add( MyXmlSimpleData::typeid, "CurrentDate", xmlAttributes );
// Serialize the class except specify the XmlAttributeOverrides object as well xmlSerializer = gcnew XmlSerializer( MyXmlSimpleData::typeid, xmlAttributeOverrides );
try { Console::WriteLine("Serializing an overridden class..."); xmlSerializer->Serialize( fileStream, this ); } catch ( InvalidOperationException^ err ) { Console::WriteLine("Serialization of overridden class failed: {0}", err->Message); } } };
/// <summary> /// This class illustrates declaring XML attributes along with the class definition. /// These attributes affect how the data is serialized to XML. /// </summary> public ref class MyXmlAttributeData { public: // Using Attributes That Control XML Serialization // http://msdn.microsoft.com/en-us/library/83y7df3e(VS.71).aspx [ XmlElement( ElementName = "_1394Type" )] int FireWireType;
public: // Using Attributes That Control XML Serialization [ XmlArray( "SupportedDevices" ), XmlArrayItem( "_1394Device" ) ] array<String^>^ SupportedDevices;
/// <summary> /// Simple constructor to initialize member variables /// </summary> public: MyXmlAttributeData() { FireWireType = 1;
SupportedDevices = gcnew array<String^>(5); SupportedDevices[0] = "scanner"; SupportedDevices[1] = "camcorder"; SupportedDevices[2] = "mp3 player"; SupportedDevices[3] = "IPhone"; SupportedDevices[4] = "USB drive"; }
/// <summary> /// Prints the class members to the console /// </summary> public: void Print() { Console::WriteLine("MyXmlAttributeData::FireWireType = {0}", FireWireType); for(int i=0; i < SupportedDevices->Length ;i++) { Console::WriteLine("MyXmlAttributeData::SupportedDevices[{0}] = {1}", i, SupportedDevices[i]); } } };
/// <summary> /// This is the class which contains the support routines. /// </summary> public ref class XmlSerializeSample { /// <summary> /// Displays usage information /// </summary> public: static void usage() { Console::WriteLine("executable_file_name [/serialize | /deserialize]"); Console::WriteLine(" [/simple | /attribute | /override] [/file file.xml]"); Console::WriteLine("Available options:"); Console::WriteLine(" /serialize Serialize data to XML"); Console::WriteLine(" /deserialize Deserialize data from XML"); Console::WriteLine(" /simple Perform simple XML serialization"); Console::WriteLine(" /attribute Perform XML serialization with attributes"); Console::WriteLine(" /override Perform XML serialization with overridden attributes"); Console::WriteLine(" /file filename File name to serialize to or deserialize from"); Console::WriteLine(); }
};
/// <summary> /// Main routine that parses the command line, creates the select file stream, and /// serializes or deserializes the indicated class. /// </summary> /// <param name="args">Command line parameters passed to application</param> int main(array<System::String ^> ^args) { SerializeOperation serializeOp = SerializeOperation::opWrite; SerializeClass serializeClass = SerializeClass::classSimple; // A default file name String^ fileName = "simpletest.xml";
// Parse the command line if(args->Length != 0) { for (int i = 0; i < args->Length; i++) { if (String::Compare(args[i], "/serialize", true) == 0) { serializeOp = SerializeOperation::opWrite; } else if (String::Compare(args[i], "/deserialize", true) == 0) { serializeOp = SerializeOperation::opRead; } else if (String::Compare(args[i], "/file", true) == 0) { try { fileName = args[++i]; } catch (IndexOutOfRangeException^) { Console::WriteLine("Please specify output filename!\n"); XmlSerializeSample::usage(); } } else if (String::Compare(args[i], "/simple", true) == 0) { serializeClass = SerializeClass::classSimple; } else if (String::Compare(args[i], "/attribute", true) == 0) { serializeClass = SerializeClass::classAttribute; } else if (String::Compare(args[i], "/override", true) == 0) { serializeClass = SerializeClass::classOverride; } else { XmlSerializeSample:: usage(); return 0; } } } else { XmlSerializeSample:: usage(); return 0; }
FileStream^ fileStream = nullptr; XmlSerializer^ xmlSerializer = nullptr;
try { // Create an instance of the FileStream on which serialization or deserialization will take place. if (serializeOp == SerializeOperation::opWrite) { String^ s = "hello"; array<Byte>^ data = Text::Encoding::ASCII->GetBytes(s->ToCharArray()); fileStream = gcnew FileStream( fileName, FileMode::Create, FileAccess::Write, FileShare::None ); fileStream->Write(data, 0, 0); Console::WriteLine("Writing is OK, filename is " + fileName); } else if (serializeOp == SerializeOperation::opRead) { fileStream = gcnew FileStream( fileName, FileMode::Open, FileAccess::Read, FileShare::Read ); Console::WriteLine("Reading is OK..."); }
if (serializeOp == SerializeOperation::opWrite) { // If serialization (writing) is selected, we need to create an instance // of the class which will be serialized to the stream. if (serializeClass == SerializeClass::classSimple) { // Create an instance of the simple class MyXmlSimpleData^ simpleData = nullptr; simpleData = gcnew MyXmlSimpleData(); xmlSerializer = gcnew XmlSerializer(MyXmlSimpleData::typeid);
try { Console::WriteLine("Serializing a simple class..."); xmlSerializer->Serialize(fileStream, simpleData); } catch (InvalidOperationException^ err) { Console::WriteLine("Serialization of simple class failed: {0}", err->Message); } } else if (serializeClass == SerializeClass::classAttribute) { // Create an instance of the class containing XML attributes MyXmlAttributeData^ attributeData = nullptr; attributeData = gcnew MyXmlAttributeData(); xmlSerializer = gcnew XmlSerializer(MyXmlAttributeData::typeid);
try { Console::WriteLine("Serializing an attributed class..."); xmlSerializer->Serialize(fileStream, attributeData); } catch (InvalidOperationException^ err) { Console::WriteLine("Serialization of attributed class failed: {0}", err->Message); } } else if (serializeClass == SerializeClass::classOverride) { // Create an instance of the class which has its own override method // and call that method to serialize the data. MyXmlSimpleData^ simpleData = nullptr; simpleData = gcnew MyXmlSimpleData(); simpleData->OverrideSerialization(fileStream); } } else if (serializeOp == SerializeOperation::opRead) { // If deserialization (reading) is selected, simply create an instance // of the XmlSerializer for the type being serialized and call the deserialize method. if (serializeClass == SerializeClass::classSimple) { MyXmlSimpleData^ simpleData = nullptr; xmlSerializer = gcnew XmlSerializer(MyXmlSimpleData::typeid);
try { Console::WriteLine("De-serializing a simple class..."); simpleData = (MyXmlSimpleData^)xmlSerializer->Deserialize(fileStream); simpleData->Print(); } catch (InvalidOperationException^ err) { Console::WriteLine("Deserialization of simple class failed: {0}", err->Message); } } else if ((serializeClass == SerializeClass::classAttribute) || (serializeClass == SerializeClass::classOverride)) { MyXmlAttributeData^ attributeData = nullptr; xmlSerializer = gcnew XmlSerializer(MyXmlAttributeData::typeid);
try { Console::WriteLine("De-serializing an overriding/attributed class..."); attributeData = (MyXmlAttributeData^)xmlSerializer->Deserialize(fileStream); attributeData->Print(); } catch (InvalidOperationException^ err) { Console::WriteLine("Deserialization of overriding/attributed class failed: {0}", err->Message); } } } } catch(Exception^ err) { Console::WriteLine("Error lor! -->" + err->Message); }
// Close up try { Console::WriteLine("Closing FileStream..."); fileStream->Close(); } catch (Exception^ err) { Console::WriteLine("Error closing FileStream..." + err->Message); } return 0; } |
Build and run the project.

The following are the output samples when the program run at the command prompt.
![]() |


Well, we have some error as seen in the above screenshot when deserializing the overriding and the details is shown below. It is left for your exercise and please take sometime to solve it.
|
Unhandled Exception: System.InvalidOperationException: There is an error in XML document (2, 2). ---> System.InvalidOperationException: <MyXmlSimpleData xmlns=''> was not expected. at Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationReaderMyXmlAttributeData.Read3_MyXmlAttributeData() --- End of inner exception stack trace --- at System.Xml.Serialization.XmlSerializer.Deserialize(XmlReader xmlReader, String encodingStyle, XmlDeserializationEvents events) at System.Xml.Serialization.XmlSerializer.Deserialize(XmlReader xmlReader, String encodingStyle) at System.Xml.Serialization.XmlSerializer.Deserialize(Stream stream) at main(String[ ] args) at mainCRTStartupStrArray(String[ ] arguments) |
The following is the generated XML file opened in the Internet browser.
