start of xml::Optional
This commit is contained in:
@@ -12,7 +12,6 @@
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <list>
|
||||
#include <set>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
@@ -20,6 +19,7 @@
|
||||
#include <stdexcept>
|
||||
#include <xml-cxx/any.hxx>
|
||||
|
||||
//! @cond DEBUG
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
@@ -51,7 +51,7 @@ class MethodTrace {
|
||||
} \
|
||||
assert(Y); \
|
||||
}
|
||||
|
||||
//! @endcond
|
||||
|
||||
/*! @mainpage
|
||||
|
||||
@@ -60,11 +60,90 @@ class MethodTrace {
|
||||
- Specify your XML schema in C++ using common C++ syntax,
|
||||
such as shift, dereference, etc.
|
||||
- Verify the schema of XML files while they are read from a stream.
|
||||
- Map and store your own C++ classes to XML and restore them back.
|
||||
|
||||
From the README file:
|
||||
@section basics Basics
|
||||
|
||||
Include file:
|
||||
@code
|
||||
#include <xml-cxx/xml.hxx>
|
||||
@endcode
|
||||
|
||||
Link option:
|
||||
@code
|
||||
-lxml-cxx
|
||||
@endcode
|
||||
|
||||
@section schemaFactory Factory with Schema Declaration
|
||||
|
||||
Small example on how to declare an XML schema (@ref freexml), you
|
||||
may then use <code>template.read(is)</code> to read XML from a
|
||||
stream:
|
||||
|
||||
@code
|
||||
// start with root element: <root id="">
|
||||
xml::Factory template(xml::Node("root").attr("id", xml::optional)
|
||||
// <root> contains any number of <child>
|
||||
<<xml::String("child")
|
||||
// must contain exactly one <other>
|
||||
<<(xml::Node("other").limits(1, 1)
|
||||
// <other> contains min 2 max 4 <text>
|
||||
<<xml::String("text").limits(2, 4)));
|
||||
@endcode
|
||||
|
||||
@section introMacro Using Macros Instead od Literal Text
|
||||
|
||||
If you prefere using constants instead of literal texts, you can
|
||||
declare the node names before you use them (@ref xmlConst):
|
||||
|
||||
@code
|
||||
XML_NODE(root);
|
||||
XML_STRING(child);
|
||||
[...]
|
||||
@endcode
|
||||
|
||||
@code
|
||||
xml::Factory template(xml::node::root.clone()->attr("id", xml::optional)
|
||||
<<*xml::string::child.clone()
|
||||
[...]
|
||||
@endcode
|
||||
|
||||
@section introSer Serialize Classes, Join Classes with XML
|
||||
|
||||
When inheriting from xml::Serialize, your class inherits the
|
||||
methods xml::Serialize::loadXml and
|
||||
xml::Serialize::saveXml. Simply overwrite
|
||||
xml::Serialize::initXmlMembers to make your class serializable
|
||||
(@ref serialization):
|
||||
|
||||
@code
|
||||
class MyClass: public xml::Serialize {
|
||||
[...]
|
||||
protected:
|
||||
void initXmlMembers() {
|
||||
className("MyClass");
|
||||
persist(i, "i");
|
||||
persist(s, "s");
|
||||
persist(l, "l");
|
||||
}
|
||||
private:
|
||||
int i;
|
||||
std::string s;
|
||||
xml::List<std::string> l; // same behaviour as std::list
|
||||
};
|
||||
@endcode
|
||||
|
||||
@section readme The README File
|
||||
|
||||
@include README
|
||||
|
||||
@page Known Limitations
|
||||
@page license License is LGPL 3
|
||||
|
||||
File COPYING from http://www.gnu.org/licenses/lgpl-3.0.txt:
|
||||
|
||||
@include COPYING
|
||||
|
||||
@page limits Known Limitations
|
||||
|
||||
- XML-Comments are only ignored, not read, not stored.
|
||||
- Mixed tags and text is not supported. Tags may either contain
|
||||
@@ -74,6 +153,23 @@ class MethodTrace {
|
||||
(e.g. <p><p><p></p></p></p>)
|
||||
- Exceptions should be optional, best effort otherwise (option "strict")
|
||||
|
||||
@see serializationLimits
|
||||
|
||||
@page serializationLimits Limitations of Serialization
|
||||
|
||||
- Only the following types are intended to be serialized:\n
|
||||
(It is possible to use other techniques, but that's not recommended)
|
||||
- basic C++ types (except pointer)
|
||||
- @c std::string
|
||||
- classes derieved from xml::Serialize
|
||||
- most standard containers, but in their xml-form,
|
||||
e.g. xml::List instead of @c std::list
|
||||
(xml::List inherits @c std::list)
|
||||
- @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
|
||||
|
||||
The initial idea was to map C++ data structures to XML files
|
||||
@@ -98,7 +194,7 @@ class MethodTrace {
|
||||
(http://gsoap.sf.net), boost serialization (http://boost.org) and
|
||||
Qt XML (http://qtsoftware.com).
|
||||
|
||||
@section Qt XML, a typical DOM approach
|
||||
@section qtxml Qt XML, a typical DOM approach
|
||||
|
||||
One is the XML part of the Qt library. These classes can read XML
|
||||
into a DOM tree, but then the user has to check for every detail.
|
||||
@@ -118,25 +214,83 @@ class MethodTrace {
|
||||
...
|
||||
@endcode
|
||||
|
||||
@example address.cxx */
|
||||
This is a typical example of a DOM parser. The main disadvantage
|
||||
here is that we cannot declare a schema. After parsing an XML
|
||||
file, we cannot know whether it is valid with respect to our
|
||||
definition or not. This means that every single access tested.
|
||||
|
||||
xml::Factory lets you specify a schema template and guarantees
|
||||
that the parsed file passed a lot of tests to make sure it fits
|
||||
into the schema. If any test fails, the factory throws an
|
||||
exception.
|
||||
|
||||
@section boostserialization Boost Serialization
|
||||
|
||||
Boost serialization is quite flexible and easy to use, but there
|
||||
are several pitfalls, and worst, the generated XML cannot easily
|
||||
be edited by hand. One of the main problems: If you store lists,
|
||||
you cannot simply add an arbitrary number of list items, but you
|
||||
must first serialize the list size as a number. If you edit the
|
||||
file by hand, the number must exactly match the number of items,
|
||||
or parsing will fail. Error messages (the exceptions) don't help
|
||||
finding the problem within the parsed XML code. The XML format it
|
||||
generates is definitely not made to be edited by hand.
|
||||
|
||||
In fact, in my project that resulted in this new class (CoMoL, see
|
||||
http://comol.sourceforge.net), we first used Boost serialization
|
||||
to read and write XML files. The configuration was then done on
|
||||
the GUI. But this was not comfortable enough, so the configuration
|
||||
was mostly edited by hand. It was a pain then to find any typos in
|
||||
the XML and the storage was too unflexible. So we needed a new
|
||||
apporach, and well here it is. CoMoL now uses the full flexibility
|
||||
of @ref freexml including optional tags and attributes.
|
||||
|
||||
@section gsoap Using gSOAP for Serialization of C++ Structures
|
||||
|
||||
When I was working at Siemens, we often used gSOAP
|
||||
(http://gsoap.sf.net) when we needed mor flexibility in XML
|
||||
declaration than what's possible with @ref boostserialization. But
|
||||
gSOAP has several problems:
|
||||
|
||||
- It is a C framework, not native C++, with all the problems
|
||||
that result from this, i.e. memory management is absolutely
|
||||
awful.
|
||||
- It is a quite a complex problem to copy a gSOAP structure
|
||||
without memory access problems.
|
||||
- Moreover gSOAP is not real C++ code, but it requires a pre
|
||||
processor that generates C++ from a pseudo C++ structure.
|
||||
- It is not designed to Store C++ in XML, but to implement the
|
||||
gSOAP protocol.
|
||||
- And last but not least, the license is not free for all usage.
|
||||
|
||||
@example address.cxx Example
|
||||
|
||||
This is a simple example on how to declare a XML schema and how to
|
||||
use a xml::Factory to restore it from a file. */
|
||||
|
||||
//! @addtogroup freexml
|
||||
//@{
|
||||
/*! @defgroup xmlConst XML Constant Declarations
|
||||
|
||||
There are macros to help you with declaring constants. Chose a C++
|
||||
header fiel, where you want to declare constant names for your xml
|
||||
header file, where you want to declare constant names for your xml
|
||||
nodes.
|
||||
|
||||
Then for every leaf xml::Node name you will use, call
|
||||
XML_NODE(name) and for every xml::String call XML_STRING(name).
|
||||
Then for xml::Node you will use, call XML_NODE(name) and for every
|
||||
xml::String call XML_STRING(othername). After the declaration, you
|
||||
can use the xml::Node as constant @c xml::node::name, the
|
||||
xml::String as constant @c xml::string::name and @c std::string
|
||||
constants for the given node names as @c xml::name::name and @c
|
||||
xml::name::othername.
|
||||
|
||||
For every node with children call XML_PARENT(name, child1, child2 ...).
|
||||
@note If you want to use the xml::Node, xml::String constants in a
|
||||
non constant environment, i.e. to add children, attributes or
|
||||
limits, you must call xml::Node::clone to get a non constant copy.
|
||||
|
||||
@note Node names must be unique. You can not even use the same
|
||||
name for a XML_NODE and a XML_STRING declaration.
|
||||
|
||||
This code is from the examples:
|
||||
|
||||
@include node_macros.cxx
|
||||
@see @ref node_macros.cxx
|
||||
|
||||
@example node_macros.cxx
|
||||
|
||||
@@ -168,12 +322,17 @@ class MethodTrace {
|
||||
names are more often used than nodes. (@em Never use @c using in a
|
||||
C++ header file, you would pollute the scope of all the
|
||||
includers.) */
|
||||
//@}
|
||||
//! @addtogroup xmlConst
|
||||
//@{
|
||||
|
||||
//! Define a string for a node name
|
||||
/*! It is called inside XML_NODE and XML_STRING, so if you work with
|
||||
these two, you don't have to care about XML_NAME. But you can use
|
||||
XML_NAME alone if you don't want the other two macros.
|
||||
|
||||
Declares a constant of type @c std::string with name @c xml::name::NAME.
|
||||
|
||||
@see XML_NODE
|
||||
@see XML_STRING */
|
||||
#define XML_NAME(NAME) \
|
||||
@@ -233,8 +392,14 @@ class MethodTrace {
|
||||
|
||||
//@}
|
||||
|
||||
//! 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++.
|
||||
/*! @defgroup freexml Arbitrary XML Schema Definition and Storage
|
||||
|
||||
Class xml::Node declares an XML DOM node. Storing XML structures
|
||||
has never been a problem, but to read them back again,
|
||||
xml::Factory is needed, which must be given an XML schema
|
||||
description. The XML schema is fully declared in C++, simply by
|
||||
shifting the allowed nodes and attributes into the factory and by
|
||||
setting limits.
|
||||
|
||||
A xml::Factory represents a factory that owns a template and can
|
||||
instanciate XML trees that are valid for the given template from
|
||||
@@ -286,8 +451,15 @@ class MethodTrace {
|
||||
<<x.what()<<std::endl;
|
||||
}
|
||||
@endcode */
|
||||
|
||||
//! Everything is in namespace xml
|
||||
namespace xml {
|
||||
|
||||
|
||||
//! @addtogroup freexml
|
||||
//@{
|
||||
|
||||
//! @cond INTERNAL
|
||||
|
||||
//============================================================================
|
||||
//! Type of an xml node.
|
||||
/*! Only start nodes and empty nodes may have attributes. */
|
||||
@@ -300,6 +472,9 @@ namespace xml {
|
||||
//! a xml start indication <code><?xml?></code>
|
||||
//! or a document type declaration <code><!DOCTYPE ...></code>
|
||||
};
|
||||
|
||||
//! @endcond
|
||||
|
||||
//! Declares an attribute to be mandatory.
|
||||
const bool mandatory(true);
|
||||
//! Declares an attribute to be optional.
|
||||
@@ -311,6 +486,10 @@ namespace xml {
|
||||
class Node;
|
||||
class Factory;
|
||||
|
||||
//@}
|
||||
//! @defgroup exceptions Exception classes
|
||||
//@{
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
class exception: public std::exception {
|
||||
public:
|
||||
@@ -330,6 +509,9 @@ namespace xml {
|
||||
exception("serialized node type is not registered\ntype: "
|
||||
+type+"\nname: "+name, t) {
|
||||
}
|
||||
type_not_registered(std::string type):
|
||||
exception("serialized node type is not registered\ntype: "+type) {
|
||||
}
|
||||
};
|
||||
//----------------------------------------------------------------------------
|
||||
class empty_attribute_list: public exception {
|
||||
@@ -421,6 +603,7 @@ namespace xml {
|
||||
stream_error("mismatching end tag", t, is, tag, c) {
|
||||
}
|
||||
};
|
||||
//----------------------------------------------------------------------------
|
||||
class missing_end_tag: public stream_error {
|
||||
public:
|
||||
missing_end_tag(const Node& t, std::istream& is, const Tag& tag, char c=0)
|
||||
@@ -428,6 +611,7 @@ namespace xml {
|
||||
stream_error("missing end tag, end of file reached", t, is, tag, c) {
|
||||
}
|
||||
};
|
||||
//----------------------------------------------------------------------------
|
||||
class wrong_start_tag: public stream_error {
|
||||
public:
|
||||
wrong_start_tag(const Node& t, std::istream& is, const Tag& tag, char c=0)
|
||||
@@ -435,6 +619,7 @@ namespace xml {
|
||||
stream_error("start tag does not match expected tag", t, is, tag, c) {
|
||||
}
|
||||
};
|
||||
//----------------------------------------------------------------------------
|
||||
class second_slash_in_tag: public stream_error {
|
||||
public:
|
||||
second_slash_in_tag(const Node& t, std::istream& is, const Tag& tag,
|
||||
@@ -443,6 +628,7 @@ namespace xml {
|
||||
stream_error("a tag may have no more than one slash", t, is, tag, c) {
|
||||
}
|
||||
};
|
||||
//----------------------------------------------------------------------------
|
||||
class character_after_slash: public stream_error {
|
||||
public:
|
||||
character_after_slash(const Node& t, std::istream& is, const Tag& tag,
|
||||
@@ -452,6 +638,7 @@ namespace xml {
|
||||
t, is, tag, c) {
|
||||
}
|
||||
};
|
||||
//----------------------------------------------------------------------------
|
||||
class attributes_in_end_tag: public stream_error {
|
||||
public:
|
||||
attributes_in_end_tag(const Node& t, std::istream& is, const Tag& tag)
|
||||
@@ -459,6 +646,7 @@ namespace xml {
|
||||
stream_error("attributes are not allowed in end tags",t, is, tag) {
|
||||
}
|
||||
};
|
||||
//----------------------------------------------------------------------------
|
||||
class attribute_value_not_quoted: public stream_error {
|
||||
public:
|
||||
attribute_value_not_quoted(const Node& t, std::istream& is,
|
||||
@@ -468,6 +656,7 @@ namespace xml {
|
||||
t, is, tag, c) {
|
||||
}
|
||||
};
|
||||
//----------------------------------------------------------------------------
|
||||
class duplicate_attribute: public stream_error {
|
||||
public:
|
||||
duplicate_attribute(const Node& t, std::istream& is, const Tag& tag,
|
||||
@@ -476,6 +665,7 @@ namespace xml {
|
||||
t, is, tag, 0) {
|
||||
}
|
||||
};
|
||||
//----------------------------------------------------------------------------
|
||||
class illegal_attribute: public stream_error {
|
||||
public:
|
||||
illegal_attribute(const Node& t, std::istream& is, const Tag& tag,
|
||||
@@ -484,6 +674,7 @@ namespace xml {
|
||||
t, is, tag, 0) {
|
||||
}
|
||||
};
|
||||
//----------------------------------------------------------------------------
|
||||
class mandatory_attribute_missing: public stream_error {
|
||||
public:
|
||||
mandatory_attribute_missing(const Node& t, std::istream& is,
|
||||
@@ -492,6 +683,7 @@ namespace xml {
|
||||
t, is, tag, 0) {
|
||||
}
|
||||
};
|
||||
//----------------------------------------------------------------------------
|
||||
class wrong_node_number: public stream_error {
|
||||
public:
|
||||
wrong_node_number(const Node& t, std::istream& is,
|
||||
@@ -510,9 +702,13 @@ namespace xml {
|
||||
return ss.str();
|
||||
}
|
||||
};
|
||||
//! @}
|
||||
|
||||
//============================================================================
|
||||
|
||||
//! @addtogroup freexml
|
||||
//@{
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
//! Map for attribute values.
|
||||
/*! Attributes can be set using method xml::Node::attr(). Check for
|
||||
@@ -570,7 +766,7 @@ namespace xml {
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
//! An xml Node.
|
||||
//! An xml Node that contains child nodes but no text.
|
||||
/*! XML Nodes may contain either text or other nodes, but not both
|
||||
at the same time. This node can hold other nodes. For a Node for
|
||||
text contents, see xml::String. */
|
||||
@@ -639,6 +835,7 @@ namespace xml {
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
//! A leaf node that contains text but no child nodes.
|
||||
class String: public Node {
|
||||
public:
|
||||
String(std::string name,
|
||||
@@ -672,6 +869,7 @@ namespace xml {
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
//! A leaf node that contains only numbers and no child nodes.
|
||||
class UnsignedInteger: public String {
|
||||
public:
|
||||
UnsignedInteger(std::string name, unsigned long i=0,
|
||||
@@ -685,6 +883,52 @@ namespace xml {
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
//! Factory to restore XML structures from a stream.
|
||||
/*! A xml::Factory must be given a template that declares the
|
||||
structure, before the factory can be used. This can be done
|
||||
either at instanciation or later by assignment.
|
||||
|
||||
The template is a xml::Node that specifies the schema of the data
|
||||
that can be loaded from streams through a xml::Factory
|
||||
instance.
|
||||
|
||||
The root element has automatically set the limits 1..1
|
||||
(<code>xml::Node::limits(1, 1)</code>, see xml::Node::limits),
|
||||
which means that the root element must exist exactly once. If
|
||||
you pass another limit, your limit is overwritten and ignored.
|
||||
|
||||
E.g. to load an address, that contains a tag <address>
|
||||
with at least a name and optional an address in it's body, you
|
||||
may write:
|
||||
|
||||
@code
|
||||
xml::Factory addrTpl(xml::Node("address")
|
||||
(<<xml::Node("name").limit(1, 1)
|
||||
(<<xml::String("first").limit(1, 1)
|
||||
<<xml::String("middle") // 0..n -> .limit(0, 0)
|
||||
<<xml::String("last").limit(1, 1))
|
||||
<<(xml::Node("location").max(1)
|
||||
<<xml::String("line").min(1))
|
||||
<<xml::String("country").max(1)));
|
||||
@endcode
|
||||
|
||||
According to this example, a valid XML file could be:
|
||||
|
||||
@verbatim
|
||||
<address>
|
||||
<name>
|
||||
<first>Marc</first>
|
||||
<middle>Roman</middle>
|
||||
<last>Wäckerlin</last>
|
||||
</name>
|
||||
<location>
|
||||
<line>SwissSign AG</line>
|
||||
<line>Pfingstweidstrasse 60b</line>
|
||||
<line>8005 Zürich</line>
|
||||
</location>
|
||||
<country>Schweiz</country>
|
||||
</address>
|
||||
@endverbatim */
|
||||
class Factory {
|
||||
public:
|
||||
Factory(const Node& t) throw();
|
||||
@@ -695,7 +939,8 @@ namespace xml {
|
||||
const Node*const operator->() const throw(factory_not_valid);
|
||||
operator bool() const throw();
|
||||
friend std::ostream& operator<<(std::ostream& os,
|
||||
const Factory& factory) throw();
|
||||
const Factory& factory)
|
||||
throw(factory_not_valid);
|
||||
static std::ostream& print(std::ostream& os, const Node& node,
|
||||
unsigned int level=0) throw();
|
||||
std::auto_ptr<Node> read(std::istream& is)
|
||||
@@ -704,12 +949,14 @@ namespace xml {
|
||||
missing_end_tag, attribute_value_not_quoted, access_error,
|
||||
duplicate_attribute, attributes_in_end_tag,
|
||||
illegal_attribute, mandatory_attribute_missing,
|
||||
wrong_node_number);
|
||||
wrong_node_number, factory_not_valid);
|
||||
void reset() throw();
|
||||
private:
|
||||
friend class stream_error;
|
||||
friend class Serialize;
|
||||
template<class T, class A> friend class List;
|
||||
template<class T> friend class Container;
|
||||
template<class T> friend class AssociativeContainer;
|
||||
template<class T> friend class AssociativeMap;
|
||||
Node& operator*() throw(factory_not_valid);
|
||||
Node*const operator->() throw(factory_not_valid);
|
||||
bool ws(char c) throw();
|
||||
@@ -734,6 +981,7 @@ namespace xml {
|
||||
unsigned long _line;
|
||||
long _open;
|
||||
};
|
||||
//@}
|
||||
|
||||
/*! @defgroup serialization Class Serialization
|
||||
|
||||
@@ -763,74 +1011,87 @@ namespace xml {
|
||||
@section serActual Actual Status
|
||||
|
||||
The following member types are supported
|
||||
- All built-in C++ types are supported
|
||||
- std::string is supported
|
||||
- All built-in C++ types are supported, except enum
|
||||
- @c std::string is supported
|
||||
- Contained classes are supported
|
||||
- Inheritance
|
||||
- @ref serContainer
|
||||
|
||||
The following will be supported soon (ideas):
|
||||
- lists, maps
|
||||
- inheritance
|
||||
@todo The following will be supported soon (ideas):
|
||||
- choices (one of)
|
||||
- choices (polymorfism)
|
||||
- optional members (pointer)
|
||||
- enum (class xml::Enum)
|
||||
|
||||
Pointers cannot be stored.
|
||||
|
||||
There are many ways of implemenation. best practice is to
|
||||
inherit xml::Serialize and to overwrite
|
||||
xml::Serialize::initXmlMembers:
|
||||
|
||||
@code
|
||||
class A: public xml::Serialize {
|
||||
protected:
|
||||
// all persitent members must be registered
|
||||
virtual void initXmlMembers() {
|
||||
className("A"); // giving a class name is very important
|
||||
persist(_anInteger, "anInteger");
|
||||
persist(_aBool, "aBool");
|
||||
persist(_aDouble, "aDouble");
|
||||
persist(_aString, "aString");
|
||||
persist(_anotherString, "anotherString");
|
||||
persist(_aLong, "aLong");
|
||||
}
|
||||
private:
|
||||
int _anInteger;
|
||||
bool _aBool;
|
||||
double _aDouble;
|
||||
std::string _aString;
|
||||
std::string _anotherString;
|
||||
unsigned long _aLong;
|
||||
};
|
||||
@section serBestPract Best Practice and Inheritance
|
||||
|
||||
class B: public xml::Serialize {
|
||||
protected:
|
||||
virtual void initXmlMembers() {
|
||||
className("B");
|
||||
persist(_a); // name must not be given, it's already known
|
||||
persist(_anInteger, "anInteger");
|
||||
}
|
||||
private:
|
||||
A _a; // contains an A
|
||||
int _anInteger;
|
||||
};
|
||||
There are many ways of implemenation (see example @ref
|
||||
serialization.cxx). best practice is to inherit xml::Serialize
|
||||
and to overwrite xml::Serialize::initXmlMembers, as shown in the
|
||||
example @ref serialization.cxx.
|
||||
|
||||
int main(int, char**) {
|
||||
A a;
|
||||
B b;
|
||||
// ... do something with a and b, then write it to stdout:
|
||||
a.saveXml(std::out)<<std::endl;
|
||||
b.saveXml(std::out)<<std::endl;
|
||||
return 0;
|
||||
}
|
||||
@endcode
|
||||
@warning If you do not follow the best practice, you must know
|
||||
what you are doing to prevent crashing: You must know that
|
||||
xml::Serialize stores pointers to the variables given in
|
||||
xml::Serialize::persist. So be careful and don't access
|
||||
xml::Serialize after the referenced variables have been removed
|
||||
from memory.
|
||||
|
||||
@subsection inheritance Inheritance
|
||||
|
||||
If you follow the best practice and inherit from another class,
|
||||
you must first call method xml::Serialize::initXmlMembers of the
|
||||
parent class, then call xml::Serialize::className to set the new
|
||||
name of the child class.
|
||||
|
||||
@section examples Examples
|
||||
|
||||
@see @ref serialization.cxx for the different approaches
|
||||
@see @ref contain_serialization.cxx for containment
|
||||
@see @ref inherit_serialization.cxx for inheritance
|
||||
|
||||
@example serialization.cxx
|
||||
@example contain_serialization.cxx */
|
||||
|
||||
In this example you see several apporoaches on how to connect
|
||||
variables to XML data structures to serialize them in
|
||||
XML. Please note, that <b>only class @c B</b> shows the
|
||||
recommended way of doing it.
|
||||
|
||||
@warning Please note that xml::Serialize stores pointers to the
|
||||
variables that are serialized. If you access xml::Serialize
|
||||
outside of the life-cycle of any of the persistent variables,
|
||||
then your program may crash (in the best case) or even behave in
|
||||
an unexpected way.
|
||||
|
||||
@example contain_serialization.cxx
|
||||
|
||||
Handle containment in the recommended way. It's very simple: If
|
||||
all classes inherit from xml::Serialize, then containment
|
||||
behaves as expected.
|
||||
|
||||
@example inherit_serialization.cxx
|
||||
|
||||
This is an example for inheritance according the recommended way:
|
||||
- There's nothing special for the parent.
|
||||
- The child must do the following in xml::Serialize::initXmlMembers
|
||||
(the order is important!):
|
||||
-# call xml::Serialize::initXmlMembers of the parent
|
||||
-# call xml::Serialize::className to set the new class name
|
||||
-# call xml::Serialize::persist for all child members
|
||||
- The only difference is, that ...
|
||||
- ... the child does not inherit xml::Serialize, but a child of it
|
||||
- ... the child must first call xml::Serialize::initXmlMembers of
|
||||
the parent in it's own xml::Serialize::initXmlMembers */
|
||||
//! @addtogroup serialization
|
||||
//@{
|
||||
|
||||
class Serialize {
|
||||
public:
|
||||
typedef bool(*FromNodeFunc)(Any, const xml::Node&);
|
||||
typedef bool(*ToNodeFunc)(const Any, xml::Node&);
|
||||
typedef bool(*ClearFunc)(Any);
|
||||
//! You must call Serialize::className() if you use this constructor!
|
||||
Serialize() throw();
|
||||
Serialize(const std::string& className) throw();
|
||||
@@ -866,14 +1127,15 @@ namespace xml {
|
||||
const std::string& name) throw();
|
||||
Serialize& persist(std::string& member,
|
||||
const std::string& name) throw();
|
||||
std::ostream& saveXml(std::ostream& os,
|
||||
const std::string& name = std::string())
|
||||
virtual std::ostream& saveXml(std::ostream& os,
|
||||
const std::string& name = std::string())
|
||||
const throw();
|
||||
std::istream& loadXml(std::istream& is,
|
||||
const std::string& name = std::string());
|
||||
virtual std::istream& loadXml(std::istream& is,
|
||||
const std::string& name = std::string());
|
||||
std::string schema() const throw();
|
||||
static void registerFromNode(FromNodeFunc fromNodeFunc);
|
||||
static void registerToNode(ToNodeFunc toNodeFunc);
|
||||
static void registerClear(ClearFunc clearFunc);
|
||||
protected:
|
||||
virtual void initXmlMembers();
|
||||
void checkInit(const Serialize* const ser=0) const {
|
||||
@@ -883,8 +1145,12 @@ namespace xml {
|
||||
if (!_xmlFactory) const_cast<Serialize*>(this)->initXmlMembers();
|
||||
}
|
||||
}
|
||||
private:
|
||||
public: //! @todo
|
||||
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
|
||||
void clear(Any member) throw();
|
||||
void reset() throw();
|
||||
void copy(const Serialize& o) throw();
|
||||
template<typename TYPE>
|
||||
@@ -896,85 +1162,210 @@ namespace xml {
|
||||
_xmlFactory = schema;
|
||||
return *this;
|
||||
}
|
||||
virtual void fromNode(Any member, const xml::Node& node);
|
||||
virtual void toNode(const Any member, xml::Node& node) const;
|
||||
/*
|
||||
template<typename TYPE, class ALLOC>
|
||||
void fromNode(std::list<TYPE, ALLOC>* member, xml::Node& node) {
|
||||
member->clear();
|
||||
for (xml::Node::size_type i(0); i<node.children(); ++i)
|
||||
...
|
||||
}*/
|
||||
void fromNode(Any member, const xml::Node& node);
|
||||
void toNode(const Any member, xml::Node& node) const;
|
||||
std::map<std::string, Any> _xmlNames;
|
||||
xml::Factory _xmlFactory;
|
||||
static std::set<FromNodeFunc> _fromNode;
|
||||
static std::set<ToNodeFunc> _toNode;
|
||||
static std::set<ClearFunc> _clear;
|
||||
//! @endcond
|
||||
};
|
||||
|
||||
const int MAX_NUM(14);
|
||||
|
||||
template<int NUM> struct ToType {typedef Serialize Type;};
|
||||
template<> struct ToType<1> {typedef Serialize Type;};
|
||||
template<> struct ToType<2> {typedef std::string Type;};
|
||||
template<> struct ToType<3> {typedef bool Type;};
|
||||
template<> struct ToType<4> {typedef unsigned char Type;};
|
||||
template<> struct ToType<5> {typedef signed char Type;};
|
||||
template<> struct ToType<6> {typedef char Type;};
|
||||
template<> struct ToType<7> {typedef unsigned short Type;};
|
||||
template<> struct ToType<8> {typedef signed short Type;};
|
||||
template<> struct ToType<9> {typedef unsigned int Type;};
|
||||
template<> struct ToType<10> {typedef signed int Type;};
|
||||
template<> struct ToType<11> {typedef unsigned long Type;};
|
||||
template<> struct ToType<12> {typedef signed long Type;};
|
||||
template<> struct ToType<13> {typedef float Type;};
|
||||
template<> struct ToType<14> {typedef double Type;};
|
||||
|
||||
template<typename T> struct ToNum {static const int NUM = 1;};
|
||||
template<> struct ToNum<Serialize > {static const int NUM = 1;};
|
||||
template<> struct ToNum<std::string > {static const int NUM = 2;};
|
||||
template<> struct ToNum<bool > {static const int NUM = 3;};
|
||||
template<> struct ToNum<unsigned char > {static const int NUM = 4;};
|
||||
template<> struct ToNum<signed char > {static const int NUM = 5;};
|
||||
template<> struct ToNum< char > {static const int NUM = 6;};
|
||||
template<> struct ToNum<unsigned short> {static const int NUM = 7;};
|
||||
template<> struct ToNum<signed short> {static const int NUM = 8;};
|
||||
template<> struct ToNum<unsigned int > {static const int NUM = 9;};
|
||||
template<> struct ToNum<signed int > {static const int NUM = 10;};
|
||||
template<> struct ToNum<unsigned long > {static const int NUM = 11;};
|
||||
template<> struct ToNum<signed long > {static const int NUM = 12;};
|
||||
template<> struct ToNum<float > {static const int NUM = 13;};
|
||||
template<> struct ToNum<double > {static const int NUM = 14;};
|
||||
|
||||
template<typename T> bool isSerialize() {
|
||||
return ToNum<T>::NUM == 1;
|
||||
}
|
||||
|
||||
template <typename T, bool GOOD=(ToNum<T>::NUM==1)> struct Mapper {
|
||||
static Serialize* toSerialize(T& obj) {
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
template <typename T> struct Mapper<T, true> {
|
||||
static Serialize* toSerialize(T& obj) {
|
||||
return dynamic_cast<Serialize*>(&obj);
|
||||
}
|
||||
};
|
||||
|
||||
template<class TYPE, class ALLOC=std::allocator<TYPE> > class List:
|
||||
public std::list<TYPE, ALLOC>, public Serialize {
|
||||
template <class TYPE> class Optional: public Serialize {
|
||||
public:
|
||||
List() {}
|
||||
List(const List& o): std::list<TYPE, ALLOC>(o), Serialize(o) {}
|
||||
List(const std::string& className) throw(): Serialize(className) {}
|
||||
virtual ~List() {}
|
||||
Optional() throw() {}
|
||||
Optional(const Optional& o) throw(): _member(new TYPE(*o._member)) {}
|
||||
Optional(const TYPE& mem) throw(): _member(new TYPE(mem)) {}
|
||||
virtual ~Optional() throw() {}
|
||||
Optional& operator=(const Optional& o) throw() {
|
||||
_member = new TYPE(*o._member);
|
||||
return *this;
|
||||
}
|
||||
Optional& operator=(const TYPE& mem) throw() {
|
||||
_member = new TYPE(mem);
|
||||
return *this;
|
||||
}
|
||||
operator bool() const throw() {
|
||||
return _member.get();
|
||||
}
|
||||
const TYPE& operator*() const throw() {
|
||||
return *_member;
|
||||
}
|
||||
TYPE& operator*() throw() {
|
||||
return *_member;
|
||||
}
|
||||
const TYPE*const operator->() const throw() {
|
||||
return _member.get();
|
||||
}
|
||||
TYPE*const operator->() throw() {
|
||||
return _member.get();
|
||||
}
|
||||
Optional& reset() throw() {
|
||||
_member.reset();
|
||||
return *this;
|
||||
}
|
||||
protected:
|
||||
virtual void clear() throw() {
|
||||
_member.reset();
|
||||
}
|
||||
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;
|
||||
}
|
||||
private:
|
||||
std::auto_ptr<TYPE> _member;
|
||||
};
|
||||
|
||||
//! @addtogroup serialization
|
||||
//@{
|
||||
/*! @defgroup serContainer Serialization of Container
|
||||
|
||||
libxml-cpp can serialize container, such as Lists, Vectors or
|
||||
Maps. Classes that serialize cannot contain standard C++
|
||||
container directly, but they must contain container defined
|
||||
here. For every standard container except @c std::bitset there
|
||||
is a XML representation available.
|
||||
|
||||
The following containers are defined:
|
||||
- xml::DeQue (inherits @c std::deque and xml::Serialize)
|
||||
- xml::List (inherits @c std::list and xml::Serialize)
|
||||
- xml::Map (inherits @c std::map and xml::Serialize)
|
||||
- xml::MultiMap (inherits @c std::multimap and xml::Serialize)
|
||||
- xml::MultiSet (inherits @c std::multiset and xml::Serialize)
|
||||
- xml::Set (inherits @c std::set and xml::Serialize)
|
||||
- xml::Vector (inherits @c std::vector and xml::Serialize)
|
||||
|
||||
E.g. use @c xml::List instead of @c std::list.
|
||||
|
||||
I don't see any necessity to implement @c std::priority_queue,
|
||||
@c std::queue and @c std::stack, they are only restricted
|
||||
interfaces to another container and don't allow random access
|
||||
(which is needed to store them).
|
||||
|
||||
@example list_serialization.cxx */
|
||||
//@}
|
||||
|
||||
//! @cond INTERNAL
|
||||
template<class CONTAINER_TYPE> class Container:
|
||||
public CONTAINER_TYPE,
|
||||
public Serialize {
|
||||
public:
|
||||
Container() {}
|
||||
Container(const Container& o): CONTAINER_TYPE(o), Serialize(o) {}
|
||||
Container(const std::string& className) throw(): Serialize(className) {}
|
||||
virtual ~Container() {}
|
||||
virtual std::istream& loadXml(std::istream& is,
|
||||
const std::string& name = std::string()) {
|
||||
checkInit();
|
||||
xml::Factory factory(_xmlFactory);
|
||||
if (name.size()) factory->name(name);
|
||||
std::auto_ptr<xml::Node> node(factory.read(is));
|
||||
CONTAINER_TYPE::clear();
|
||||
for (xml::Node::size_type i(0); i<node->children(); ++i) {
|
||||
typename CONTAINER_TYPE::value_type tmp;
|
||||
Serialize::fromNode(&tmp, (*node)[i]); // reads into tmp
|
||||
push_back(tmp);
|
||||
}
|
||||
return is;
|
||||
}
|
||||
virtual std::ostream& saveXml(std::ostream& os,
|
||||
const std::string& name = std::string())
|
||||
const throw() {
|
||||
checkInit();
|
||||
xml::Node node(*_xmlFactory);
|
||||
if (name.size()) node.name(name);
|
||||
std::auto_ptr<xml::Node> tpl(node[0].clone());
|
||||
node.clear();
|
||||
for (typename Container::const_iterator it = this->begin();
|
||||
it!=this->end(); ++it) {
|
||||
typename CONTAINER_TYPE::value_type tmp;
|
||||
tmp = *it;
|
||||
std::auto_ptr<xml::Node> item(tpl->clone());
|
||||
Serialize::toNode(&tmp, *item);
|
||||
node<<*item;
|
||||
}
|
||||
os<<node;
|
||||
return os;
|
||||
}
|
||||
protected:
|
||||
virtual void initXmlMembers() {
|
||||
std::string itemName("item");
|
||||
TYPE tmp;
|
||||
LOG("initXmlMembers List for: "<<typeid(TYPE).name());
|
||||
if (isSerialize<TYPE>()) {
|
||||
LOG("Liste von Serialize");
|
||||
Serialize* ser(Mapper<TYPE>::toSerialize(tmp));
|
||||
typename CONTAINER_TYPE::value_type tmp;
|
||||
if (isSerialize<typename CONTAINER_TYPE::value_type>()) {
|
||||
Serialize* ser(Mapper<typename CONTAINER_TYPE::value_type>
|
||||
::toSerialize(tmp));
|
||||
checkInit(ser);
|
||||
itemName = ser->_xmlFactory->name();
|
||||
}
|
||||
_xmlFactory = xml::Node("dummyroot"); // dummy root, (uninitialized exc)
|
||||
persist(tmp, itemName); // add as child of dummyroot
|
||||
(*_xmlFactory)[0].limits(0, 0); // any number of children possible
|
||||
}
|
||||
virtual void clear() throw() {
|
||||
CONTAINER_TYPE::clear();
|
||||
}
|
||||
};
|
||||
|
||||
template<class CONTAINER_TYPE> class AssociativeContainer:
|
||||
public CONTAINER_TYPE,
|
||||
public Serialize {
|
||||
public:
|
||||
AssociativeContainer() {}
|
||||
AssociativeContainer(const AssociativeContainer& o):
|
||||
CONTAINER_TYPE(o), Serialize(o) {
|
||||
}
|
||||
AssociativeContainer(const std::string& className) throw():
|
||||
Serialize(className) {
|
||||
}
|
||||
virtual ~AssociativeContainer() {}
|
||||
virtual std::istream& loadXml(std::istream& is,
|
||||
const std::string& name = std::string()) {
|
||||
checkInit();
|
||||
xml::Factory factory(_xmlFactory);
|
||||
if (name.size()) factory->name(name);
|
||||
std::auto_ptr<xml::Node> node(factory.read(is));
|
||||
CONTAINER_TYPE::clear();
|
||||
for (xml::Node::size_type i(0); i<node->children(); ++i) {
|
||||
typename CONTAINER_TYPE::value_type tmp;
|
||||
Serialize::fromNode(&tmp, (*node)[i]); // reads into tmp
|
||||
insert(tmp);
|
||||
}
|
||||
return is;
|
||||
}
|
||||
virtual std::ostream& saveXml(std::ostream& os,
|
||||
const std::string& name = std::string())
|
||||
const throw() {
|
||||
checkInit();
|
||||
xml::Node node(*_xmlFactory);
|
||||
if (name.size()) node.name(name);
|
||||
std::auto_ptr<xml::Node> tpl(node[0].clone());
|
||||
node.clear();
|
||||
for (typename CONTAINER_TYPE::const_iterator it = this->begin();
|
||||
it!=this->end(); ++it) {
|
||||
typename CONTAINER_TYPE::value_type tmp;
|
||||
tmp = *it;
|
||||
std::auto_ptr<xml::Node> item(tpl->clone());
|
||||
Serialize::toNode(&tmp, *item);
|
||||
node<<*item;
|
||||
}
|
||||
os<<node;
|
||||
return os;
|
||||
}
|
||||
protected:
|
||||
virtual void initXmlMembers() {
|
||||
std::string itemName("item");
|
||||
typename CONTAINER_TYPE::value_type tmp;
|
||||
if (isSerialize<typename CONTAINER_TYPE::value_type>()) {
|
||||
Serialize* ser(Mapper<typename CONTAINER_TYPE::value_type>
|
||||
::toSerialize(tmp));
|
||||
assert(ser);
|
||||
assert(ser!=this);
|
||||
assert((void*)ser==(void*)&tmp);
|
||||
@@ -982,34 +1373,231 @@ namespace xml {
|
||||
itemName = ser->_xmlFactory->name();
|
||||
}
|
||||
_xmlFactory = xml::Node("dummyroot"); // dummy root, (uninitialized exc)
|
||||
persist(tmp, itemName); // add _reference as child of dummyroot
|
||||
persist(tmp, itemName); // add as child of dummyroot
|
||||
(*_xmlFactory)[0].limits(0, 0); // any number of children possible
|
||||
}
|
||||
virtual void fromNode(Any member, const xml::Node& node) {
|
||||
this->clear();
|
||||
for (xml::Node::size_type i(0); i<node.parent().children(); ++i) {
|
||||
TYPE tmp;
|
||||
Serialize::fromNode(&tmp, node.parent()[i]); // reads into tmp
|
||||
push_back(tmp);
|
||||
}
|
||||
}
|
||||
virtual void toNode(const Any member, xml::Node& node) const {
|
||||
std::auto_ptr<xml::Node> tpl(node.clone());
|
||||
xml::Node& parent(node.parent());
|
||||
parent.clear(); // "node" is now invalid
|
||||
for (typename List::const_iterator it = this->begin();
|
||||
it!=this->end(); ++it) {
|
||||
TYPE tmp;
|
||||
tmp = *it;
|
||||
std::auto_ptr<xml::Node> item(tpl->clone());
|
||||
Serialize::toNode(&tmp, *item);
|
||||
parent<<*item;
|
||||
}
|
||||
virtual void clear() throw() {
|
||||
CONTAINER_TYPE::clear();
|
||||
}
|
||||
};
|
||||
|
||||
//@}
|
||||
|
||||
template<class CONTAINER_TYPE> class AssociativeMap:
|
||||
public CONTAINER_TYPE,
|
||||
public Serialize {
|
||||
public:
|
||||
AssociativeMap() {}
|
||||
AssociativeMap(const AssociativeMap& o):
|
||||
CONTAINER_TYPE(o), Serialize(o) {
|
||||
}
|
||||
AssociativeMap(const std::string& className) throw():
|
||||
Serialize(className) {
|
||||
}
|
||||
virtual ~AssociativeMap() {}
|
||||
virtual std::istream& loadXml(std::istream& is,
|
||||
const std::string& name = std::string()) {
|
||||
checkInit();
|
||||
xml::Factory factory(_xmlFactory);
|
||||
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,
|
||||
const std::string& name = std::string())
|
||||
const throw() {
|
||||
checkInit();
|
||||
xml::Node node(*_xmlFactory);
|
||||
if (name.size()) node.name(name);
|
||||
std::auto_ptr<xml::Node> tpl1(node[0].clone());
|
||||
std::auto_ptr<xml::Node> tpl2(node[1].clone());
|
||||
node.clear(); // "node" is now invalid
|
||||
for (typename AssociativeMap::const_iterator it = this->begin();
|
||||
it!=this->end(); ++it) {
|
||||
typename CONTAINER_TYPE::key_type key;
|
||||
typename CONTAINER_TYPE::mapped_type data;
|
||||
key = it->first;
|
||||
data = it->second;
|
||||
std::auto_ptr<xml::Node> item1(tpl1->clone());
|
||||
Serialize::toNode(&key, *item1);
|
||||
std::auto_ptr<xml::Node> item2(tpl2->clone());
|
||||
Serialize::toNode(&data, *item2);
|
||||
node<<*item1<<*item2;
|
||||
}
|
||||
os<<node;
|
||||
return os;
|
||||
}
|
||||
protected:
|
||||
virtual void initXmlMembers() {
|
||||
std::string keyName("key");
|
||||
std::string valueName("value");
|
||||
typename CONTAINER_TYPE::key_type key;
|
||||
typename CONTAINER_TYPE::mapped_type data;
|
||||
if (isSerialize<typename CONTAINER_TYPE::key_type>()) {
|
||||
const Serialize* ser(Mapper<typename CONTAINER_TYPE::key_type>
|
||||
::toSerialize(key));
|
||||
checkInit(ser);
|
||||
keyName = ser->_xmlFactory->name();
|
||||
}
|
||||
if (isSerialize<typename CONTAINER_TYPE::mapped_type>()) {
|
||||
Serialize* ser(Mapper<typename CONTAINER_TYPE::mapped_type>
|
||||
::toSerialize(data));
|
||||
checkInit(ser);
|
||||
valueName = ser->_xmlFactory->name();
|
||||
}
|
||||
_xmlFactory = xml::Node("dummyroot"); // dummy root, (uninitialized exc)
|
||||
persist(key, keyName); // add as child of dummyroot
|
||||
persist(data, valueName); // add as child of dummyroot
|
||||
(*_xmlFactory)[0].limits(0, 0); // any number of children possible
|
||||
(*_xmlFactory)[1].limits(0, 0); // any number of children possible
|
||||
}
|
||||
virtual void clear() throw() {
|
||||
CONTAINER_TYPE::clear();
|
||||
}
|
||||
};
|
||||
//! @endcond
|
||||
|
||||
}
|
||||
|
||||
//! @cond INTERNAL
|
||||
//! @addtogroup serContainer
|
||||
//@{
|
||||
# ifdef __XML_CXX_DECLARE_CONTAINER_CLASS__
|
||||
# error Macro __XML_CXX_DECLARE_CONTAINER_CLASS__ has been used elsewhere
|
||||
# endif
|
||||
# define __XML_CXX_DECLARE_CONTAINER_CLASS__(CONTAINER, STD_CONTAINER) \
|
||||
namespace xml { \
|
||||
template<class TYPE, class ALLOC=std::allocator<TYPE> > \
|
||||
class CONTAINER: \
|
||||
public Container<STD_CONTAINER<TYPE, ALLOC> > { \
|
||||
public: \
|
||||
CONTAINER() {} \
|
||||
CONTAINER(const CONTAINER& o): \
|
||||
Container<STD_CONTAINER<TYPE, ALLOC> >(o) { \
|
||||
} \
|
||||
CONTAINER(const std::string& className) throw(): \
|
||||
Container<STD_CONTAINER<TYPE, ALLOC> >(className) { \
|
||||
} \
|
||||
virtual ~CONTAINER() {} \
|
||||
}; \
|
||||
}
|
||||
# include <list>
|
||||
__XML_CXX_DECLARE_CONTAINER_CLASS__(List, std::list);
|
||||
# include <vector>
|
||||
__XML_CXX_DECLARE_CONTAINER_CLASS__(Vector, std::vector);
|
||||
# include <deque>
|
||||
__XML_CXX_DECLARE_CONTAINER_CLASS__(Deque, std::deque);
|
||||
# undef __XML_CXX_DECLARE_CONTAINER_CLASS__
|
||||
# define __XML_CXX_DECLARE_CONTAINER_CLASS__(CONTAINER, STD_CONTAINER) \
|
||||
namespace xml { \
|
||||
template<class TYPE, class CONT=std::deque<TYPE> > \
|
||||
class CONTAINER: \
|
||||
public AssociativeContainer \
|
||||
<STD_CONTAINER<TYPE, CONT> > { \
|
||||
public: \
|
||||
CONTAINER() {} \
|
||||
CONTAINER(const CONTAINER& o): \
|
||||
AssociativeContainer \
|
||||
<STD_CONTAINER<TYPE, CONT> >(o) { \
|
||||
} \
|
||||
CONTAINER(const std::string& className) throw(): \
|
||||
AssociativeContainer \
|
||||
<STD_CONTAINER<TYPE, CONT> > \
|
||||
(className) { \
|
||||
} \
|
||||
virtual ~CONTAINER() {} \
|
||||
}; \
|
||||
}
|
||||
# include <stack>
|
||||
__XML_CXX_DECLARE_CONTAINER_CLASS__(Stack, std::stack);
|
||||
# include <queue>
|
||||
__XML_CXX_DECLARE_CONTAINER_CLASS__(Queue, std::queue);
|
||||
# undef __XML_CXX_DECLARE_CONTAINER_CLASS__
|
||||
# define __XML_CXX_DECLARE_CONTAINER_CLASS__(CONTAINER, STD_CONTAINER) \
|
||||
namespace xml { \
|
||||
template \
|
||||
<class TYPE, class CONT=std::vector<TYPE>, \
|
||||
class COMPARE=std::less<TYPE>, \
|
||||
class ALLOC=std::allocator<TYPE> > \
|
||||
class CONTAINER: \
|
||||
public AssociativeContainer \
|
||||
<STD_CONTAINER<TYPE, COMPARE, ALLOC> > { \
|
||||
public: \
|
||||
CONTAINER() {} \
|
||||
CONTAINER(const CONTAINER& o): \
|
||||
AssociativeContainer \
|
||||
<STD_CONTAINER<TYPE, COMPARE, ALLOC> >(o) { \
|
||||
} \
|
||||
CONTAINER(const std::string& className) throw(): \
|
||||
AssociativeContainer \
|
||||
<STD_CONTAINER<TYPE, COMPARE, ALLOC> > \
|
||||
(className) { \
|
||||
} \
|
||||
virtual ~CONTAINER() {} \
|
||||
}; \
|
||||
}
|
||||
__XML_CXX_DECLARE_CONTAINER_CLASS__(PriorityQueue, std::priority_queue);
|
||||
# undef __XML_CXX_DECLARE_CONTAINER_CLASS__
|
||||
# define __XML_CXX_DECLARE_CONTAINER_CLASS__(CONTAINER, STD_CONTAINER) \
|
||||
namespace xml { \
|
||||
template<class TYPE, class COMPARE=std::less<TYPE>, \
|
||||
class ALLOC=std::allocator<TYPE> > \
|
||||
class CONTAINER: \
|
||||
public AssociativeContainer \
|
||||
<STD_CONTAINER<TYPE, COMPARE, ALLOC> > { \
|
||||
public: \
|
||||
CONTAINER() {} \
|
||||
CONTAINER(const CONTAINER& o): \
|
||||
AssociativeContainer \
|
||||
<STD_CONTAINER<TYPE, COMPARE, ALLOC> >(o) { \
|
||||
} \
|
||||
CONTAINER(const std::string& className) throw(): \
|
||||
AssociativeContainer \
|
||||
<STD_CONTAINER<TYPE, COMPARE, ALLOC> > \
|
||||
(className) { \
|
||||
} \
|
||||
virtual ~CONTAINER() {} \
|
||||
}; \
|
||||
}
|
||||
# include <set>
|
||||
__XML_CXX_DECLARE_CONTAINER_CLASS__(Set, std::set);
|
||||
__XML_CXX_DECLARE_CONTAINER_CLASS__(MultiSet, std::multiset);
|
||||
# undef __XML_CXX_DECLARE_CONTAINER_CLASS__
|
||||
# define __XML_CXX_DECLARE_CONTAINER_CLASS__(CONTAINER, STD_CONTAINER) \
|
||||
namespace xml { \
|
||||
template<class KEY, class VALUE, class COMPARE=std::less<KEY>, \
|
||||
class ALLOC=std::allocator<std::pair<const KEY, VALUE> > > \
|
||||
class CONTAINER: public AssociativeMap \
|
||||
<STD_CONTAINER<KEY, VALUE, COMPARE, ALLOC> > { \
|
||||
public: \
|
||||
CONTAINER() {} \
|
||||
CONTAINER(const CONTAINER& o): \
|
||||
AssociativeMap \
|
||||
<STD_CONTAINER<KEY, VALUE, COMPARE, ALLOC> >(o) { \
|
||||
} \
|
||||
CONTAINER(const std::string& className) throw(): \
|
||||
AssociativeMap \
|
||||
<STD_CONTAINER<KEY, VALUE, COMPARE, ALLOC> > \
|
||||
(className) { \
|
||||
} \
|
||||
virtual ~CONTAINER() {} \
|
||||
}; \
|
||||
}
|
||||
# include <map>
|
||||
__XML_CXX_DECLARE_CONTAINER_CLASS__(Map, std::map);
|
||||
__XML_CXX_DECLARE_CONTAINER_CLASS__(MultiMap, std::multimap);
|
||||
# undef __XML_CXX_DECLARE_CONTAINER_CLASS__
|
||||
//@}
|
||||
//! @endcond
|
||||
|
||||
#endif
|
||||
|
Reference in New Issue
Block a user