master
Marc Wäckerlin 16 years ago
parent f17c1d5995
commit 2860cdf5ec
  1. 5
      doc/examples/contain_serialization.cxx
  2. 3
      doc/examples/makefile.am
  3. 46
      doc/examples/optional_serialization.cxx
  4. 92
      src/xml-cxx/xml.hxx
  5. 44
      src/xml.cxx
  6. 5
      test/makefile.am
  7. 118
      test/optional_serialization_test.cxx

@ -35,10 +35,6 @@ class B: public xml::Serialize {
} }
}; };
std::ostream& fn(std::ostream& os) {
os<<std::endl<<"HALLO"<<std::endl;
}
int main(int, char**) { int main(int, char**) {
{ // Serialization as a member { // Serialization as a member
std::stringstream ss("<b>\n" std::stringstream ss("<b>\n"
@ -56,7 +52,6 @@ int main(int, char**) {
std::cout<<"Text B: "<<b.txt<<std::endl; std::cout<<"Text B: "<<b.txt<<std::endl;
std::cout<<"Text A: "<<b.a.txt<<std::endl; std::cout<<"Text A: "<<b.a.txt<<std::endl;
b.saveXml(std::cout)<<std::endl; b.saveXml(std::cout)<<std::endl;
std::cout<<fn;
} }
return 0; return 0;
} }

@ -8,7 +8,7 @@ AM_LDFLAGS = -L${top_builddir}/src -lxml-cxx
noinst_PROGRAMS = address node_macros serialization \ noinst_PROGRAMS = address node_macros serialization \
contain_serialization inherit_serialization \ contain_serialization inherit_serialization \
list_serialization list_serialization optional_serialization
address_SOURCES = address.cxx address_SOURCES = address.cxx
node_macros_SOURCES = node_macros.cxx node_macros_SOURCES = node_macros.cxx
@ -16,5 +16,6 @@ serialization_SOURCES = serialization.cxx
contain_serialization_SOURCES = contain_serialization.cxx contain_serialization_SOURCES = contain_serialization.cxx
inherit_serialization_SOURCES = inherit_serialization.cxx inherit_serialization_SOURCES = inherit_serialization.cxx
list_serialization_SOURCES = list_serialization.cxx list_serialization_SOURCES = list_serialization.cxx
optional_serialization_SOURCES = optional_serialization.cxx
MAINTAINERCLEANFILES = makefile.in MAINTAINERCLEANFILES = makefile.in

@ -0,0 +1,46 @@
/*! @file
@id $Id$
*/
// 1 2 3 4 5 6 7 8
// 45678901234567890123456789012345678901234567890123456789012345678901234567890
#include <xml-cxx/xml.hxx>
#include <iostream>
#include <sstream>
class A: public xml::Serialize {
public:
xml::Optional<int> a;
xml::Optional<std::string> txt;
protected:
void initXmlMembers() {
className("A");
persist(a, "a");
persist(txt, "txt");
}
};
class B: public xml::Serialize {
public:
xml::Optional<A> a;
xml::Optional<int> i;
xml::Optional<std::string> txt;
protected:
void initXmlMembers() {
className("B");
persist(a, "a");
persist(i, "i");
persist(txt, "txt");
}
};
int main(int, char**) {
{ // Serialization as a member
std::stringstream ss("<B/>");
B b;
b.loadXml(ss);
b.saveXml(std::cout)<<std::endl;
}
return 0;
}

@ -165,9 +165,9 @@ class MethodTrace {
- most standard containers, but in their xml-form, - most standard containers, but in their xml-form,
e.g. xml::List instead of @c std::list e.g. xml::List instead of @c std::list
(xml::List inherits @c std::list) (xml::List inherits @c std::list)
- Optional values through xml::Optional
- @c std::bitset, @c std::priority_queue, @c std::queue and - @c std::bitset, @c std::priority_queue, @c std::queue and
@c std::stack are not implemented @c std::stack are not implemented
- Optional values are not yet implemented
- Polymorfic serialisation is not yet implemented - Polymorfic serialisation is not yet implemented
@page rationale Rationale - Limitations of other libraries @page rationale Rationale - Limitations of other libraries
@ -787,6 +787,9 @@ namespace xml {
virtual Node& text(const std::string& txt) throw(tag_expected, virtual Node& text(const std::string& txt) throw(tag_expected,
type_mismatch); type_mismatch);
virtual Node& append(const Node& o) throw(cannot_have_children); virtual Node& append(const Node& o) throw(cannot_have_children);
virtual Node& remove(Node& n) throw(access_error);
virtual Node& remove(const std::string& n) throw(access_error);
virtual Node& remove(size_type n) throw(out_of_range);
virtual Node& set(const Attributes& o) throw(); virtual Node& set(const Attributes& o) throw();
Node& clear() throw (); Node& clear() throw ();
std::string name() const throw(); std::string name() const throw();
@ -954,6 +957,7 @@ namespace xml {
private: private:
friend class stream_error; friend class stream_error;
friend class Serialize; friend class Serialize;
template<class T> friend class Optional;
template<class T> friend class Container; template<class T> friend class Container;
template<class T> friend class AssociativeContainer; template<class T> friend class AssociativeContainer;
template<class T> friend class AssociativeMap; template<class T> friend class AssociativeMap;
@ -1098,8 +1102,8 @@ namespace xml {
Serialize(const Serialize& other) throw(); Serialize(const Serialize& other) throw();
virtual ~Serialize(); virtual ~Serialize();
Serialize& operator=(const Serialize& other) throw(); Serialize& operator=(const Serialize& other) throw();
Serialize& className(const std::string& name) throw(); virtual Serialize& className(const std::string& name) throw();
virtual Serialize& persist(Serialize& member, Serialize& persist(Serialize& member,
const std::string& name) throw(); const std::string& name) throw();
Serialize& persist(bool& member, Serialize& persist(bool& member,
const std::string& name) throw(); const std::string& name) throw();
@ -1136,6 +1140,7 @@ namespace xml {
static void registerFromNode(FromNodeFunc fromNodeFunc); static void registerFromNode(FromNodeFunc fromNodeFunc);
static void registerToNode(ToNodeFunc toNodeFunc); static void registerToNode(ToNodeFunc toNodeFunc);
static void registerClear(ClearFunc clearFunc); static void registerClear(ClearFunc clearFunc);
virtual void clear() throw();
protected: protected:
virtual void initXmlMembers(); virtual void initXmlMembers();
void checkInit(const Serialize* const ser=0) const { void checkInit(const Serialize* const ser=0) const {
@ -1145,11 +1150,15 @@ namespace xml {
if (!_xmlFactory) const_cast<Serialize*>(this)->initXmlMembers(); if (!_xmlFactory) const_cast<Serialize*>(this)->initXmlMembers();
} }
} }
virtual void clear() throw();
/*! @todo Why does @c protected: not work here?!? Children can't /*! @todo Why does @c protected: not work here?!? Children can't
access the members if they are protected! */ access the members if they are protected! */
public: public:
//! @cond INTERNAL //! @cond INTERNAL
template<typename TYPE> friend bool assignFromNode(Any member,
const xml::Node& node);
template<typename TYPE> friend bool assigntoNode(Any member,
const xml::Node& node);
virtual bool optional() const throw();
void clear(Any member) throw(); void clear(Any member) throw();
void reset() throw(); void reset() throw();
void copy(const Serialize& o) throw(); void copy(const Serialize& o) throw();
@ -1162,8 +1171,8 @@ namespace xml {
_xmlFactory = schema; _xmlFactory = schema;
return *this; return *this;
} }
void fromNode(Any member, const xml::Node& node); virtual void fromNode(Any member, const xml::Node& node);
void toNode(const Any member, xml::Node& node) const; virtual void toNode(const Any member, xml::Node& node) const;
std::map<std::string, Any> _xmlNames; std::map<std::string, Any> _xmlNames;
xml::Factory _xmlFactory; xml::Factory _xmlFactory;
static std::set<FromNodeFunc> _fromNode; static std::set<FromNodeFunc> _fromNode;
@ -1174,54 +1183,71 @@ namespace xml {
template <class TYPE> class Optional: public Serialize { template <class TYPE> class Optional: public Serialize {
public: public:
Optional() throw() {} Optional() throw(): _valid(false) {}
Optional(const Optional& o) throw(): _member(new TYPE(*o._member)) {} Optional(const Optional& o) throw():
Optional(const TYPE& mem) throw(): _member(new TYPE(mem)) {} _member(o._member), _valid(o.valid) {
}
Optional(const TYPE& mem) throw():
_member(mem), _valid(true) {
}
virtual ~Optional() throw() {} virtual ~Optional() throw() {}
Optional& operator=(const Optional& o) throw() { Optional& operator=(const Optional& o) throw() {
_member = new TYPE(*o._member); _member = o._member;
_valid = o._valid;
return *this; return *this;
} }
Optional& operator=(const TYPE& mem) throw() { Optional& operator=(const TYPE& mem) throw() {
_member = new TYPE(mem); _member = mem;
_valid = true;
return *this; return *this;
} }
operator bool() const throw() { operator bool() const throw() {
return _member.get(); return _valid;
} }
const TYPE& operator*() const throw() { const TYPE& operator*() const throw() {
return *_member; return _member;
} }
TYPE& operator*() throw() { TYPE& operator*() throw() {
return *_member; return _member;
} }
const TYPE*const operator->() const throw() { const TYPE*const operator->() const throw() {
return _member.get(); return &_member;
} }
TYPE*const operator->() throw() { TYPE*const operator->() throw() {
return _member.get(); return &_member;
}
virtual void clear() throw() {
_valid = false;
}
virtual Optional& className(const std::string& name) throw() {
if (!_xmlFactory) {
Serialize::className(name);
persist(_member, name);
// make the child the root, and it's optional
_xmlFactory = (*_xmlFactory)[0];
_xmlFactory->limits(0, 1);
} }
Optional& reset() throw() {
_member.reset();
return *this; return *this;
} }
protected: protected:
virtual void clear() throw() { virtual bool optional() const throw() {
_member.reset(); return true;
} }
virtual std::ostream& saveXml(std::ostream& os, virtual void fromNode(Any member, const xml::Node& node) {
const std::string& name = std::string()) _valid = true;
const throw() { Serialize::fromNode(Any(&_member), node);
if (!_member.get()) return os; }
checkInit(); virtual void toNode(const Any member, xml::Node& node) const {
xml::Node node(*_xmlFactory); if (!_valid) {
if (name.size()) node.name(name); node.parent().remove(node);
toNode(*_member, node); return;
os<<node; }
return os; const Any mem(&const_cast<Optional*>(this)->_member);
Serialize::toNode(mem, node);
} }
private: private:
std::auto_ptr<TYPE> _member; TYPE _member;
bool _valid;
}; };
//! @addtogroup serialization //! @addtogroup serialization
@ -1400,17 +1426,13 @@ namespace xml {
if (name.size()) factory->name(name); if (name.size()) factory->name(name);
std::auto_ptr<xml::Node> node(factory.read(is)); std::auto_ptr<xml::Node> node(factory.read(is));
CONTAINER_TYPE::clear(); CONTAINER_TYPE::clear();
LOG("READING: "<<*node);
for (xml::Node::size_type i(0); i<node->children(); ++i) { for (xml::Node::size_type i(0); i<node->children(); ++i) {
typename CONTAINER_TYPE::key_type key; typename CONTAINER_TYPE::key_type key;
typename CONTAINER_TYPE::mapped_type data; typename CONTAINER_TYPE::mapped_type data;
LOG("READING Key: "<<(*node)[i]<<"Value:"<<(*node)[1+i]);
Serialize::fromNode(&key, (*node)[i]); // reads into tmp Serialize::fromNode(&key, (*node)[i]); // reads into tmp
Serialize::fromNode(&data, (*node)[++i]); // key&value Serialize::fromNode(&data, (*node)[++i]); // key&value
insert(typename CONTAINER_TYPE::value_type(key, data)); insert(typename CONTAINER_TYPE::value_type(key, data));
LOG("READ");
} }
LOG("DONE");
return is; return is;
} }
virtual std::ostream& saveXml(std::ostream& os, virtual std::ostream& saveXml(std::ostream& os,

@ -9,6 +9,7 @@
#include <iostream> #include <iostream>
#include <sstream> #include <sstream>
#include <cstdlib> #include <cstdlib>
#include <algorithm>
unsigned int MethodTrace::_level(0); unsigned int MethodTrace::_level(0);
@ -310,6 +311,25 @@ namespace xml {
_contents.push_back(o.clone(this).release()); _contents.push_back(o.clone(this).release());
return *this; return *this;
} }
//! Removes a given child node.
Node& Node::remove(Node& n) throw(access_error) {
Contents::iterator it(std::find(_contents.begin(), _contents.end(), &n));
if (it==_contents.end()) throw access_error(*this, n.name());
_contents.erase(it);
return *this;
}
//! Removes the first child node of a given name.
Node& Node::remove(const std::string& n) throw(access_error) {
Node* t(find(n));
if (!t) throw access_error(*this, n);
return remove(*t);
}
//! Removes the child node of a given position.
Node& Node::remove(size_type n) throw(out_of_range) {
if (n>=children()) throw out_of_range(*this, n);
_contents.erase(_contents.begin()+n);
return *this;
}
//! Set a list of attributes. //! Set a list of attributes.
/*! Existing attributes with the same name are overwritten. */ /*! Existing attributes with the same name are overwritten. */
Node& Node::set(const Attributes& o) throw() { Node& Node::set(const Attributes& o) throw() {
@ -1020,6 +1040,12 @@ namespace xml {
} }
Serialize& Serialize::persist(Serialize& ser, Serialize& Serialize::persist(Serialize& ser,
const std::string& name) throw() { const std::string& name) throw() {
if (ser.optional()) {
_xmlNames[name] = &ser;
ser.className(name);
*_xmlFactory<<*ser._xmlFactory;
std::stringstream ss;
} else {
ser.checkInit(); ser.checkInit();
_xmlNames[name] = &ser; _xmlNames[name] = &ser;
xml::Node schema(*_xmlFactory); xml::Node schema(*_xmlFactory);
@ -1029,6 +1055,8 @@ namespace xml {
_xmlFactory = schema<<node; _xmlFactory = schema<<node;
return *this; return *this;
} }
return *this;
}
Serialize& Serialize::persist(bool& member, Serialize& Serialize::persist(bool& member,
const std::string& name) throw() { const std::string& name) throw() {
return persistSimpleType(member, name); return persistSimpleType(member, name);
@ -1123,13 +1151,13 @@ namespace xml {
void Serialize::registerClear(Serialize::ClearFunc clearFunc) { void Serialize::registerClear(Serialize::ClearFunc clearFunc) {
_clear.insert(clearFunc); _clear.insert(clearFunc);
} }
void Serialize::initXmlMembers() {}
void Serialize::clear() throw() { void Serialize::clear() throw() {
for (std::map<std::string, Any>::const_iterator for (std::map<std::string, Any>::const_iterator
it(_xmlNames.begin()); it(_xmlNames.begin());
it!=_xmlNames.end(); ++it) it!=_xmlNames.end(); ++it)
clear(it->second); clear(it->second);
} }
void Serialize::initXmlMembers() {}
void Serialize::reset() throw() { void Serialize::reset() throw() {
_xmlFactory.reset(); _xmlFactory.reset();
_xmlNames.clear(); _xmlNames.clear();
@ -1156,6 +1184,10 @@ namespace xml {
if ((**it)(member)) return; // found match if ((**it)(member)) return; // found match
throw type_not_registered(member.type().name()); throw type_not_registered(member.type().name());
} }
bool Serialize::optional() const throw() {
return false;
}
std::set<Serialize::FromNodeFunc> Serialize::_fromNode; std::set<Serialize::FromNodeFunc> Serialize::_fromNode;
std::set<Serialize::ToNodeFunc> Serialize::_toNode; std::set<Serialize::ToNodeFunc> Serialize::_toNode;
std::set<Serialize::ClearFunc> Serialize::_clear; std::set<Serialize::ClearFunc> Serialize::_clear;
@ -1201,6 +1233,10 @@ namespace xml {
template<> bool assignFromNode<Serialize>(Any member, template<> bool assignFromNode<Serialize>(Any member,
const xml::Node& node) { const xml::Node& node) {
if (!any_cast<Serialize>(&member)) return false; if (!any_cast<Serialize>(&member)) return false;
if (any_cast<Serialize>(member)->optional()) {
(*any_cast<Serialize>(member)).fromNode(member, node);
return true;
}
//! @todo improve this (inefficient) //! @todo improve this (inefficient)
std::stringstream ss; // simple but inefficient: rewrite and reread std::stringstream ss; // simple but inefficient: rewrite and reread
ss<<node; ss<<node;
@ -1214,6 +1250,10 @@ namespace xml {
template<> bool assignToNode<Serialize>(const Any member, template<> bool assignToNode<Serialize>(const Any member,
xml::Node& node) { xml::Node& node) {
if (!any_cast<Serialize>(&member)) return false; if (!any_cast<Serialize>(&member)) return false;
if (any_cast<Serialize>(member)->optional()) {
any_cast<Serialize>(member)->toNode(member, node);
return true;
}
std::stringstream ss; std::stringstream ss;
any_cast<Serialize>(member)->saveXml(ss, node.name()); any_cast<Serialize>(member)->saveXml(ss, node.name());
xml::Factory factory(node); xml::Factory factory(node);
@ -1238,7 +1278,7 @@ namespace xml {
} }
template<> bool clearMember<Serialize>(Any member) { template<> bool clearMember<Serialize>(Any member) {
if (!any_cast<Serialize>(&member)) return false; if (!any_cast<Serialize>(&member)) return false;
any_cast<std::string>(member)->clear(); any_cast<Serialize>(member)->clear();
return true; return true;
} }
// Init To and From Node --------------------------------------------------- // Init To and From Node ---------------------------------------------------

@ -7,12 +7,15 @@ AM_CXXFLAGS += -I ${top_srcdir}/src
AM_LDFLAGS = -L${top_builddir}/src AM_LDFLAGS = -L${top_builddir}/src
LDADD = -lcppunit -lxml-cxx LDADD = -lcppunit -lxml-cxx
check_PROGRAMS = xml_test serialization_test container_serialization_test check_PROGRAMS = xml_test serialization_test \
container_serialization_test optional_serialization_test
TESTS=${check_PROGRAMS} TESTS=${check_PROGRAMS}
xml_test_SOURCES = xml_test.cxx xml_test_SOURCES = xml_test.cxx
serialization_test_SOURCES = serialization_test.cxx serialization_test_SOURCES = serialization_test.cxx
container_serialization_test_SOURCES = container_serialization_test.cxx container_serialization_test_SOURCES = container_serialization_test.cxx
optional_serialization_test_SOURCES = optional_serialization_test.cxx
CLEANFILES = CLEANFILES =
MAINTAINERCLEANFILES = makefile.in MAINTAINERCLEANFILES = makefile.in

@ -0,0 +1,118 @@
/*! @file
@id $Id: serialization_test.cxx 31 2009-04-28 07:36:07Z $
*/
// 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>
#include <cppunit/XmlOutputter.h>
#include <fstream>
class A: public xml::Serialize {
public:
xml::Optional<int> _int;
protected:
void initXmlMembers() {
className("A");
persist(_int, "int");
}
};
class B: public xml::Serialize {
public:
xml::Optional<long> _long;
xml::Optional<short> _short;
protected:
void initXmlMembers() {
className("B");
persist(_long, "long");
persist(_short, "short");
}
};
class B1: public B {
public:
xml::Optional<A> _a1;
xml::Optional<A> _a2;
xml::Optional<A> _a3;
protected:
void initXmlMembers() {
B::initXmlMembers();
className("B1");
persist(_a1, "a1");
persist(_a2, "a2");
persist(_a3, "a3");
}
};
class OptionalSerializationTest: public CppUnit::TestFixture {
public:
void checkOptional() {
std::string with("<A>\n"
"\t<int>13</int>\n"
"</A>");
std::string without("<A/>");
A a;
CPPUNIT_ASSERT_EQUAL(std::string("<A>\n"
"\t<int/>\n"
"</A>"), a.schema());
std::stringstream ss1a(with);
CPPUNIT_ASSERT_NO_THROW(a.loadXml(ss1a));
CPPUNIT_ASSERT_EQUAL(true, (bool)a._int);
CPPUNIT_ASSERT_EQUAL(13, *a._int);
std::stringstream ss1b;
CPPUNIT_ASSERT_NO_THROW(a.saveXml(ss1b));
CPPUNIT_ASSERT_EQUAL(with, ss1b.str());
std::stringstream ss2a(without);
CPPUNIT_ASSERT_NO_THROW(a.loadXml(ss2a));
CPPUNIT_ASSERT_EQUAL(false, (bool)a._int);
std::stringstream ss2b;
CPPUNIT_ASSERT_NO_THROW(a.saveXml(ss2b));
CPPUNIT_ASSERT_EQUAL(without, ss2b.str());
}
void checkMoreOptional() {
std::string first("<B1>\n"
"\t<short>13</short>\n"
"\t<a2/>\n"
"\t<a3>\n"
"\t\t<int>42</int>\n"
"\t</a3>\n"
"</B1>");
B1 b;
std::stringstream ifirst(first);
CPPUNIT_ASSERT_NO_THROW(b.loadXml(ifirst));
CPPUNIT_ASSERT_EQUAL(false, (bool)b._long);
CPPUNIT_ASSERT_EQUAL(true, (bool)b._short);
CPPUNIT_ASSERT_EQUAL((short)13, *b._short);
CPPUNIT_ASSERT_EQUAL(false, (bool)b._a1);
CPPUNIT_ASSERT_EQUAL(true, (bool)b._a2);
CPPUNIT_ASSERT_EQUAL(false, (bool)b._a2->_int);
CPPUNIT_ASSERT_EQUAL(true, (bool)b._a3);
CPPUNIT_ASSERT_EQUAL(true, (bool)b._a3->_int);
CPPUNIT_ASSERT_EQUAL(42, *b._a3->_int);
std::stringstream ofirst;
CPPUNIT_ASSERT_NO_THROW(b.saveXml(ofirst));
CPPUNIT_ASSERT_EQUAL(first, ofirst.str());
}
CPPUNIT_TEST_SUITE(OptionalSerializationTest);
CPPUNIT_TEST(checkOptional);
CPPUNIT_TEST(checkMoreOptional);
CPPUNIT_TEST_SUITE_END();
};
CPPUNIT_TEST_SUITE_REGISTRATION(OptionalSerializationTest);
int main(int argc, char** argv) try {
std::ofstream ofs((*argv+std::string(".xml")).c_str());
CppUnit::TextUi::TestRunner runner;
//runner.setOutputter(new CppUnit::XmlOutputter(&runner.result(), ofs));
runner.addTest(CppUnit::TestFactoryRegistry::getRegistry().makeTest());
return runner.run() ? 0 : 1;
} catch (std::exception& e) {
std::cerr<<"***Exception: "<<e.what()<<std::endl;
return 1;
}
Loading…
Cancel
Save