serialization; more docu

This commit is contained in:
Marc Wäckerlin
2009-04-22 16:10:10 +00:00
parent 9548b27052
commit 94f5fd4970
4 changed files with 252 additions and 6 deletions

View File

@@ -82,6 +82,147 @@
@example doc/examples/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
//@}
//! Deefine a string for a node name
/*! Put this macro in the global part of your header files. After
declaration of e.g. <code>XML_NODE(tagname)</code> you can use
<code>xml::node::tagname</code> as constant std::string with
contents @c "tagname" in your code.
@code
XML_NAME(base);
XML_NAME(child);
int main(int, char**) {
xml::Factory test(xml::Node(xml::node::base)
return 0;
}
@endcode */
#define XML_NODE(NAME) \
namespace xml {\
namespace node {\
static const std::string xml::Node NAME(#name);\
}\
}
//! Represents classes for handling C++ access to XML files with strict schema.
/*! The schema ist not presented through xsd, but it can be declared in C++.
@@ -181,6 +322,13 @@ namespace xml {
}
};
//----------------------------------------------------------------------------
class factory_not_valid: public exception {
public:
factory_not_valid() throw():
exception("a factory must be given a template node") {
}
};
//----------------------------------------------------------------------------
class no_parent: public exception {
public:
no_parent(const Node& t) throw(): exception("node has no parent", t) {}
@@ -487,6 +635,18 @@ namespace xml {
throw();
virtual String& append(const Node& o) throw(cannot_have_children);
Node& operator=(const std::string& contents) throw();
operator std::string() const throw();
operator bool() const throw();
operator signed char() const throw();
operator unsigned char() const throw();
operator signed short() const throw();
operator unsigned short() const throw();
operator signed int() const throw();
operator unsigned int() const throw();
operator signed long() const throw();
operator unsigned long() const throw();
operator float() const throw();
operator double() const throw();
protected:
std::string _text;
};
@@ -508,7 +668,11 @@ namespace xml {
class Factory {
public:
Factory(const Node& t) throw();
const Node& operator*() const throw();
Factory() throw();
Factory& operator=(const Node& t) throw();
Factory& append(const Node& node) throw();
const Node& operator*() const throw(factory_not_valid);
operator bool() const throw();
friend std::ostream& operator<<(std::ostream& os,
const Factory& factory) throw();
static std::ostream& print(std::ostream& os, const Node& node,
@@ -522,7 +686,6 @@ namespace xml {
wrong_node_number);
private:
friend class stream_error;
Factory(); // not implemented
Factory(const Factory&); // not implemented
bool ws(char c) throw();
std::auto_ptr<Node> read(std::istream& is, const Node& position)