Click here to Skip to main content
15,881,757 members
Articles / Programming Languages / XML
Tip/Trick

Tiny XML Serializer for C++

Rate me:
Please Sign up or sign in to vote.
4.86/5 (9 votes)
13 Feb 2014CPOL1 min read 44.9K   1.9K   21   5
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)


Written By
p++ Datentechnik GmbH
Germany Germany
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
PraiseThank you! Pin
Member 1354615929-Dec-17 10:31
Member 1354615929-Dec-17 10:31 
QuestionSerialize/Deserialize COBList Pin
orna791113-Jun-17 11:13
orna791113-Jun-17 11:13 
Questionxmls types Pin
Rafal Rebisz21-Feb-15 14:06
Rafal Rebisz21-Feb-15 14:06 
Hi can you tell me how should treat xmls types should I use them as types for my object or should I store them in my object along with other types and use them only to parse data ?
Questionsmall addition Pin
WHAK.com1-Jan-15 12:22
professionalWHAK.com1-Jan-15 12:22 
Questionthat's perfect! Pin
Member 111699872-Dec-14 22:55
Member 111699872-Dec-14 22:55 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.