Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / XML

Tiny XML Serializer for C++

4.86/5 (9 votes)
13 Feb 2014CPOL1 min read 46.1K   2K  
Simple and lightweight XML Serialization using tinyxml2

Introduction 

I was looking for a lightweight and easy to use XML Serialization library for C++.
Mainly for simple tasks like to store application settings or to send messages.
After looking around I found a few candidates. But most of them are too complicated or to heavy.
I thought there must be a simple solution, without defining a bulk of interfaces or helper classes.

How it works  

Creating serializable classes is pretty simple and straightforward.  

  1. Derive you class from "Serializeable"
  2. Add members
    Members can be basic types like xString, xInt, xBool
    or complex types like member classes or collections of member classes.
  3. Register members in the constructor

 

Features    

  • Serialization / Deserialization   
  • Member-Classes  
  • Member-Collections    
  • Copy / Clone objects
  • Compare objects
  • Find / Replace values
  • Complete code in 1 header and 1 code file (+tinyxml2)    

Using the code  

Let's have a look at the example "application settings":
The first step is to define your class containing all needed setting values.
As you can see, serializeable members are defined as xString, xInt, xBool...
All other types are allowed, of course. They are simply ignored during the serialization process.

C++
class ApplicationSettings: public Serializable
{
public:
    ApplicationSettings();    
    xString Setting1;    
    xString Setting2;
    xString Setting3;
    xInt Setting4;
    xInt Setting5;
    xBool Setting6;
    xTime_t Setting7;
};

The second step is to register all x-members for serialization.
This is usually done in the constructor: 

C++
ApplicationSettings::ApplicationSettings():
    Setting1("Default string value"), // init default values here
    Setting4(1234)
{
    // Set the XML class name.
    // This name can differ from the C++ class name
    setClassName("ApplicationSettings");
 
    // Set class version
    setVersion("2.1");
 
    // Register members. Like the class name, member names can differ from their xml depandants
    Register("Setting1", &Setting1);
    Register("Setting2", &Setting2);
    Register("Setting3", &Setting3);
    Register("Setting4", &Setting4);
    Register("Setting5", &Setting5);
    Register("Setting6", &Setting6);
    Register("Setting7", &Setting7);
}; 

Set and access member values in your code:

C++
ApplicationSettings *settings=new ApplicationSettings; // Create new object
    settings->Setting1="Settings string 1"; // set new values
    settings->Setting2="Settings string 2";
    settings->Setting3="Settings string 3";
    settings->Setting4=1234;
    settings->Setting5=5678;
    settings->Setting6=false;
    settings->Setting7=true; 
 
    std::string strValue = settings->Setting1.value();
    int intValue = settings->Setting4.value();

Serialize the class to string:

C++
std::string xmlData = settings->toXML();

XML - Result: 

XML
<SerializableClass Type="ApplicationSettings" Version="2.1">
    <Member Name="Setting1">Settings string 1</Member>
    <Member Name="Setting2">Settings string 2</Member>
    <Member Name="Setting3">Settings string 3</Member>
    <Member Name="Setting4">1234</Member>
    <Member Name="Setting5">5678</Member>
    <Member Name="Setting6">false</Member>
    <Member Name="Setting7">true</Member>
</SerializableClass>  

Deserialize from string:

