master
Marc Wäckerlin 15 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. 94
      src/xml-cxx/xml.hxx
  5. 58
      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**) {
{ // Serialization as a member
std::stringstream ss("<b>\n"
@ -56,7 +52,6 @@ int main(int, char**) {
std::cout<<"Text B: "<<b.txt<<std::endl;
std::cout<<"Text A: "<<b.a.txt<<std::endl;
b.saveXml(std::cout)<<std::endl;
std::cout<<fn;
}
return 0;
}

@ -8,7 +8,7 @@ AM_LDFLAGS = -L${top_builddir}/src -lxml-cxx
noinst_PROGRAMS = address node_macros serialization \
contain_serialization inherit_serialization \
list_serialization
list_serialization optional_serialization
address_SOURCES = address.cxx
node_macros_SOURCES = node_macros.cxx
@ -16,5 +16,6 @@ serialization_SOURCES = serialization.cxx
contain_serialization_SOURCES = contain_serialization.cxx
inherit_serialization_SOURCES = inherit_serialization.cxx
list_serialization_SOURCES = list_serialization.cxx
optional_serialization_SOURCES = optional_serialization.cxx
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,
e.g. xml::List instead of @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::stack are not implemented
- Optional values are not yet implemented
- Polymorfic serialisation is not yet implemented
@page rationale Rationale - Limitations of other libraries
@ -787,6 +787,9 @@ namespace xml {
virtual Node& text(const std::string& txt) throw(tag_expected,
type_mismatch);
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();
Node& clear() throw ();
std::string name() const throw();
@ -954,6 +957,7 @@ namespace xml {
private:
friend class stream_error;
friend class Serialize;
template<class T> friend class Optional;
template<class T> friend class Container;
template<class T> friend class AssociativeContainer;
template<class T> friend class AssociativeMap;
@ -1098,9 +1102,9 @@ namespace xml {
Serialize(const Serialize& other) throw();
virtual ~Serialize();
Serialize& operator=(const Serialize& other) throw();
Serialize& className(const std::string& name) throw();
virtual Serialize& persist(Serialize& member,
const std::string& name) throw();
virtual Serialize& className(const std::string& name) throw();
Serialize& persist(Serialize& member,
const std::string& name) throw();
Serialize& persist(bool& member,
const std::string& name) throw();
Serialize& persist(char& member,
@ -1136,6 +1140,7 @@ namespace xml {
static void registerFromNode(FromNodeFunc fromNodeFunc);
static void registerToNode(ToNodeFunc toNodeFunc);
static void registerClear(ClearFunc clearFunc);
virtual void clear() throw();
protected:
virtual void initXmlMembers();
void checkInit(const Serialize* const ser=0) const {
@ -1145,11 +1150,15 @@ namespace xml {
if (!_xmlFactory) const_cast<Serialize*>(this)->initXmlMembers();
}
}
virtual void clear() throw();
/*! @todo Why does @c protected: not work here?!? Children can't
access the members if they are protected! */
public:
//! @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 reset() throw();
void copy(const Serialize& o) throw();
@ -1162,8 +1171,8 @@ namespace xml {
_xmlFactory = schema;
return *this;
}
void fromNode(Any member, const xml::Node& node);
void toNode(const Any member, xml::Node& node) const;
virtual void fromNode(Any member, const xml::Node& node);
virtual void toNode(const Any member, xml::Node& node) const;
std::map<std::string, Any> _xmlNames;
xml::Factory _xmlFactory;
static std::set<FromNodeFunc> _fromNode;
@ -1174,54 +1183,71 @@ namespace xml {
template <class TYPE> class Optional: public Serialize {
public:
Optional() throw() {}
Optional(const Optional& o) throw(): _member(new TYPE(*o._member)) {}
Optional(const TYPE& mem) throw(): _member(new TYPE(mem)) {}
Optional() throw(): _valid(false) {}
Optional(const Optional& o) throw():
_member(o._member), _valid(o.valid) {
}
Optional(const TYPE& mem) throw():
_member(mem), _valid(true) {
}
virtual ~Optional() throw() {}
Optional& operator=(const Optional& o) throw() {
_member = new TYPE(*o._member);
_member = o._member;
_valid = o._valid;
return *this;
}
Optional& operator=(const TYPE& mem) throw() {
_member = new TYPE(mem);
_member = mem;
_valid = true;
return *this;
}
operator bool() const throw() {
return _member.get();
return _valid;
}
const TYPE& operator*() const throw() {
return *_member;
return _member;
}
TYPE& operator*() throw() {
return *_member;
return _member;
}
const TYPE*const operator->() const throw() {
return _member.get();
return &_member;
}
TYPE*const operator->() throw() {
return _member.get();
return &_member;
}
Optional& reset() throw() {
_member.reset();
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);
}
return *this;
}
protected:
virtual void clear() throw() {
_member.reset();
virtual bool optional() const throw() {
return true;
}
virtual std::ostream& saveXml(std::ostream& os,
const std::string& name = std::string())
const throw() {
if (!_member.get()) return os;
checkInit();
xml::Node node(*_xmlFactory);
if (name.size()) node.name(name);
toNode(*_member, node);
os<<node;
return os;
virtual void fromNode(Any member, const xml::Node& node) {
_valid = true;
Serialize::fromNode(Any(&_member), node);
}
virtual void toNode(const Any member, xml::Node& node) const {
if (!_valid) {
node.parent().remove(node);
return;
}
const Any mem(&const_cast<Optional*>(this)->_member);
Serialize::toNode(mem, node);
}
private:
std::auto_ptr<TYPE> _member;
TYPE _member;
bool _valid;
};
//! @addtogroup serialization
@ -1400,17 +1426,13 @@ namespace xml {
if (name.size()) factory->name(name);
std::auto_ptr<xml::Node> node(factory.read(is));
CONTAINER_TYPE::clear();
LOG("READING: "<<*node);
for (xml::Node::size_type i(0); i<node->children(); ++i) {
typename CONTAINER_TYPE::key_type key;
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(&data, (*node)[++i]); // key&value
insert(typename CONTAINER_TYPE::value_type(key, data));
LOG("READ");
}
LOG("DONE");
return is;
}
virtual std::ostream& saveXml(std::ostream& os,

@ -9,6 +9,7 @@
#include <iostream>
#include <sstream>
#include <cstdlib>
#include <algorithm>
unsigned int MethodTrace::_level(0);
@ -310,6 +311,25 @@ namespace xml {
_contents.push_back(o.clone(this).release());
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.
/*! Existing attributes with the same name are overwritten. */
Node& Node::set(const Attributes& o) throw() {
@ -1020,13 +1040,21 @@ namespace xml {
}
Serialize& Serialize::persist(Serialize& ser,
const std::string& name) throw() {
ser.checkInit();
_xmlNames[name] = &ser;
xml::Node schema(*_xmlFactory);
xml::Node node(xml::Node(name).limits(1,1));
for (xml::Node::size_type i(0); i<ser._xmlFactory->children(); ++i)
node<<(*ser._xmlFactory)[i];
_xmlFactory = schema<<node;
if (ser.optional()) {
_xmlNames[name] = &ser;
ser.className(name);
*_xmlFactory<<*ser._xmlFactory;
std::stringstream ss;
} else {
ser.checkInit();
_xmlNames[name] = &ser;
xml::Node schema(*_xmlFactory);
xml::Node node(xml::Node(name).limits(1,1));
for (xml::Node::size_type i(0); i<ser._xmlFactory->children(); ++i)
node<<(*ser._xmlFactory)[i];
_xmlFactory = schema<<node;
return *this;
}
return *this;
}
Serialize& Serialize::persist(bool& member,
@ -1123,13 +1151,13 @@ namespace xml {
void Serialize::registerClear(Serialize::ClearFunc clearFunc) {
_clear.insert(clearFunc);
}
void Serialize::initXmlMembers() {}
void Serialize::clear() throw() {
for (std::map<std::string, Any>::const_iterator
it(_xmlNames.begin());
it!=_xmlNames.end(); ++it)
clear(it->second);
}
void Serialize::initXmlMembers() {}
void Serialize::reset() throw() {
_xmlFactory.reset();
_xmlNames.clear();
@ -1156,6 +1184,10 @@ namespace xml {
if ((**it)(member)) return; // found match
throw type_not_registered(member.type().name());
}
bool Serialize::optional() const throw() {
return false;
}
std::set<Serialize::FromNodeFunc> Serialize::_fromNode;
std::set<Serialize::ToNodeFunc> Serialize::_toNode;
std::set<Serialize::ClearFunc> Serialize::_clear;
@ -1201,6 +1233,10 @@ namespace xml {
template<> bool assignFromNode<Serialize>(Any member,
const xml::Node& node) {
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)
std::stringstream ss; // simple but inefficient: rewrite and reread
ss<<node;
@ -1214,6 +1250,10 @@ namespace xml {
template<> bool assignToNode<Serialize>(const Any member,
xml::Node& node) {
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;
any_cast<Serialize>(member)->saveXml(ss, node.name());
xml::Factory factory(node);
@ -1238,7 +1278,7 @@ namespace xml {
}
template<> bool clearMember<Serialize>(Any member) {
if (!any_cast<Serialize>(&member)) return false;
any_cast<std::string>(member)->clear();
any_cast<Serialize>(member)->clear();
return true;
}
// Init To and From Node ---------------------------------------------------

@ -7,12 +7,15 @@ AM_CXXFLAGS += -I ${top_srcdir}/src
AM_LDFLAGS = -L${top_builddir}/src
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}
xml_test_SOURCES = xml_test.cxx
serialization_test_SOURCES = serialization_test.cxx
container_serialization_test_SOURCES = container_serialization_test.cxx
optional_serialization_test_SOURCES = optional_serialization_test.cxx
CLEANFILES =
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