Object serialization using XTI and XML

From WxWiki

Jump to: navigation, search

This page demonstrates how an object with properties can be saved to an XML file, and later reloaded. The code below makes use of the XTI features of wxWidgets.

Note: for the code below to work, you must build your wx library with wxUSE_EXTENDED_RTTI set to 1 (in setup.h).


Contents

[edit] person.h

Here is the complete code of a simple person class that has an Age property:

person.h
#ifndef _WX_PERSON_H_
#define _WX_PERSON_H_
 
#include "wx/object.h"
 
class wxPerson : public wxObject
{
public:
	wxPerson( const int age) { Create(age); }
	virtual ~wxPerson() {}
 
	void Create(const int age = 0) { m_Age = age; }
 
private:
	wxIMPLEMENT_PROPERTY(Age, int)
	DECLARE_DYNAMIC_CLASS(wxPerson)
};
 
#endif // _WX_PERSON_H_ 

[edit] Notes

  • Notice that your class MUST have a Create method.

[edit] wxIMPLEMENT_PROPERTY

wxIMPLEMENT_PROPERTY is a helper implementation for the simple properties whose setters and getters involve nothing but the obvious. Notice that in the code above, this macro:

wxIMPLEMENT_PROPERTY(Age, int)

will be replaced by the preprocessor with this code:

public:
	void SetAge(int const p) { m_Age = p; }
	int const GetAge() const { return m_Age; }
private:
	int m_Age;

You might wish NOT to use wxIMPLEMENT_PROPERTY if you want to implement more complex setters and getters.

[edit] person.cpp

Since both the constructor and the Create methods are implemented in the header file, the implementation code looks like so:

person.cpp
#include "person.h"
 
#if wxUSE_EXTENDED_RTTI
	IMPLEMENT_DYNAMIC_CLASS_XTI(wxPerson, wxObject, "person.h")	
 
	wxBEGIN_PROPERTIES_TABLE(wxPerson)
		wxPROPERTY( Age, int, SetAge, GetAge, 3, 0 /*flags*/ , wxT("Helpstring") , wxT("group") )
	wxEND_PROPERTIES_TABLE()
 
	wxBEGIN_HANDLERS_TABLE(wxPerson)
	wxEND_HANDLERS_TABLE()
 
	wxCONSTRUCTOR_1(wxPerson, int, Age)
#else
	IMPLEMENT_DYNAMIC_CLASS(wxPerson, wxObject)
#endif 

[edit] Notes

  • You must include the wxBEGIN_HANDLERS_TABLE block, even if empty.
  • The property name ('Age' in the example above) must be identical for both the wxPROPERTY and wxCONSTRUCTOR_X macros.
  • Use wxCONSTRUCTOR_2 for constructors involving 2 parameters, wxCONSTRUCTOR_3 for 3 parameters, and so on...

[edit] Saving the object

To stream the object and its properties to an XML file, the following code can be used:

Saving an object to an XML file
wxPerson *person = new wxPerson(8);
 
wxXmlDocument xml;
wxXmlNode *root;
root = new wxXmlNode(wxXML_ELEMENT_NODE, wxT("root"), wxT(""));
xml.SetRoot(root);
wxXmlWriter writer(root);
wxPersister persister;
wxxVariantArray metadata;
 
writer.WriteObject( person, person->GetClassInfo() , &persister , wxString(wxT("person")), metadata );
xml.Save(wxT("myXML.xml"));

This will create an XML file that looks like so:

<?xml version="1.0" encoding="utf-8"?>
<root>
  <entry name="person">
    <object class="wxPerson" id="0">
      <prop name="Age">8</prop>
    </object>
  </entry>
</root>

[edit] Loading the Object

The following code creates and loads the object from the XML file and debug-output the person's age:

Loading an object to an XML file
wxXmlDocument xml;
wxXmlNode *root;
wxRuntimeDepersister Callbacks;
 
xml.Load(wxT("myXML.xml"));
root = xml.GetRoot();
if (root->GetName() != wxT("root"))
{
	assert(!"Bad XML file");
}
wxXmlReader Reader(root);
int obj = Reader.ReadObject( wxString(wxT("person")) , &Callbacks );
	
wxPerson *person = (wxPerson*)Callbacks.GetObject(obj);
wxLogDebug(wxT("%d"), person->GetAge());

[edit] See also

XTI

Personal tools