C++
ApplicationSettings* dser_Settings=new ApplicationSettings; // Create new object
if (Serializable::fromXML(xmlData, dser_Settings) // perform deserialization
{
    // Deserialization successful
    cout << dser_Settings->Setting1.value() << endl; // get the value in original data format
    cout << dser_Settings->Setting1.toString() << endl; // get the value as string
}

Member Classes and Collections

Additionally we want to store database login and a list of used document items:

C++
// Define collection-item class:
class LastUsedDocument: public Serializable
{
public:
    LastUsedDocument();
    xString Name;
    xString Path;
    xInt Size;
};
 
// Define member class
class DatabaseLogin: public Serializable
{
public:
    DatabaseLogin();
    xString HostName;
    xInt Port;
    xString User;
    xString Password;
}; 
 
// Register member's 
LastUsedDocument::LastUsedDocument()
{
    setClassName("LastUsedDocument"); 
    Register("Name", &Name);
    Register("Path", &Path);
    Register("Size", &Size);
};
 
DatabaseLogin::DatabaseLogin()
{
    setClassName("DatabaseLogin");
    Register("HostName", &HostName);
    Register("Port", &Port);
    Register("User", &User);
    Register("Password", &Password);
};    

The updated ApplicationSettings class definition including document collection and login data.

C++
class ApplicationSettings: public Serializable
{
public:
    ApplicationSettings();
    xString Setting1;
    xString Setting2;
    xString Setting3;
    xInt Setting4;
    xInt Setting5;
    xBool Setting6;
    xBool Setting7;
    DatabaseLogin Login; // Define Member-Class
    Collection<LastUsedDocument> LastUsedDocuments; // Define Last-Doc collection
};  

ApplicationSettings::ApplicationSettings()
{
...
    Register("Setting7", &Setting7);
    Register("Login", &Login); // Register Member-Class
    Register("LastUsedDocuments", &LastUsedDocuments); // Register collection
}

Using member classes and collections:

C++
// Member class:
cout << "Login, URL:" << endl;
cout << "Hostname: " << settings->Login.HostName.value();
cout << ":" << settings->Login.Port.value() << endl;
// Member collection
cout << "Show all collection items" << endl;
for (size_t i=0; i<settings->LastUsedDocuments.size(); i++)
{
    LastUsedDocument* doc = settings->LastUsedDocuments.getItem(i);
    cout << "Item " << i << ": " << doc->Name.value() << endl;
} 

Final XML:

XML
<SerializableClass Type="ApplicationSettings" Version="2.1">
    <Member Name="Setting1">Settings string 1</Member>
    <Member Name="Setting2">Settings string 2</Member>
    <Member Name="Setting3">Settings string 3</Member>
    <Member Name="Setting4">1234</Member>
    <Member Name="Setting5">5678</Member>
    <Member Name="Setting6">false</Member>
    <Member Name="Setting7">true</Member>
    <Class Name="Login" Type="DatabaseLogin" Version="1">
        <Member Name="HostName">my.db.Settings.server.local</Member>
        <Member Name="Port">2000</Member>
        <Member Name="User">john.smith</Member>
        <Member Name="Password">newPassword</Member>
    </Class>
    <Collection Name="LastUsedDocuments">
        <Class Type="LastUsedDocument" Version="1">
            <Member Name="Name">Document #1</Member>
            <Member Name="Path">c:\temp\</Member>
            <Member Name="Size"></Member>
        </Class>
        <Class Type="LastUsedDocument" Version="1">
            <Member Name="Name">Document #2</Member>
            <Member Name="Path">c:\temp\</Member>
            <Member Name="Size"></Member>
        </Class>
        <Class Type="LastUsedDocument" Version="1">
            <Member Name="Name">Document #3</Member>
            <Member Name="Path">c:\temp\</Member>
            <Member Name="Size"></Member>
        </Class>
        <Class Type="LastUsedDocument" Version="1">
            <Member Name="Name">Document #4</Member>
            <Member Name="Path">c:\temp\</Member>
            <Member Name="Size"></Member>
        </Class>
        <Class Type="LastUsedDocument" Version="1">
            <Member Name="Name">Document #5</Member>
            <Member Name="Path">c:\temp\</Member>
            <Member Name="Size"></Member>
        </Class>
    </Collection>
</SerializableClass>

Tools 

Compare objects
// compare all fields, member classes and collections
if (object_1->Compare(object_2))
    cout << "equal" << endl; else
    cout << "net equal" << endl; 
Clone/Copy objects
// copy all fields, member classes and collections
ApplicationSettings *destination=new ApplicationSettings;
Serializable::Clone(source, destination);
Find/Replace
// find/replace, also recursiv
settings->Replace("{FILEPATH}", "c:\\temp\\");

Other frameworks

If you need a complete XML framework, have a look at Brian Aberle's XMLFoundation.
Nice Article!

History    

Version 1.0: Initial publication.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)