better serialization, but test does not work actually
This commit is contained in:
92
doc/examples/inherit_serialization.cxx
Normal file
92
doc/examples/inherit_serialization.cxx
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
/*! @file
|
||||||
|
|
||||||
|
@id $Id$
|
||||||
|
*/
|
||||||
|
// 1 2 3 4 5 6 7 8
|
||||||
|
// 45678901234567890123456789012345678901234567890123456789012345678901234567890
|
||||||
|
|
||||||
|
// g++ -I../../src ../../src/xml.cxx serialization.cxx
|
||||||
|
|
||||||
|
#include <xml-cxx/xml.hxx>
|
||||||
|
#include <iostream>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
class B: public xml::Serialize {
|
||||||
|
public:
|
||||||
|
int a;
|
||||||
|
std::string txt;
|
||||||
|
protected:
|
||||||
|
void initXmlMembers() {
|
||||||
|
className("b");
|
||||||
|
persist(a, "a");
|
||||||
|
persist(txt, "txt");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class B: public xml::Serialize {
|
||||||
|
public:
|
||||||
|
int a;
|
||||||
|
std::string txt;
|
||||||
|
protected:
|
||||||
|
void initXmlMembers() {
|
||||||
|
className("b");
|
||||||
|
persist(a, "a");
|
||||||
|
persist(txt, "txt");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//! Class with external xml::Serialize
|
||||||
|
class C {
|
||||||
|
public:
|
||||||
|
int a;
|
||||||
|
std::string txt;
|
||||||
|
};
|
||||||
|
|
||||||
|
int main(int, char**) {
|
||||||
|
{ // Serialization as a member
|
||||||
|
std::stringstream ss("<a>\n"
|
||||||
|
"\t<a>1234</a>\n"
|
||||||
|
"\t<txt>Dies ist ein Serialisierungs-Test</txt>\n"
|
||||||
|
"</a>");
|
||||||
|
A a;
|
||||||
|
a._ser.loadXml(ss);
|
||||||
|
if (a.a==1234) a.a=4321;
|
||||||
|
a._ser.saveXml(std::cout)<<std::endl;
|
||||||
|
} { // Inherited Serialization
|
||||||
|
std::stringstream ss("<b>\n"
|
||||||
|
"\t<a>1234</a>\n"
|
||||||
|
"\t<txt>Dies ist ein Serialisierungs-Test</txt>\n"
|
||||||
|
"</b>");
|
||||||
|
B b;
|
||||||
|
b.loadXml(ss);
|
||||||
|
if (b.a==1234) b.a=4321;
|
||||||
|
b.saveXml(std::cout)<<std::endl;
|
||||||
|
} { // External xml::Serialize: "ser" must live in no longer than "c"!
|
||||||
|
std::stringstream ss("<c>\n"
|
||||||
|
"\t<a>1234</a>\n"
|
||||||
|
"\t<txt>Dies ist ein Serialisierungs-Test</txt>\n"
|
||||||
|
"</c>");
|
||||||
|
C c;
|
||||||
|
xml::Serialize ser(xml::Serialize("c")
|
||||||
|
.persist(c.a, "a")
|
||||||
|
.persist(c.txt, "txt"));
|
||||||
|
ser.loadXml(ss);
|
||||||
|
if (c.a==1234) c.a=4321;
|
||||||
|
ser.saveXml(std::cout)<<std::endl;
|
||||||
|
} { // Use xml::Serialize to store anything, e.g. local variables
|
||||||
|
// Important: "ser" must live in no longer than the variables!
|
||||||
|
std::stringstream ss("<d>\n"
|
||||||
|
"\t<a>1234</a>\n"
|
||||||
|
"\t<txt>Dies ist ein Serialisierungs-Test</txt>\n"
|
||||||
|
"</d>");
|
||||||
|
int a;
|
||||||
|
std::string txt;
|
||||||
|
xml::Serialize ser(xml::Serialize("d")
|
||||||
|
.persist(a, "a")
|
||||||
|
.persist(txt, "txt"));
|
||||||
|
ser.loadXml(ss);
|
||||||
|
if (a==1234) a=4321;
|
||||||
|
ser.saveXml(std::cout)<<std::endl;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
@@ -5,46 +5,89 @@
|
|||||||
// 1 2 3 4 5 6 7 8
|
// 1 2 3 4 5 6 7 8
|
||||||
// 45678901234567890123456789012345678901234567890123456789012345678901234567890
|
// 45678901234567890123456789012345678901234567890123456789012345678901234567890
|
||||||
|
|
||||||
// g++ -I../../src ../../src/xml.cxx node_macros.cxx
|
// g++ -I../../src ../../src/xml.cxx serialization.cxx
|
||||||
|
|
||||||
#include <xml-cxx/xml.hxx>
|
#include <xml-cxx/xml.hxx>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
/*
|
|
||||||
template<class STREAM> class Stream: public STREAM {
|
|
||||||
public:
|
|
||||||
virtual ~Stream() {}
|
|
||||||
template<typename T> virtual Stream& operator%(T& o);
|
|
||||||
};
|
|
||||||
|
|
||||||
template<class STREAM> class IStream: public Stream<STREAM> {
|
|
||||||
public:
|
|
||||||
virtual template<typename T> IStream& operator%(T& o) {
|
|
||||||
operator>>(o);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template<class STREAM> class OStream: public Stream<STREAM> {
|
|
||||||
public:
|
|
||||||
virtual template<typename T> OStream& operator%(T& o) {
|
|
||||||
operator<<(o);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
*/
|
|
||||||
|
|
||||||
template<class STREAM, typename TYPE>
|
|
||||||
STREAM& operator%(STREAM& s, TYPE& o);
|
|
||||||
template<class STREAM, typename TYPE>
|
|
||||||
STREAM& operator%(STREAM& s, TYPE& o);
|
|
||||||
|
|
||||||
|
//! Class with built in xml::Serialize as member, no inheritance
|
||||||
class A {
|
class A {
|
||||||
|
public:
|
||||||
|
A(): _ser("a") {
|
||||||
|
_ser.persist(a, "a");
|
||||||
|
_ser.persist(txt, "txt");
|
||||||
|
}
|
||||||
|
int a;
|
||||||
|
std::string txt;
|
||||||
|
xml::Serialize _ser;
|
||||||
|
};
|
||||||
|
|
||||||
|
//! Class that inherits xml::Serialize
|
||||||
|
class B: public xml::Serialize {
|
||||||
|
public:
|
||||||
|
int a;
|
||||||
|
std::string txt;
|
||||||
|
protected:
|
||||||
|
void initXmlMembers() {
|
||||||
|
className("b");
|
||||||
|
persist(a, "a");
|
||||||
|
persist(txt, "txt");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//! Class with external xml::Serialize
|
||||||
|
class C {
|
||||||
public:
|
public:
|
||||||
int a;
|
int a;
|
||||||
std::string txt;
|
std::string txt;
|
||||||
};
|
};
|
||||||
|
|
||||||
int main(int, char**) {
|
int main(int, char**) {
|
||||||
|
{ // Serialization as a member
|
||||||
|
std::stringstream ss("<a>\n"
|
||||||
|
"\t<a>1234</a>\n"
|
||||||
|
"\t<txt>Dies ist ein Serialisierungs-Test</txt>\n"
|
||||||
|
"</a>");
|
||||||
|
A a;
|
||||||
|
a._ser.loadXml(ss);
|
||||||
|
if (a.a==1234) a.a=4321;
|
||||||
|
a._ser.saveXml(std::cout)<<std::endl;
|
||||||
|
} { // Inherited Serialization
|
||||||
|
std::stringstream ss("<b>\n"
|
||||||
|
"\t<a>1234</a>\n"
|
||||||
|
"\t<txt>Dies ist ein Serialisierungs-Test</txt>\n"
|
||||||
|
"</b>");
|
||||||
|
B b;
|
||||||
|
b.loadXml(ss);
|
||||||
|
if (b.a==1234) b.a=4321;
|
||||||
|
b.saveXml(std::cout)<<std::endl;
|
||||||
|
} { // External xml::Serialize: "ser" must live in no longer than "c"!
|
||||||
|
std::stringstream ss("<c>\n"
|
||||||
|
"\t<a>1234</a>\n"
|
||||||
|
"\t<txt>Dies ist ein Serialisierungs-Test</txt>\n"
|
||||||
|
"</c>");
|
||||||
|
C c;
|
||||||
|
xml::Serialize ser(xml::Serialize("c")
|
||||||
|
.persist(c.a, "a")
|
||||||
|
.persist(c.txt, "txt"));
|
||||||
|
ser.loadXml(ss);
|
||||||
|
if (c.a==1234) c.a=4321;
|
||||||
|
ser.saveXml(std::cout)<<std::endl;
|
||||||
|
} { // Use xml::Serialize to store anything, e.g. local variables
|
||||||
|
// Important: "ser" must live in no longer than the variables!
|
||||||
|
std::stringstream ss("<d>\n"
|
||||||
|
"\t<a>1234</a>\n"
|
||||||
|
"\t<txt>Dies ist ein Serialisierungs-Test</txt>\n"
|
||||||
|
"</d>");
|
||||||
|
int a;
|
||||||
|
std::string txt;
|
||||||
|
xml::Serialize ser(xml::Serialize("d")
|
||||||
|
.persist(a, "a")
|
||||||
|
.persist(txt, "txt"));
|
||||||
|
ser.loadXml(ss);
|
||||||
|
if (a==1234) a=4321;
|
||||||
|
ser.saveXml(std::cout)<<std::endl;
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@@ -14,6 +14,8 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <typeinfo>
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
/*! @mainpage
|
/*! @mainpage
|
||||||
|
|
||||||
@@ -82,125 +84,6 @@
|
|||||||
|
|
||||||
@example address.cxx */
|
@example address.cxx */
|
||||||
|
|
||||||
/*! @defgroup serialization Class Serialization
|
|
||||||
|
|
||||||
@section serIntro Introduction
|
|
||||||
|
|
||||||
Boost library (http://boost.org) offers a serialization framework,
|
|
||||||
which is able to serialize even complex class structures, you only
|
|
||||||
need to overwrite one or two serialization macros. The
|
|
||||||
disadvantages are that a lot of macros are needed and it becomes
|
|
||||||
quite complex as soon as you need inheritance. Also the generated
|
|
||||||
XML is not very enhanced, especially for Lists and
|
|
||||||
optional. Editing the boost serialization code by hand is a pain.
|
|
||||||
|
|
||||||
Classes could also be serialized using gSOAP (http://gsoap.sf.net)
|
|
||||||
which is designed for the SOA-Protocol. This serialization is much
|
|
||||||
more flexible, but it requires a pseudo C++ declaration and a C++
|
|
||||||
parser/generator. Also it has very bad memory management, since it
|
|
||||||
is plain C internally.
|
|
||||||
|
|
||||||
Our requirements are:
|
|
||||||
- No precompiler, plain C++.
|
|
||||||
- Automatic memory management.
|
|
||||||
- Nice looking XML code that is easy to edit manually.
|
|
||||||
- Good error messages (exception) in case of bad XML files.
|
|
||||||
- As few ugly overflow as possible.
|
|
||||||
|
|
||||||
@section serActual Actual Status
|
|
||||||
|
|
||||||
Instead of:
|
|
||||||
|
|
||||||
@code
|
|
||||||
class A {
|
|
||||||
protected:
|
|
||||||
int _anInteger;
|
|
||||||
bool _aBool;
|
|
||||||
double _aDouble;
|
|
||||||
std::string _aString;
|
|
||||||
std::string _anotherString;
|
|
||||||
unsigned long _aLong;
|
|
||||||
};
|
|
||||||
@endcode
|
|
||||||
|
|
||||||
You have to write:
|
|
||||||
|
|
||||||
@code
|
|
||||||
class A {
|
|
||||||
protected:
|
|
||||||
XML_DECLARE_MEMBER(int, anInteger);
|
|
||||||
XML_DECLARE_MEMBER(bool, aBool);
|
|
||||||
XML_DECLARE_MEMBER(double, aDouble);
|
|
||||||
XML_DECLARE_MEMBER(std::string, aString);
|
|
||||||
XML_DECLARE_MEMBER(std::string, anotherString);
|
|
||||||
XML_DECLARE_MEMBER(unsigned long, aLong);
|
|
||||||
private:
|
|
||||||
XML_INIT_BEGIN(A);
|
|
||||||
XML_INIT_MEMBER(A, anInteger);
|
|
||||||
XML_INIT_MEMBER(A, aBool);
|
|
||||||
XML_INIT_MEMBER(A, aDouble);
|
|
||||||
XML_INIT_MEMBER(A, aString);
|
|
||||||
XML_INIT_MEMBER(A, anotherString);
|
|
||||||
XML_INIT_MEMBER(A, aLong);
|
|
||||||
XML_INIT_END;
|
|
||||||
};
|
|
||||||
@endcode
|
|
||||||
|
|
||||||
You get:
|
|
||||||
- All the members (with @c _ as member prefix)
|
|
||||||
- method <code>void saveXml(std::ostream&) const</code>
|
|
||||||
- method <code>void loadXml(std::istream&)</code>
|
|
||||||
|
|
||||||
@todo Up to now: Only base types plus std::string are supported,
|
|
||||||
no list, no inheritance is possible and no optional members. */
|
|
||||||
//@{
|
|
||||||
#define XML_DECLARE_MEMBER(TYPE, MEMBER) \
|
|
||||||
void MEMBER##FromNode(xml::Node& node) { \
|
|
||||||
_##MEMBER = (TYPE)dynamic_cast<xml::String&>(node[#MEMBER]); \
|
|
||||||
} \
|
|
||||||
void MEMBER##ToNode(xml::Node& node) const { \
|
|
||||||
std::stringstream ss; \
|
|
||||||
ss<<_##MEMBER; \
|
|
||||||
node[#MEMBER].text(ss.str()); \
|
|
||||||
} \
|
|
||||||
TYPE _##MEMBER
|
|
||||||
|
|
||||||
#define XML_INIT_BEGIN(CLASS_NAME) \
|
|
||||||
const CLASS_NAME& saveXml(std::ostream& os) const { \
|
|
||||||
const_cast<CLASS_NAME*>(this)->initXmlMembers(); \
|
|
||||||
xml::Node node(*_xmlFactory); \
|
|
||||||
for (std::vector<XmlSaveMethod>::const_iterator \
|
|
||||||
it(_saveXmlMemberList.begin()); \
|
|
||||||
it!=_saveXmlMemberList.end(); ++it) \
|
|
||||||
(this->*(*it))(node); \
|
|
||||||
os<<node; \
|
|
||||||
} \
|
|
||||||
CLASS_NAME& loadXml(std::istream& is) { \
|
|
||||||
initXmlMembers(); \
|
|
||||||
std::auto_ptr<xml::Node> node(_xmlFactory.read(is)); \
|
|
||||||
for (std::vector<XmlLoadMethod>::const_iterator \
|
|
||||||
it(_loadXmlMemberList.begin()); \
|
|
||||||
it!=_loadXmlMemberList.end(); ++it) \
|
|
||||||
(this->*(*it))(*node); \
|
|
||||||
} \
|
|
||||||
private: \
|
|
||||||
typedef void(CLASS_NAME::*XmlSaveMethod)(xml::Node&) const; \
|
|
||||||
typedef void(CLASS_NAME::*XmlLoadMethod)(xml::Node&); \
|
|
||||||
std::vector<XmlSaveMethod> _saveXmlMemberList; \
|
|
||||||
std::vector<XmlLoadMethod> _loadXmlMemberList; \
|
|
||||||
void initXmlMembers() { \
|
|
||||||
if (_xmlFactory) return; \
|
|
||||||
xml::Node schema(#CLASS_NAME)
|
|
||||||
#define XML_INIT_MEMBER(CLASS_NAME, MEMBER) \
|
|
||||||
schema<<xml::String(#MEMBER).limits(1,1); \
|
|
||||||
_saveXmlMemberList.push_back(&CLASS_NAME::MEMBER##ToNode); \
|
|
||||||
_loadXmlMemberList.push_back(&CLASS_NAME::MEMBER##FromNode)
|
|
||||||
#define XML_INIT_END \
|
|
||||||
_xmlFactory = schema;\
|
|
||||||
} \
|
|
||||||
xml::Factory _xmlFactory
|
|
||||||
//@}
|
|
||||||
|
|
||||||
/*! @defgroup xmlConst XML Constant Declarations
|
/*! @defgroup xmlConst XML Constant Declarations
|
||||||
|
|
||||||
There are macros to help you with declaring constants. Chose a C++
|
There are macros to help you with declaring constants. Chose a C++
|
||||||
@@ -777,7 +660,6 @@ namespace xml {
|
|||||||
wrong_node_number);
|
wrong_node_number);
|
||||||
private:
|
private:
|
||||||
friend class stream_error;
|
friend class stream_error;
|
||||||
Factory(const Factory&); // not implemented
|
|
||||||
bool ws(char c) throw();
|
bool ws(char c) throw();
|
||||||
std::auto_ptr<Node> read(std::istream& is, const Node& position)
|
std::auto_ptr<Node> read(std::istream& is, const Node& position)
|
||||||
throw(wrong_end_tag, wrong_start_tag, tag_expected, type_mismatch,
|
throw(wrong_end_tag, wrong_start_tag, tag_expected, type_mismatch,
|
||||||
@@ -801,5 +683,126 @@ namespace xml {
|
|||||||
long _open;
|
long _open;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*! @defgroup serialization Class Serialization
|
||||||
|
|
||||||
|
@section serIntro Introduction
|
||||||
|
|
||||||
|
Boost library (http://boost.org) offers a serialization framework,
|
||||||
|
which is able to serialize even complex class structures, you only
|
||||||
|
need to overwrite one or two serialization macros. The
|
||||||
|
disadvantages are that a lot of macros are needed and it becomes
|
||||||
|
quite complex as soon as you need inheritance. Also the generated
|
||||||
|
XML is not very enhanced, especially for Lists and
|
||||||
|
optional. Editing the boost serialization code by hand is a pain.
|
||||||
|
|
||||||
|
Classes could also be serialized using gSOAP (http://gsoap.sf.net)
|
||||||
|
which is designed for the SOA-Protocol. This serialization is much
|
||||||
|
more flexible, but it requires a pseudo C++ declaration and a C++
|
||||||
|
parser/generator. Also it has very bad memory management, since it
|
||||||
|
is plain C internally.
|
||||||
|
|
||||||
|
Our requirements are:
|
||||||
|
- No precompiler, plain C++.
|
||||||
|
- Automatic memory management.
|
||||||
|
- Nice looking XML code that is easy to edit manually.
|
||||||
|
- Good error messages (exception) in case of bad XML files.
|
||||||
|
- As few ugly overflow as possible.
|
||||||
|
|
||||||
|
@section serActual Actual Status
|
||||||
|
|
||||||
|
Instead of:
|
||||||
|
|
||||||
|
@code
|
||||||
|
class A {
|
||||||
|
protected:
|
||||||
|
int _anInteger;
|
||||||
|
bool _aBool;
|
||||||
|
double _aDouble;
|
||||||
|
std::string _aString;
|
||||||
|
std::string _anotherString;
|
||||||
|
unsigned long _aLong;
|
||||||
|
};
|
||||||
|
@endcode
|
||||||
|
|
||||||
|
You have to write:
|
||||||
|
|
||||||
|
@code
|
||||||
|
class A {
|
||||||
|
protected:
|
||||||
|
XML_DECLARE_MEMBER(int, anInteger);
|
||||||
|
XML_DECLARE_MEMBER(bool, aBool);
|
||||||
|
XML_DECLARE_MEMBER(double, aDouble);
|
||||||
|
XML_DECLARE_MEMBER(std::string, aString);
|
||||||
|
XML_DECLARE_MEMBER(std::string, anotherString);
|
||||||
|
XML_DECLARE_MEMBER(unsigned long, aLong);
|
||||||
|
private:
|
||||||
|
XML_INIT_BEGIN(A);
|
||||||
|
XML_INIT_MEMBER(A, anInteger);
|
||||||
|
XML_INIT_MEMBER(A, aBool);
|
||||||
|
XML_INIT_MEMBER(A, aDouble);
|
||||||
|
XML_INIT_MEMBER(A, aString);
|
||||||
|
XML_INIT_MEMBER(A, anotherString);
|
||||||
|
XML_INIT_MEMBER(A, aLong);
|
||||||
|
XML_INIT_END;
|
||||||
|
};
|
||||||
|
@endcode
|
||||||
|
|
||||||
|
You get:
|
||||||
|
- All the members (with @c _ as member prefix)
|
||||||
|
- method <code>void saveXml(std::ostream&) const</code>
|
||||||
|
- method <code>void loadXml(std::istream&)</code>
|
||||||
|
|
||||||
|
@todo Up to now: Only base types plus std::string are supported,
|
||||||
|
no list, no inheritance is possible and no optional members.
|
||||||
|
|
||||||
|
@example serialization.cxx */
|
||||||
|
//@{
|
||||||
|
|
||||||
|
class Serialize {
|
||||||
|
public:
|
||||||
|
//! You must call Serialize::className() if you use this constructor!
|
||||||
|
Serialize() throw();
|
||||||
|
Serialize(const std::string& className) throw();
|
||||||
|
virtual ~Serialize();
|
||||||
|
void className(const std::string& name) throw();
|
||||||
|
template<typename TYPE>
|
||||||
|
Serialize& persist(TYPE& member, const std::string& name) {
|
||||||
|
mapName<TYPE>()[name] = &member;
|
||||||
|
mapMember<TYPE>()[&member] = name;
|
||||||
|
_xmlNames[name] = &typeid(TYPE);
|
||||||
|
xml::Node schema(*_xmlFactory);
|
||||||
|
schema<<xml::String(name).limits(1,1);
|
||||||
|
_xmlFactory = schema;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
std::ostream& saveXml(std::ostream& os) const throw();
|
||||||
|
std::istream& loadXml(std::istream& is);
|
||||||
|
protected:
|
||||||
|
virtual void initXmlMembers();
|
||||||
|
private:
|
||||||
|
template<typename TYPE> std::map<std::string, TYPE*>& mapName() const {
|
||||||
|
static std::map<std::string, TYPE*> MAP;
|
||||||
|
return MAP;
|
||||||
|
}
|
||||||
|
template<typename TYPE> std::map<TYPE*, std::string>& mapMember() const {
|
||||||
|
static std::map<TYPE*, std::string> MAP;
|
||||||
|
return MAP;
|
||||||
|
}
|
||||||
|
template<typename TYPE> void fromNode(TYPE* member, xml::Node& node) {
|
||||||
|
*member =
|
||||||
|
(TYPE)dynamic_cast<xml::String&>(node[mapMember<TYPE>()[member]]);
|
||||||
|
}
|
||||||
|
template<typename TYPE> void toNode(TYPE* member, xml::Node& node) const {
|
||||||
|
std::stringstream ss;
|
||||||
|
ss<<*member;
|
||||||
|
node[mapMember<TYPE>()[member]].text(ss.str());
|
||||||
|
}
|
||||||
|
std::map<std::string, const std::type_info*> _xmlNames;
|
||||||
|
xml::Factory _xmlFactory;
|
||||||
|
};
|
||||||
|
|
||||||
|
//@}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
77
src/xml.cxx
77
src/xml.cxx
@@ -260,6 +260,7 @@ namespace xml {
|
|||||||
same parent as the source of the copy.
|
same parent as the source of the copy.
|
||||||
@see xml::Node::clone() for more information on the parenting. */
|
@see xml::Node::clone() for more information on the parenting. */
|
||||||
Node& Node::operator=(const Node& o) throw() {
|
Node& Node::operator=(const Node& o) throw() {
|
||||||
|
clear();
|
||||||
_attributes=o._attributes;
|
_attributes=o._attributes;
|
||||||
_name = o.name();
|
_name = o.name();
|
||||||
_min = o._min;
|
_min = o._min;
|
||||||
@@ -1006,4 +1007,80 @@ namespace xml {
|
|||||||
return tag;
|
return tag;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//============================================================== Serialization
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
Serialize::Serialize() throw() {}
|
||||||
|
Serialize::Serialize(const std::string& className) throw():
|
||||||
|
_xmlFactory(xml::Node(xml::String(className).limits(1,1))) {
|
||||||
|
}
|
||||||
|
Serialize::~Serialize() {};
|
||||||
|
void Serialize::className(const std::string& name) throw() {
|
||||||
|
_xmlFactory=xml::Node(xml::String(name).limits(1,1));
|
||||||
|
}
|
||||||
|
std::ostream& Serialize::saveXml(std::ostream& os) const throw() {
|
||||||
|
if (!_xmlFactory) const_cast<Serialize*>(this)->initXmlMembers();
|
||||||
|
xml::Node node(*_xmlFactory);
|
||||||
|
for (std::map<std::string, const std::type_info*>::const_iterator
|
||||||
|
it(_xmlNames.begin());
|
||||||
|
it!=_xmlNames.end(); ++it) {
|
||||||
|
#define QWERTZ_CHECK_TYPE_ZTREWQ___XXX(TYPE) \
|
||||||
|
if (*it->second==typeid(TYPE)) \
|
||||||
|
toNode(mapName<TYPE>()[it->first], node); \
|
||||||
|
else
|
||||||
|
QWERTZ_CHECK_TYPE_ZTREWQ___XXX(std::string)
|
||||||
|
QWERTZ_CHECK_TYPE_ZTREWQ___XXX(float)
|
||||||
|
QWERTZ_CHECK_TYPE_ZTREWQ___XXX(double)
|
||||||
|
QWERTZ_CHECK_TYPE_ZTREWQ___XXX(bool)
|
||||||
|
QWERTZ_CHECK_TYPE_ZTREWQ___XXX(char)
|
||||||
|
QWERTZ_CHECK_TYPE_ZTREWQ___XXX(signed char)
|
||||||
|
QWERTZ_CHECK_TYPE_ZTREWQ___XXX(unsigned char)
|
||||||
|
QWERTZ_CHECK_TYPE_ZTREWQ___XXX(short)
|
||||||
|
QWERTZ_CHECK_TYPE_ZTREWQ___XXX(signed short)
|
||||||
|
QWERTZ_CHECK_TYPE_ZTREWQ___XXX(unsigned short)
|
||||||
|
QWERTZ_CHECK_TYPE_ZTREWQ___XXX(int)
|
||||||
|
QWERTZ_CHECK_TYPE_ZTREWQ___XXX(signed int)
|
||||||
|
QWERTZ_CHECK_TYPE_ZTREWQ___XXX(unsigned int)
|
||||||
|
QWERTZ_CHECK_TYPE_ZTREWQ___XXX(long)
|
||||||
|
QWERTZ_CHECK_TYPE_ZTREWQ___XXX(signed long)
|
||||||
|
QWERTZ_CHECK_TYPE_ZTREWQ___XXX(unsigned long)
|
||||||
|
throw std::runtime_error(it->second->name());
|
||||||
|
#undef QWERTZ_CHECK_TYPE_ZTREWQ___XXX
|
||||||
|
}
|
||||||
|
os<<node;
|
||||||
|
return os;
|
||||||
|
}
|
||||||
|
std::istream& Serialize::loadXml(std::istream& is) {
|
||||||
|
if (!_xmlFactory) initXmlMembers();
|
||||||
|
std::auto_ptr<xml::Node> node(_xmlFactory.read(is));
|
||||||
|
for (std::map<std::string, const std::type_info*>::const_iterator
|
||||||
|
it(_xmlNames.begin());
|
||||||
|
it!=_xmlNames.end(); ++it) {
|
||||||
|
#define QWERTZ_CHECK_TYPE_ZTREWQ___XXX(TYPE) \
|
||||||
|
if (*it->second==typeid(TYPE)) \
|
||||||
|
fromNode(mapName<TYPE>()[it->first], *node); \
|
||||||
|
else
|
||||||
|
QWERTZ_CHECK_TYPE_ZTREWQ___XXX(std::string)
|
||||||
|
QWERTZ_CHECK_TYPE_ZTREWQ___XXX(float)
|
||||||
|
QWERTZ_CHECK_TYPE_ZTREWQ___XXX(double)
|
||||||
|
QWERTZ_CHECK_TYPE_ZTREWQ___XXX(bool)
|
||||||
|
//QWERTZ_CHECK_TYPE_ZTREWQ___XXX(char)
|
||||||
|
QWERTZ_CHECK_TYPE_ZTREWQ___XXX(signed char)
|
||||||
|
QWERTZ_CHECK_TYPE_ZTREWQ___XXX(unsigned char)
|
||||||
|
QWERTZ_CHECK_TYPE_ZTREWQ___XXX(short)
|
||||||
|
QWERTZ_CHECK_TYPE_ZTREWQ___XXX(signed short)
|
||||||
|
QWERTZ_CHECK_TYPE_ZTREWQ___XXX(unsigned short)
|
||||||
|
QWERTZ_CHECK_TYPE_ZTREWQ___XXX(int)
|
||||||
|
QWERTZ_CHECK_TYPE_ZTREWQ___XXX(signed int)
|
||||||
|
QWERTZ_CHECK_TYPE_ZTREWQ___XXX(unsigned int)
|
||||||
|
QWERTZ_CHECK_TYPE_ZTREWQ___XXX(long)
|
||||||
|
QWERTZ_CHECK_TYPE_ZTREWQ___XXX(signed long)
|
||||||
|
QWERTZ_CHECK_TYPE_ZTREWQ___XXX(unsigned long)
|
||||||
|
throw std::runtime_error(it->second->name());
|
||||||
|
#undef QWERTZ_CHECK_TYPE_ZTREWQ___XXX
|
||||||
|
}
|
||||||
|
return is;
|
||||||
|
}
|
||||||
|
void Serialize::initXmlMembers() {}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
109
test/serialization_test.cxx
Normal file
109
test/serialization_test.cxx
Normal file
@@ -0,0 +1,109 @@
|
|||||||
|
/*! @file
|
||||||
|
|
||||||
|
@id $Id$
|
||||||
|
*/
|
||||||
|
// 1 2 3 4 5 6 7 8
|
||||||
|
// 45678901234567890123456789012345678901234567890123456789012345678901234567890
|
||||||
|
|
||||||
|
#include <xml-cxx/xml.hxx>
|
||||||
|
#include <cppunit/TestFixture.h>
|
||||||
|
#include <cppunit/ui/text/TestRunner.h>
|
||||||
|
#include <cppunit/extensions/HelperMacros.h>
|
||||||
|
#include <cppunit/extensions/TestFactoryRegistry.h>
|
||||||
|
|
||||||
|
class A: public xml::Serialization {
|
||||||
|
public:
|
||||||
|
int _anInteger;
|
||||||
|
bool _aBool;
|
||||||
|
double _aDouble;
|
||||||
|
std::string _aString;
|
||||||
|
std::string _anotherString;
|
||||||
|
unsigned long _aLong;
|
||||||
|
protected:
|
||||||
|
void initXmlMembers() {
|
||||||
|
className("A");
|
||||||
|
persist(_anInteger, "anInteger");
|
||||||
|
persist(_aBool, "aBool");
|
||||||
|
persist(_aDouble, "aDouble");
|
||||||
|
persist(_aString, "aString");
|
||||||
|
persist(_anotherString, "anotherString");
|
||||||
|
persist(_aLong, "aLong");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class SerializationTest: public CppUnit::TestFixture {
|
||||||
|
public:
|
||||||
|
std::string _file;
|
||||||
|
A _a;
|
||||||
|
void setUp() {
|
||||||
|
_a._anInteger = 15;
|
||||||
|
_a._aBool = true;
|
||||||
|
_a._aDouble = 123.456;
|
||||||
|
_a._aString = "Hello World";
|
||||||
|
_a._anotherString = "This is another Text";
|
||||||
|
_a._aLong = 4123674622;
|
||||||
|
try {
|
||||||
|
std::stringstream ss;
|
||||||
|
_a.saveXml(ss);
|
||||||
|
_file = ss.str();
|
||||||
|
} catch (...) {}
|
||||||
|
}
|
||||||
|
void memberDeclaration() {
|
||||||
|
// This is more a compile time test than a runtime test.
|
||||||
|
A a;
|
||||||
|
a._anInteger = 15;
|
||||||
|
CPPUNIT_ASSERT_EQUAL(15, a._anInteger);
|
||||||
|
a._aString = "Hello World";
|
||||||
|
CPPUNIT_ASSERT_EQUAL(std::string("Hello World"), a._aString);
|
||||||
|
std::stringstream ss;
|
||||||
|
}
|
||||||
|
void store() {
|
||||||
|
{
|
||||||
|
std::stringstream ss;
|
||||||
|
CPPUNIT_ASSERT_NO_THROW(_a.saveXml(ss));
|
||||||
|
CPPUNIT_ASSERT_EQUAL(std::string("<A>\n"
|
||||||
|
"\t<anInteger>15</anInteger>\n"
|
||||||
|
"\t<aBool>1</aBool>\n"
|
||||||
|
"\t<aDouble>123.456</aDouble>\n"
|
||||||
|
"\t<aString>Hello World</aString>\n"
|
||||||
|
"\t<anotherString>This is"
|
||||||
|
" another Text</anotherString>\n"
|
||||||
|
"\t<aLong>4123674622</aLong>\n"
|
||||||
|
"</A>"),
|
||||||
|
ss.str());
|
||||||
|
} { // again - initialisation of A should be done only once
|
||||||
|
std::stringstream ss;
|
||||||
|
CPPUNIT_ASSERT_NO_THROW(_a.saveXml(ss));
|
||||||
|
CPPUNIT_ASSERT_EQUAL(_file, ss.str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void restore() {
|
||||||
|
A a;
|
||||||
|
std::stringstream ss(_file);
|
||||||
|
CPPUNIT_ASSERT(_file.size()>0);
|
||||||
|
CPPUNIT_ASSERT_EQUAL(_file, ss.str());
|
||||||
|
CPPUNIT_ASSERT_NO_THROW(a.loadXml(ss));
|
||||||
|
CPPUNIT_ASSERT_EQUAL(15, a._anInteger);
|
||||||
|
CPPUNIT_ASSERT_EQUAL(true, a._aBool);
|
||||||
|
CPPUNIT_ASSERT_EQUAL(123.456, a._aDouble);
|
||||||
|
CPPUNIT_ASSERT_EQUAL(std::string("Hello World"), a._aString);
|
||||||
|
CPPUNIT_ASSERT_EQUAL(std::string("This is another Text"),
|
||||||
|
a._anotherString);
|
||||||
|
CPPUNIT_ASSERT_EQUAL(4123674622ul, a._aLong);
|
||||||
|
}
|
||||||
|
CPPUNIT_TEST_SUITE(SerializationTest);
|
||||||
|
CPPUNIT_TEST(memberDeclaration);
|
||||||
|
CPPUNIT_TEST(store);
|
||||||
|
CPPUNIT_TEST(restore);
|
||||||
|
CPPUNIT_TEST_SUITE_END();
|
||||||
|
};
|
||||||
|
CPPUNIT_TEST_SUITE_REGISTRATION(SerializationTest);
|
||||||
|
|
||||||
|
int main() try {
|
||||||
|
CppUnit::TextUi::TestRunner runner;
|
||||||
|
runner.addTest(CppUnit::TestFactoryRegistry::getRegistry().makeTest());
|
||||||
|
return runner.run() ? 0 : 1;
|
||||||
|
} catch (std::exception& e) {
|
||||||
|
std::cerr<<"***Exception: "<<e.what()<<std::endl;
|
||||||
|
return 1;
|
||||||
|
}
|
Reference in New Issue
Block a user