Files
libxml-cxx/src/xml.cxx

1312 lines
47 KiB
C++
Raw Normal View History

2009-04-02 13:24:59 +00:00
/*! @file
@id $Id$
*/
// 1 2 3 4 5 6 7 8
// 45678901234567890123456789012345678901234567890123456789012345678901234567890
2009-04-02 14:47:54 +00:00
#include <xml-cxx/xml.hxx>
2009-04-02 13:24:59 +00:00
#include <iostream>
#include <sstream>
#include <cstdlib>
2009-05-06 07:13:50 +00:00
#include <algorithm>
2009-04-02 13:24:59 +00:00
unsigned int MethodTrace::_level(0);
namespace xml {
2009-04-02 13:24:59 +00:00
//================================================================= EXCEPTIONS
//----------------------------------------------------------------------------
exception::exception(std::string reason) throw():
_what(reason), _node(0) {
}
2009-04-02 13:24:59 +00:00
exception::exception(std::string reason, const Node& t) throw():
_what(reason), _node(t.clone().release()) {
}
exception::~exception() throw() {
delete _node;
}
2009-04-07 14:31:46 +00:00
void exception::line(unsigned long line) throw() {
std::stringstream ss;
ss<<line;
_what += "\nat line: "+ss.str();
}
2009-04-02 13:24:59 +00:00
const char* exception::what() const throw() {
static std::string w;
if (!w.size()) {
if (_node)
if (_node->isChild())
w = _what+"\ntag: "+_node->name()+"\nparent: "+_node->parent().name();
else
w = _what+"\ntag: "+_node->name()+" (root element)";
else
w = _what;
}
return w.c_str();
}
//----------------------------------------------------------------------------
access_error::access_error(const Node& t, const std::string& name) throw():
exception("child not available", t), _name(name) {
}
const char* access_error::what() const throw() {
static std::string w;
if (!w.size()) w = std::string(exception::what())+"\nchild name: "+_name;
return w.c_str();
}
//----------------------------------------------------------------------------
out_of_range::out_of_range(const Node& t, size_t pos) throw():
exception("child not available", t), _pos(pos) {
}
const char* out_of_range::what() const throw() {
static std::stringstream w;
if (!w.str().size()) w<<exception::what()<<"\nchild number: "<<_pos;
return w.str().c_str();
}
//----------------------------------------------------------------------------
cannot_have_children::cannot_have_children(const Node& parent,
const Node& child) throw():
exception("node does not accept child nodes", parent),
_child(child.clone().release()) {
}
cannot_have_children::~cannot_have_children() throw() {
delete _child;
}
const char* cannot_have_children::what() const throw() {
static std::string w;
if (!w.size())
w = std::string(exception::what())+"\nchild name: "+_child->name();
return w.c_str();
}
//----------------------------------------------------------------------------
stream_error::stream_error(const std::string& reason, const Node& t,
std::istream& is, const Tag& tag, char c) throw():
exception(reason, t), _pos(is.tellg()), _tag(new Tag(tag)), _char(c) {
}
2009-04-09 10:53:03 +00:00
stream_error::stream_error(const std::string& reason, const Node& t,
std::istream& is) throw():
exception(reason, t), _pos(is.tellg()), _tag(0), _char(0) {
}
stream_error::~stream_error() throw() {
delete _tag;
2009-04-02 13:24:59 +00:00
}
const char* stream_error::what() const throw() {
static std::string w;
if (!w.size()) {
std::stringstream ss;
ss<<exception::what()
<<"\nposition in stream: "<<_pos;
if (_char)
ss<<"\nactual character: "<<(_char>31?_char:'?')
<<" (ascii="<<(int)_char<<")";
2009-04-09 10:53:03 +00:00
if (_tag) {
ss<<"\ntag type: "<<(_tag->type==START?"START"
:(_tag->type==END?"END"
:(_tag->type==EMPTY?"EMPTY"
:"???? <UNKNOWN>")));
if (_tag->name.size()) ss<<"\nnode name read: "<<_tag->name;
if (_tag->text.size()) ss<<"\ncontained text: "<<_tag->text;
}
2009-04-02 13:24:59 +00:00
w = ss.str();
}
return w.c_str();
}
//============================================================================
//----------------------------------------------------------------------------
2009-04-07 06:59:17 +00:00
//! Copy an attribute.
Attributes::Value::Value(const value_type& o) throw():
Attributes::value_type(o) {
}
//! Construct an empty attribute.
Attributes::Value::Value(const std::string& name) throw():
Attributes::value_type(name, std::string()) {
}
2009-04-07 06:59:17 +00:00
//! Construct an attribute with name an value.
Attributes::Value::Value(const std::string& name,
const std::string& value) throw():
Attributes::value_type(name, value) {
}
2009-04-07 06:59:17 +00:00
//! Assign a value.
Attributes::Value& Attributes::Value::operator=(const std::string& value)
throw() {
second = value;
return *this;
}
//! Get the attribute name.
const std::string& Attributes::Value::name() const throw() {
return first;
}
2009-04-07 06:59:17 +00:00
//! Get the attribute value.
const std::string& Attributes::Value::value() const throw() {
return second;
}
2009-04-07 06:59:17 +00:00
//! Get the attribute value.
std::string& Attributes::Value::value() throw() {
return second;
}
2009-04-07 06:59:17 +00:00
//! Convert the attribute to a boolean.
2009-04-20 06:42:09 +00:00
/*! @return @c true if the value is set and not equal to one of:
@c false @c no @c 0. */
Attributes::Value::operator bool() const throw() {
2010-03-31 15:13:10 +00:00
return bool();
}
//! Convert the attribute to a boolean.
/*! @return @c true if the value is set and not equal to one of:
@c false @c no @c 0. */
bool Attributes::Value::toBool() const throw() {
return !(!second.size()||second=="false"||second=="no"||second=="0");
}
2009-04-07 06:59:17 +00:00
//! Convert the attribute to a number.
Attributes::Value::operator unsigned long() const throw() {
2010-03-31 15:13:10 +00:00
return toNumber();
}
//! Convert the attribute to a number.
unsigned long Attributes::Value::toNumber() const throw() {
std::stringstream ss(second);
int i(0);
ss>>i;
return i;
}
2009-04-07 06:59:17 +00:00
//! Convert the attribute to a space separated list.
Attributes::Value::operator List() const throw() {
return toList();
}
2009-04-20 06:42:09 +00:00
//! Convert the attribute to list.
/*! @param separators a string containing a list of valid separators */
Attributes::List Attributes::Value::toList(const std::string& separators)
const throw() {
List l;
for (std::string::size_type it(0), pos(0);
2009-04-08 15:01:48 +00:00
it!=std::string::npos &&
((pos=second.find_first_of(separators, it)), true);
it=pos!=std::string::npos?++pos:std::string::npos)
2009-04-08 15:01:48 +00:00
if (pos==std::string::npos)
l.push_back(second.substr(it));
else
l.push_back(second.substr(it, pos-it));
return l;
}
2009-04-20 06:42:09 +00:00
//! Get the first value of an attribute containing a list of values.
2009-04-21 07:12:24 +00:00
/*! @copydoc xml::Attributes::Value::toList
@return the first element of the list. */
2009-04-09 10:53:03 +00:00
std::string Attributes::Value::front(const std::string& separators) const
throw(empty_attribute_list) {
List l(toList(separators));
if (!l.size()) throw empty_attribute_list(first);
return l.front();
}
//----------------------------------------------------------------------------
2009-04-07 06:59:17 +00:00
//! Empty attribute list
Attributes::Attributes() throw() {}
//! Attribute list with first one empty attribute given.
Attributes::Attributes(const std::string& empty) throw() {
2009-04-07 06:59:17 +00:00
insert(Value(empty));
}
2009-04-07 06:59:17 +00:00
//! Attribute list with first attribute given.
Attributes::Attributes(const std::string& key,
const std::string& value) throw() {
insert(Value(key, value));
}
2009-04-07 06:59:17 +00:00
//! Add a new key-value pair to the attribute list.
Attributes& Attributes::operator<<(const Attributes::Value& v) throw() {
insert(v);
return *this;
}
2009-04-07 06:59:17 +00:00
//! Add a new empty key to the attribute list.
Attributes& Attributes::operator<<(const std::string& key) throw() {
insert(Value(key));
return *this;
}
2009-04-02 13:24:59 +00:00
//----------------------------------------------------------------------------
2009-04-07 06:59:17 +00:00
//! Nodes must be given a name.
/*! Unnamed nodes are not allowed, therefore there's no default
2009-04-20 06:42:09 +00:00
constructor.
@copydoc xml::Node::limits */
2009-04-09 10:53:03 +00:00
Node::Node(std::string name,
Node::size_type min, Node::size_type max) throw():
_name(name), _parent(0), _min(min), _max(max) {
2009-04-02 13:24:59 +00:00
}
2009-04-20 06:42:09 +00:00
//! Copy node, reset parent.
/*! The parent is reset, the node does not belong to the same parent
2009-04-21 07:12:24 +00:00
as the source of the copy.
2009-04-22 08:25:20 +00:00
@see xml::Node::clone() for more information on the parenting. */
2009-04-02 13:24:59 +00:00
Node::Node(const Node& o) throw():
_attributes(o._attributes), _name(o.name()), _parent(0),
2009-04-09 10:53:03 +00:00
_min(o._min), _max(o._max) {
2009-04-02 13:24:59 +00:00
for (Contents::const_iterator it(o._contents.begin());
it!=o._contents.end(); ++it)
_contents.push_back((*it)->clone(this).release());
}
Node::~Node() throw() {
clear();
}
2009-04-20 06:42:09 +00:00
//! Assign new node, keep parent.
/*! The parent remains unchanged, the node does not belong to the
2009-04-21 07:12:24 +00:00
same parent as the source of the copy.
2009-04-22 08:25:20 +00:00
@see xml::Node::clone() for more information on the parenting. */
2009-04-02 13:24:59 +00:00
Node& Node::operator=(const Node& o) throw() {
clear();
2009-04-02 13:24:59 +00:00
_attributes=o._attributes;
_name = o.name();
2009-04-09 10:53:03 +00:00
_min = o._min;
_max = o._max;
2009-04-02 13:24:59 +00:00
for (Contents::const_iterator it(o._contents.begin());
it!=o._contents.end(); ++it)
_contents.push_back((*it)->clone(this).release());
}
//! Clones But resets the parent reference.
2009-04-20 06:42:09 +00:00
/*! You get a new instance of the node, but detached from the
2009-04-22 08:25:20 +00:00
parent. It is then ready to be inserted below a new parent.
If you clone (or copy) a node, the parent is not copied. This is
because otherwise the new now would need to be appended to the
parent's child list. That's most probably not
intended. Therefore, in a normal copy construction the parent is
set to @c 0 (no parent). Then the new node can be appended to a
parent if needed. In a copy assignment, the parent remains
uncanged and the other data is copied.
The user of this library doesn't have to and is not able to care
about the parenting. */
2009-04-02 13:24:59 +00:00
std::auto_ptr<Node> Node::clone() const throw() {
std::auto_ptr<Node> res(new Node(*this));
res->_parent = 0;
return res;
}
2009-04-20 06:42:09 +00:00
//! Stream XML.
/*! Streams the node including all attributes and children. It is
formatted with new-lines and tabulator indentation for human
readability. */
2009-04-02 13:24:59 +00:00
std::ostream& Node::out(std::ostream& o, unsigned int level) const throw() {
if (_contents.size()) {
o<<std::string(level, '\t')<<'<'<<name();
for (Attributes::const_iterator it(_attributes.begin());
it!=_attributes.end(); ++it)
o<<' '<<it->first<<"=\""<<it->second<<'"';
o<<'>'<<std::endl;
for (Contents::const_iterator it(_contents.begin());
it!=_contents.end(); ++it)
(*it)->out(o, level+1)<<std::endl;
o<<std::string(level, '\t')<<"</"<<name()<<'>';
} else {
o<<std::string(level, '\t')<<'<'<<name();
for (Attributes::const_iterator it(_attributes.begin());
it!=_attributes.end(); ++it)
o<<' '<<it->first<<"=\""<<it->second<<'"';
o<<"/>";
}
return o;
}
2009-04-20 06:42:09 +00:00
//! Get the textual contents of a node.
/*! By default this is the concatenation of all child nodes' texts. */
2009-04-02 13:24:59 +00:00
std::string Node::text() const throw() {
std::string s;
for (Contents::const_iterator it(_contents.begin());
it!=_contents.end(); ++it)
s+=***it;
return s;
}
2009-04-20 06:42:09 +00:00
//! Set a text (forbidden in xml::Node)
/*! This method is only useful for child nodes, where it is
reimplemented. In xml::Node, the parent of all nodes, it throws
xml::tag_expected, since a xml::Node may only contain sub-nodes
(formatted as xml-tags) and no plain text. */
Node& Node::text(const std::string& txt) throw(tag_expected, type_mismatch) {
2009-04-02 13:24:59 +00:00
throw tag_expected(*this, txt);
}
2009-04-20 06:42:09 +00:00
//! Appends a new node at the end of all children.
2009-04-02 13:24:59 +00:00
Node& Node::append(const Node& o) throw(cannot_have_children) {
_contents.push_back(o.clone(this).release());
return *this;
}
2009-05-06 07:13:50 +00:00
//! 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;
}
2009-04-20 06:42:09 +00:00
//! Set a list of attributes.
/*! Existing attributes with the same name are overwritten. */
2009-04-02 13:24:59 +00:00
Node& Node::set(const Attributes& o) throw() {
2009-04-20 06:42:09 +00:00
_attributes.clear();
2009-04-02 13:24:59 +00:00
_attributes.insert(o.begin(), o.end());
return *this;
}
2009-04-20 06:42:09 +00:00
//! Clears content and attributes.
2009-04-02 13:24:59 +00:00
Node& Node::clear() throw () {
for (Contents::const_iterator it(_contents.begin());
it!=_contents.end(); ++it)
delete *it;
_contents.clear();
_attributes.clear();
return *this;
}
2009-04-20 06:42:09 +00:00
//! Get the node's tag name.
2009-04-02 13:24:59 +00:00
std::string Node::name() const throw() {
return _name;
}
//! Set a new node's tag name.
Node& Node::name(const std::string& n) throw() {
_name = n;
return *this;
}
2009-04-20 06:42:09 +00:00
//! Set minimum number of instances (in a xml::Factory).
/*! @copydoc limits */
2009-04-09 10:53:03 +00:00
Node& Node::min(Node::size_type m) throw() {
_min = m;
return *this;
}
2009-04-20 06:42:09 +00:00
//! Get minimum number of instances (in a xml::Factory).
/*! @copydoc limits */
2009-04-09 10:53:03 +00:00
Node::size_type Node::min() const throw() {
return _min;
}
2009-04-20 06:42:09 +00:00
//! Set maximum number of instances (in a xml::Factory).
/*! @copydoc limits */
2009-04-09 10:53:03 +00:00
Node& Node::max(Node::size_type m) throw() {
_max = m;
return *this;
}
2009-04-20 06:42:09 +00:00
//! Get maximum number of instances (in a xml::Factory).
/*! @copydoc limits */
2009-04-09 10:53:03 +00:00
Node::size_type Node::max() const throw() {
return _max;
}
2009-04-20 06:42:09 +00:00
//! @c true if node has a parent.
2009-04-02 13:24:59 +00:00
bool Node::isChild() const throw() {
return _parent;
}
2009-04-20 06:42:09 +00:00
//! Get the parent node.
2009-04-02 13:24:59 +00:00
Node& Node::parent() const throw(no_parent) {
if (!_parent) throw no_parent(*this);
return *_parent;
}
2009-04-20 06:42:09 +00:00
//! Check if a specific attribute is set or not.
2009-04-02 13:24:59 +00:00
bool Node::hasAttr(const std::string& name) const throw() {
return _attributes.find(name)!=_attributes.end();
}
2009-04-20 06:42:09 +00:00
//! Declare an attribute template and specify whether it is mandatory
/*! Used for setting up attributes in xml::Factory:
@code
xml::Factory f(xml::Node("root").attr("aname", xml::mandatory);
@endcode
If a factory reads from a stream, it verifies that only optional
or mandatory attributes are given and that mandatory attributes
are specified. Otherwise reading throws an exception. */
2009-04-02 13:24:59 +00:00
Node& Node::attr(const std::string& name, bool mandatory) throw() {
_attributes[name] = mandatory?"xml::mandatory":"xml::optional";
return *this;
}
2009-04-20 06:42:09 +00:00
//! Declare an attribute with given value.
/*! When used for setting up attributes in xml::Factory, it
specifies an optional attribute with given default value:
@code
xml::Factory f(xml::Node("root").attr("aname", "avalue");
@endcode
If a factory reads from a stream and the specified attribute is
not given, it is set to @c deflt. */
2010-03-31 15:13:10 +00:00
Node& Node::attr(const std::string& name, const std::string& deflt) throw() {
_attributes[name] = deflt;
2009-04-02 13:24:59 +00:00
return *this;
}
2009-04-20 06:42:09 +00:00
//! Get an attribute.
/*! Returns the attribute's value (empty if the attribute is not set) */
2009-04-02 13:24:59 +00:00
std::string Node::attr(const std::string& name) const throw() {
Attributes::const_iterator it(_attributes.find(name));
if (it!=_attributes.end()) return it->second;
return std::string();
}
2009-04-20 06:42:09 +00:00
//! Get an attribute.
/*! Returns the attribute's value (empty if the attribute is not set) */
2009-04-06 14:57:27 +00:00
std::string& Node::attr(const std::string& name) throw() {
2009-04-02 13:24:59 +00:00
return _attributes[name];
}
2009-04-20 06:42:09 +00:00
//! Get an attribute.
/*! Returns an attribute class or throws an exception if the
attribute is not set. This method is useful when you need
conversions or other methods as specified in
xml::Attributes::Value. */
2009-04-08 15:01:48 +00:00
const Attributes::Value Node::attribute(const std::string& name)
const throw(attribute_not_available) {
Attributes::const_iterator it(_attributes.find(name));
if (it!=_attributes.end()) return *it;
throw attribute_not_available(*this, name);
}
2009-04-20 06:42:09 +00:00
//! Get the list of attributes.
const Attributes& Node::attributes() const throw() {
return _attributes;
}
2009-04-20 06:42:09 +00:00
//! Get the list of attributes.
Attributes& Node::attributes() throw() {
return _attributes;
}
2009-04-20 06:42:09 +00:00
//! Pass a minimal and maximal number for this node in a xml file.
/*! Minimal and maximal values are verified when you use the node as
a template in a xml::Factory. When the factory reads a stucture
from a stream through xml::Factory::read, then all the limits
are verified.
There are several ways to declare the limits.
- in the constructor xml::Node::Node
- minimum and maximum using method xml::Node::limits
- using methods xml::Node::min and xml::Node::max separately
It is recommended not to use the constructor, but the methods
xml::Node::limits, xml::Node::min and xml::Node::max, simply for
code readability.
The number @c 0 means unlimited: xml::Node::min(0) means the
value is optional and xml::Node::max(0) means that there is no
upper limit. The only exception for this rule is the root
element of a structure passed to a xml::Factory which must exist
exactly once.
Default is no limits: <code>0..n</code>,
which means that the node is optional and may be instatiated
multiple (infinite, unlimited) times. */
Node& Node::limits(size_type min, size_type max) throw() {
2009-04-09 10:53:03 +00:00
_min = min;
2009-04-09 14:11:39 +00:00
_max = max;
return *this;
}
2009-04-21 07:12:24 +00:00
//! Get all immediate children of a given node name.
2009-04-06 14:57:27 +00:00
Node::List Node::list(const std::string& name) const throw() {
List res;
for (Contents::const_iterator it(_contents.begin());
it!=_contents.end(); ++it)
if ((*it)->_name==name) res.push_back(*it);
return res;
}
2009-04-21 07:12:24 +00:00
//! Check if at least one child node of a given name exists.
2009-04-02 13:24:59 +00:00
bool Node::operator()(const std::string& child) const throw() {
return find(child);
}
2009-04-21 07:12:24 +00:00
//! Append a child at the end.
/*! @copydoc xml::Node::append */
2009-04-02 13:24:59 +00:00
Node& Node::operator<<(const Node& o) throw(cannot_have_children) {
return append(o);
}
2009-04-21 07:12:24 +00:00
//! Add an empty attribute.
/*! @copydoc xml::Node::set */
2009-04-02 13:24:59 +00:00
Node& Node::operator<<(const Attributes& o) throw() {
return set(o);
}
2009-04-21 07:12:24 +00:00
//! Get the number of children.
2009-04-02 13:24:59 +00:00
Node::size_type Node::children() const throw() {
return _contents.size();
}
2009-04-21 07:12:24 +00:00
//! Get a child by child-number (the n-th child).
/*! @param child number of the child to return: <code>child&gt;=0</code> and
<code>child&lt;xml::Node::children()</code> */
2009-04-02 13:24:59 +00:00
const Node& Node::operator[](Node::size_type child) const
throw(out_of_range) try {
2009-04-02 13:24:59 +00:00
return *_contents.at(child);
} catch (...) {
throw out_of_range(*this, child);
}
2009-04-21 07:12:24 +00:00
/*! @copydoc xml::Node::operator[](Node::size_type child) const */
Node& Node::operator[](Node::size_type child) throw(out_of_range) try {
2009-04-02 13:24:59 +00:00
return *_contents.at(child);
} catch (...) {
throw out_of_range(*this, child);
}
2009-04-21 07:12:24 +00:00
//! Get the first child of a given node name.
/*! @return the first child with matching node name */
2009-04-02 13:24:59 +00:00
const Node& Node::operator[](const std::string& child) const
throw(access_error) {
const Node* const t(find(child));
if (!t) throw access_error(*this, child);
return *t;
}
2009-04-21 07:12:24 +00:00
/*! @copydoc xml::Node::operator[](const std::string& child) const */
2009-04-02 13:24:59 +00:00
Node& Node::operator[](const std::string& child) throw(access_error) {
Node* const t(find(child));
if (!t) throw access_error(*this, child);
return *t;
}
2009-04-21 07:12:24 +00:00
//! Get the textual contents of a node.
/*! @copydoc xml::Node::text() */
2009-04-02 13:24:59 +00:00
std::string Node::operator*() const throw() {
return text();
}
2009-04-21 07:12:24 +00:00
//! Set a text (forbidden in xml::Node)
/*! @copydoc xml::Node::text(const std::string& txt) */
Node& Node::operator=(const std::string& contents) throw(tag_expected,
type_mismatch) {
2009-04-02 13:24:59 +00:00
return text(contents);
}
2009-04-21 07:12:24 +00:00
//! Write node in XML format to a stream.
/*! @copydoc xml::Node::out */
2009-04-02 13:24:59 +00:00
std::ostream& operator<<(std::ostream& o, const Node& t) throw() {
return t.out(o);
}
2009-04-21 07:12:24 +00:00
//! Get a pointer to the first child of a given node name.
/*! This method does not throw an exception if the element does not
exist, but returns @c 0. */
2009-04-02 13:24:59 +00:00
Node* Node::find(const std::string& child) const throw() {
for (Contents::const_iterator it(_contents.begin());
it!=_contents.end(); ++it) {
if ((*it)->name()==child) return *it;
}
return 0;
}
2009-04-21 07:12:24 +00:00
//! Clone a node, but assign a new parent.
2009-04-02 13:24:59 +00:00
std::auto_ptr<Node> Node::clone(Node* p) const throw() {
std::auto_ptr<Node> c(clone());
c->_parent = p;
return c;
}
//----------------------------------------------------------------------------
2009-04-21 07:12:24 +00:00
/*! @copydoc Node::Node(std::string name,
Node::size_type min, Node::size_type max) */
2009-04-09 10:53:03 +00:00
String::String(std::string name,
Node::size_type min, Node::size_type max) throw():
Node(name, min, max) {
}
2009-04-21 07:12:24 +00:00
//! Pass the text in the node.
/*! @copydoc Node::Node(std::string name,
Node::size_type min, Node::size_type max) */
2009-04-09 10:53:03 +00:00
String::String(std::string name, const std::string& text,
Node::size_type min, Node::size_type max) throw():
Node(name, min, max), _text(text) {
2009-04-02 13:24:59 +00:00
}
std::auto_ptr<Node> String::clone() const throw() {
return std::auto_ptr<Node>(new String(*this));
}
std::string String::text() const throw() {
return _text;
}
2009-04-21 07:12:24 +00:00
//! An xml::String contains text: Set the text.
/*! Never throws an exception. */
String& String::text(const std::string& txt) throw(tag_expected,
type_mismatch) {
2009-04-02 13:24:59 +00:00
_text = txt;
return *this;
}
std::ostream& String::out(std::ostream& o, unsigned int level) const throw() {
if (_text.size()) {
o<<std::string(level, '\t')<<'<'<<name();
for (Attributes::const_iterator it(_attributes.begin());
it!=_attributes.end(); ++it)
o<<' '<<it->first<<"=\""<<it->second<<'"';
o<<'>'<<_text<<"</"<<name()<<'>';
} else {
o<<std::string(level, '\t')<<'<'<<name();
for (Attributes::const_iterator it(_attributes.begin());
it!=_attributes.end(); ++it)
o<<' '<<it->first<<"=\""<<it->second<<'"';
o<<"/>";
}
return o;
}
2009-04-21 07:12:24 +00:00
//! An xml::String has no child nodes: Always throws an exception.
2009-04-02 13:24:59 +00:00
String& String::append(const Node& o) throw(cannot_have_children) {
throw cannot_have_children(*this, o);
}
2009-04-21 07:12:24 +00:00
//! An xml::String contains text: Set the text.
2009-04-02 13:24:59 +00:00
Node& String::operator=(const std::string& contents) throw() {
return text(contents);
}
2009-04-22 16:10:10 +00:00
String::operator std::string() const throw() {
return text();
}
String::operator bool() const throw() {
bool res;
std::stringstream ss(text());
ss>>res;
return res;
}
String::operator char() const throw() {
char res;
std::stringstream ss(text());
ss>>res;
return res;
}
2009-04-22 16:10:10 +00:00
String::operator signed char() const throw() {
signed char res;
std::stringstream ss(text());
ss>>res;
return res;
}
String::operator unsigned char() const throw() {
unsigned char res;
std::stringstream ss(text());
ss>>res;
return res;
}
String::operator signed short() const throw() {
signed short res;
std::stringstream ss(text());
ss>>res;
return res;
}
String::operator unsigned short() const throw() {
unsigned short res;
std::stringstream ss(text());
ss>>res;
return res;
}
String::operator signed int() const throw() {
signed int res;
std::stringstream ss(text());
ss>>res;
return res;
}
String::operator unsigned int() const throw() {
unsigned int res;
std::stringstream ss(text());
ss>>res;
return res;
}
String::operator signed long() const throw() {
signed long res;
std::stringstream ss(text());
ss>>res;
return res;
}
String::operator unsigned long() const throw() {
unsigned long res;
std::stringstream ss(text());
ss>>res;
return res;
}
String::operator float() const throw() {
float res;
std::stringstream ss(text());
ss>>res;
return res;
}
String::operator double() const throw() {
double res;
std::stringstream ss(text());
ss>>res;
return res;
}
2009-04-02 13:24:59 +00:00
//----------------------------------------------------------------------------
2009-04-21 07:12:24 +00:00
/*! @copydoc Node::Node(std::string name,
Node::size_type min, Node::size_type max) */
2009-04-09 10:53:03 +00:00
UnsignedInteger::UnsignedInteger(std::string name, unsigned long i,
size_type min, size_type max) throw():
2009-04-03 14:02:22 +00:00
String(name,
2009-04-09 10:53:03 +00:00
dynamic_cast<std::stringstream&>(std::stringstream()<<i).str(),
min, max) {
2009-04-03 14:02:22 +00:00
}
std::auto_ptr<Node> UnsignedInteger::clone() const throw() {
return std::auto_ptr<Node>(new UnsignedInteger(*this));
}
2009-04-21 07:12:24 +00:00
//! An xml::UnsignedInteger must only contain an number.
/*! En exception is thrown, if the contents does not match a number. */
2009-04-03 14:02:22 +00:00
UnsignedInteger& UnsignedInteger::text(const std::string& txt)
throw(tag_expected, type_mismatch) {
std::string::size_type
start(txt.find_first_not_of(" \t\n\r")),
last(txt.find_last_not_of(" \t\n\r"));
2009-04-03 14:02:22 +00:00
if (start==std::string::npos) { // empty - set to 0
_text = "0";
return *this;
}
std::string::size_type pos(txt.find_first_not_of("0123456789", start));
if (pos<last || pos==last && last==start)
2009-04-03 14:02:22 +00:00
throw type_mismatch(*this, txt,
"unsigned integer may only contain numbers");
unsigned long i(0);
std::stringstream(txt)>>i;
std::stringstream ss;
ss<<i;
_text = ss.str();
return *this;
}
2009-04-22 08:25:20 +00:00
//! Returns the contents as number.
2009-04-03 14:02:22 +00:00
unsigned long UnsignedInteger::number() const throw() {
return number(*this);
}
2009-04-22 08:25:20 +00:00
//! Returns the contents as number.
2009-04-03 14:02:22 +00:00
unsigned long UnsignedInteger::number(const Node& node) throw() {
unsigned long i(0);
std::stringstream ss(node.text());
ss>>i;
return i;
}
2009-04-02 13:24:59 +00:00
//----------------------------------------------------------------------------
2009-04-22 08:25:20 +00:00
//! To instanciate a factory, a template must be given.
Factory::Factory(const Node& t) throw():
2009-04-09 10:53:03 +00:00
_template(xml::Node("<xml::start>")<<t), _line(0) {
_template[0].min(1);
_template[0].max(1);
}
2009-05-04 12:47:57 +00:00
//! Instanciates an invalid factory. A template must be assigned later.
2009-04-22 16:10:10 +00:00
Factory::Factory() throw():
_template(xml::Node("<xml::start>")), _line(0) {
}
2009-05-04 12:47:57 +00:00
//! Assign a template.
/*! If you don't pass a template at instanciation, you must call
this method later, or you will get xml::factory_not_valid
exceptions when you try to use the factory. */
2009-04-22 16:10:10 +00:00
Factory& Factory::operator=(const Node& t) throw() {
_template = xml::Node("<xml::start>")<<t;
_template[0].min(1);
_template[0].max(1);
}
2009-05-04 12:47:57 +00:00
//! Get the template.
2009-04-22 16:10:10 +00:00
const Node& Factory::operator*() const throw(factory_not_valid) try {
return _template[0];
2009-04-22 16:10:10 +00:00
} catch (...) {
throw factory_not_valid();
}
2009-05-04 12:47:57 +00:00
//! Access the (root node of the) template.
const Node*const Factory::operator->() const throw(factory_not_valid) try {
return &_template[0];
} catch (...) {
throw factory_not_valid();
}
2009-05-04 12:47:57 +00:00
//! Check whether the factory has been given a valid template.
2009-04-22 16:10:10 +00:00
Factory::operator bool() const throw() {
return _template.children()>0;
2009-04-02 13:24:59 +00:00
}
2009-05-04 12:47:57 +00:00
//! Print the factory template's schema in human readable format.
/*! Calls xml::Factory::print */
std::ostream& operator<<(std::ostream& os, const Factory& factory)
throw(factory_not_valid) {
2009-04-09 13:32:15 +00:00
return factory.print(os, *factory);
}
2009-05-04 12:47:57 +00:00
//! Print a node's schema description in human readable format.
/*! @todo May be changed to a XML Schema output later. */
2009-04-09 13:32:15 +00:00
std::ostream& Factory::print(std::ostream& os, const Node& node,
unsigned int level) throw() {
if (node.children()) {
os<<std::string(level, '\t')<<'<'<<node.name();
for (Attributes::const_iterator it(node.attributes().begin());
it!=node.attributes().end(); ++it)
os<<' '<<it->first<<"=\""<<it->second<<'"';
os<<'>';
if (dynamic_cast<const UnsignedInteger*>(&node))
os<<" (Unsigned Integer";
else if (dynamic_cast<const String*>(&node))
os<<" (String";
else
os<<" (Node";
if (node.min()==1 && node.max()==1)
os<<", required exactly once)";
else if (node.min()==1 && node.max()==0)
os<<", required at least once)";
else if (node.min()==0 && node.max()==0)
os<<", 0..n)";
else if (node.min()==0 && node.max()==1)
os<<", optional)";
else
os<<", "<<node.min()<<".."<<node.max()<<")";
os<<std::endl;
for (Node::size_type i(0); i<node.children(); ++i)
print(os, node[i], level+1);
2009-04-09 14:11:39 +00:00
os<<std::string(level, '\t')<<"</"<<node.name()<<'>'<<std::endl;
2009-04-09 13:32:15 +00:00
} else {
os<<std::string(level, '\t')<<'<'<<node.name();
for (Attributes::const_iterator it(node.attributes().begin());
it!=node.attributes().end(); ++it)
os<<' '<<it->first<<"=\""<<it->second<<'"';
os<<"/>";
if (dynamic_cast<const UnsignedInteger*>(&node))
os<<" (Unsigned Integer";
else if (dynamic_cast<const String*>(&node))
os<<" (String";
else
os<<" (Node";
if (node.min()==1 && node.max()==1)
os<<", required exactly once)";
else if (node.min()==1 && node.max()==0)
os<<", required at least once)";
else if (node.min()==0 && node.max()==0)
os<<", 0..n)";
else if (node.min()==0 && node.max()==1)
os<<", optional)";
else
os<<", "<<node.min()<<".."<<node.max()<<")";
os<<std::endl;
}
return os;
}
2009-05-04 12:47:57 +00:00
//! Restore a xml::Node tree from a stream, according to the given schema.
2009-04-02 13:24:59 +00:00
std::auto_ptr<Node> Factory::read(std::istream& is)
throw(wrong_end_tag, wrong_start_tag, tag_expected, type_mismatch,
second_slash_in_tag,
2009-04-02 13:24:59 +00:00
character_after_slash, missing_end_tag, attribute_value_not_quoted,
access_error, duplicate_attribute,
attributes_in_end_tag,
illegal_attribute, mandatory_attribute_missing,
2009-05-04 12:47:57 +00:00
wrong_node_number, factory_not_valid) {
if (_template.children()==0) throw factory_not_valid();
try {
_line=1;
_open=0;
std::auto_ptr<Node> node(read(is, _template));
if (node->children()==0)
throw tag_expected(_template[0],
"nothing found, possibly empty stream");
return (*node)[0].clone();
} catch (exception& e) {
e.line(_line);
throw;
}
2009-04-07 14:31:46 +00:00
}
void Factory::reset() throw() {
_line = 0;
_open = 0;
_template = xml::Node("<xml::start>");
}
Node& Factory::operator*() throw(factory_not_valid) try {
return _template[0];
} catch (...) {
throw factory_not_valid();
}
Node*const Factory::operator->() throw(factory_not_valid) try {
return &_template[0];
} catch (...) {
throw factory_not_valid();
}
2009-04-07 14:31:46 +00:00
bool Factory::ws(char c) throw() {
static char last(0);
if ((c=='\n'||c=='\r')&&last!='\n'&&last!='\r') ++_line;
last = c;
2009-04-02 13:24:59 +00:00
return c==' '||c=='\t'||c=='\n'||c=='\r';
}
std::auto_ptr<Node> Factory::read(std::istream& is, const Node& node)
throw(wrong_end_tag, wrong_start_tag, tag_expected, type_mismatch,
second_slash_in_tag,
2009-04-02 13:24:59 +00:00
character_after_slash, missing_end_tag, attribute_value_not_quoted,
access_error, duplicate_attribute, attributes_in_end_tag,
illegal_attribute, mandatory_attribute_missing,
wrong_node_number) {
2009-04-02 13:24:59 +00:00
std::auto_ptr<Node> result(node.clone());
result->clear();
while (true) {
2009-04-02 13:24:59 +00:00
Tag res(tag(is, node));
if (!res.found) return result;
2009-04-02 13:24:59 +00:00
if (res.text.size()) result->text(res.text);
switch (res.type) {
case END: {
--_open;
2009-04-02 13:24:59 +00:00
if (res.attributes.size()) throw attributes_in_end_tag(node, is, res);
if (res.name!=node.name()) throw wrong_end_tag(node, is, res);
} return result;
2009-04-02 13:24:59 +00:00
case EMPTY: {
2009-04-09 10:53:03 +00:00
std::auto_ptr<Node> current(node[res.name].clone());
current->clear()<<res.attributes;
*result<<*checkChildren(node[res.name], current, is);
2009-04-02 13:24:59 +00:00
} break;
case START: {
++_open;
2009-04-09 10:53:03 +00:00
*result<<(*checkChildren(node[res.name], read(is, node[res.name]), is)
<<res.attributes);
2009-04-02 13:24:59 +00:00
} break;
case SPECIAL: break; //! @todo ignored could be stored
2009-04-02 13:24:59 +00:00
}
}
}
2009-04-09 10:53:03 +00:00
std::auto_ptr<Node> Factory::checkChildren(const xml::Node& tpl,
std::auto_ptr<Node> node,
std::istream& is) const
throw(wrong_node_number) {
for (Node::size_type i(0); i<tpl.children(); ++i)
if (tpl[i].min()>0 && node->list(tpl[i].name()).size()<tpl[i].min()
|| 0<tpl[i].max() && tpl[i].max()<node->list(tpl[i].name()).size())
throw wrong_node_number(*node, is, tpl[i].name(),
node->list(tpl[i].name()).size(),
tpl[i].min(), tpl[i].max());
return node;
}
2009-04-02 13:24:59 +00:00
Tag Factory::tag(std::istream& is, const Node& position)
throw(second_slash_in_tag, character_after_slash, tag_expected,
2009-04-02 13:24:59 +00:00
missing_end_tag, attribute_value_not_quoted,
access_error, duplicate_attribute, attributes_in_end_tag,
illegal_attribute, mandatory_attribute_missing,
2009-04-09 10:53:03 +00:00
wrong_start_tag) {
2009-04-02 13:24:59 +00:00
char c(0);
Tag tag((Tag){"", START, "", Attributes(), "", false});
2009-04-02 13:24:59 +00:00
while (is && is.get(c) && ws(c)); // skip ws
if (is.eof()) {
if (_open>0)
throw missing_end_tag(position, is, tag);
else
return tag;
}
tag.found = true;
2009-04-02 13:24:59 +00:00
if (c!='<') do tag.text+=c; while (is && is.get(c) && c!='<');
bool nameRead(false);
2009-04-07 14:31:46 +00:00
for (char last(c); is && is.get(c) && c!='>'; last=c) switch (c) {
case '\n': case '\r':
if (last!='\n'&&last!='\r') ++_line;
case ' ': case '\t':
2009-04-02 13:24:59 +00:00
if (!nameRead && tag.name.size()) nameRead=true;
break;
case '/':
if (!nameRead && tag.name.size()) nameRead=true;
if (tag.type!=START) throw second_slash_in_tag(position, is, tag, c);
tag.type = nameRead?EMPTY:END;
break;
case '!': case '?':
if (last=='<') { // <! tag or <?xml.. starts
2009-04-07 14:31:46 +00:00
tag.special+=last;
do tag.special+=c; while (c!='>' && is && is.get(c));
2009-04-07 14:31:46 +00:00
tag.type=SPECIAL;
return tag;
}
2009-04-02 13:24:59 +00:00
default:
if (tag.type==EMPTY) throw character_after_slash(position, is, tag, c);
if (nameRead) { // read attribute
if (tag.type!=START) throw attributes_in_end_tag(position, is, tag);
2009-04-02 13:24:59 +00:00
std::string attrname(1, c), attrvalue;
2009-04-09 10:53:03 +00:00
while (is && is.get(c) && c!='=' && c!='>' && c!='/'
&& !ws(c)) attrname+=c;
2009-04-07 14:58:28 +00:00
while (ws(c) && is && is.get(c)); // skip ws, search '='
2009-04-02 13:24:59 +00:00
if (c=='=') { // get the value
while (is && is.get(c) && ws(c)); // skip ws
if (c!='"')
throw attribute_value_not_quoted(position, is, tag, c, attrname);
while (is && is.get(c) && c!='"') attrvalue+=c;
if (c!='"')
throw attribute_value_not_quoted(position, is, tag, c, attrname);
} else is.unget(); // read too far
2009-04-02 13:24:59 +00:00
if (tag.attributes.find(attrname)!=tag.attributes.end())
throw duplicate_attribute(position, is, tag, attrname);
if (!position(tag.name)) {
if (tag.name.size())
throw wrong_start_tag(position, is, tag);
else
throw tag_expected(position, tag.text);
}
if (position[tag.name].attributes().find(attrname)
==position[tag.name].attributes().end())
throw illegal_attribute(position, is, tag, attrname);
2009-04-02 13:24:59 +00:00
tag.attributes[attrname] = attrvalue;
} else { // part of a tag name
tag.name+=c;
}
}
if (tag.type==START||tag.type==EMPTY) {
if (!position(tag.name)) {
if (tag.name.size())
throw wrong_start_tag(position, is, tag);
else
throw tag_expected(position, tag.text);
}
2009-04-09 10:53:03 +00:00
const xml::Node& node(position[tag.name]);
for (Attributes::const_iterator it(node.attributes().begin());
it!=node.attributes().end(); ++it)
if (tag.attributes.find(it->first)==tag.attributes.end()) {
if (it->second=="xml::mandatory")
throw mandatory_attribute_missing(position, is, tag, it->first);
else if (it->second!="xml::optional")
tag.attributes.insert(*it);
}
}
2009-04-02 13:24:59 +00:00
return tag;
}
//============================================================== Serialization
//----------------------------------------------------------------------------
Serialize::Serialize() throw() {}
Serialize::Serialize(const std::string& className) throw():
_xmlFactory(xml::Node(xml::String(className).limits(1,1))) {
}
Serialize::Serialize(const Serialize& other) throw() {
copy(other);
}
2009-04-24 15:12:44 +00:00
Serialize::~Serialize() {
reset();
}
Serialize& Serialize::operator=(const Serialize& other) throw() {
copy(other);
return *this;
}
Serialize& Serialize::className(const std::string& name) throw() {
xml::Node node(xml::Node(xml::String(name).limits(1,1)));
if (_xmlFactory) {
for (xml::Node::size_type i(0); i<_xmlFactory->children(); ++i)
node<<(*_xmlFactory)[i];
}
_xmlFactory=node;
return *this;
}
Serialize& Serialize::persist(Serialize& ser,
const std::string& name) throw() {
2009-05-06 07:13:50 +00:00
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,
const std::string& name) throw() {
return persistSimpleType(member, name);
}
Serialize& Serialize::persist(char& member,
const std::string& name) throw() {
return persistSimpleType(member, name);
}
Serialize& Serialize::persist(unsigned char& member,
const std::string& name) throw() {
return persistSimpleType(member, name);
}
Serialize& Serialize::persist(signed char& member,
const std::string& name) throw() {
return persistSimpleType(member, name);
}
Serialize& Serialize::persist(unsigned short& member,
const std::string& name) throw() {
return persistSimpleType(member, name);
}
Serialize& Serialize::persist(signed short& member,
const std::string& name) throw() {
return persistSimpleType(member, name);
}
Serialize& Serialize::persist(unsigned int& member,
const std::string& name) throw() {
return persistSimpleType(member, name);
}
Serialize& Serialize::persist(signed int& member,
const std::string& name) throw() {
return persistSimpleType(member, name);
}
Serialize& Serialize::persist(unsigned long& member,
const std::string& name) throw() {
return persistSimpleType(member, name);
}
Serialize& Serialize::persist(signed long& member,
const std::string& name) throw() {
return persistSimpleType(member, name);
}
Serialize& Serialize::persist(float& member,
const std::string& name) throw() {
return persistSimpleType(member, name);
}
Serialize& Serialize::persist(double& member,
const std::string& name) throw() {
return persistSimpleType(member, name);
}
Serialize& Serialize::persist(std::string& member,
const std::string& name) throw() {
return persistSimpleType(member, name);
}
std::ostream& Serialize::saveXml(std::ostream& os,
const std::string& name) const throw() {
checkInit();
xml::Node node(*_xmlFactory);
if (name.size()) node.name(name);
2009-04-30 15:10:09 +00:00
for (std::map<std::string, Any>::const_iterator
2009-04-24 15:12:44 +00:00
it(_xmlNames.begin());
it!=_xmlNames.end(); ++it)
toNode(it->second, node[it->first]);
os<<node;
return os;
}
std::istream& Serialize::loadXml(std::istream& is, const std::string& name) {
checkInit();
xml::Factory factory(_xmlFactory);
if (name.size()) factory->name(name);
std::auto_ptr<xml::Node> node(factory.read(is));
2009-04-30 15:10:09 +00:00
for (std::map<std::string, Any>::const_iterator
it(_xmlNames.begin());
it!=_xmlNames.end(); ++it)
2009-05-04 12:47:57 +00:00
if ((*node)(it->first))
fromNode(it->second, (*node)[it->first]);
else
clear(it->second);
return is;
}
std::string Serialize::schema() const throw() {
checkInit();
std::stringstream ss;
ss<<*_xmlFactory;
return ss.str();
}
void Serialize::registerFromNode(Serialize::FromNodeFunc fromNodeFunc) {
_fromNode.insert(fromNodeFunc);
}
void Serialize::registerToNode(Serialize::ToNodeFunc toNodeFunc) {
_toNode.insert(toNodeFunc);
}
2009-05-04 12:47:57 +00:00
void Serialize::registerClear(Serialize::ClearFunc clearFunc) {
_clear.insert(clearFunc);
}
2009-05-06 07:13:50 +00:00
void Serialize::initXmlMembers() {}
2009-05-04 12:47:57 +00:00
void Serialize::clear() throw() {
for (std::map<std::string, Any>::const_iterator
it(_xmlNames.begin());
it!=_xmlNames.end(); ++it)
clear(it->second);
}
void Serialize::reset() throw() {
_xmlFactory.reset();
_xmlNames.clear();
}
void Serialize::copy(const Serialize& o) throw() {
reset();
initXmlMembers();
}
2009-04-30 15:10:09 +00:00
void Serialize::fromNode(Any member, const xml::Node& node) {
for (std::set<FromNodeFunc>::const_iterator it(_fromNode.begin());
it!=_fromNode.end(); ++it)
if ((**it)(member, node)) return; // found match
2009-05-04 12:47:57 +00:00
throw type_not_registered(member.type().name(), node.name(), node);
}
2009-04-30 15:10:09 +00:00
void Serialize::toNode(const Any member, xml::Node& node) const {
for (std::set<ToNodeFunc>::const_iterator it(_toNode.begin());
it!=_toNode.end(); ++it)
if ((**it)(member, node)) return; // found match
2009-05-04 12:47:57 +00:00
throw type_not_registered(member.type().name(), node.name(), node);
}
void Serialize::clear(Any member) throw() {
for (std::set<ClearFunc>::const_iterator it(_clear.begin());
it!=_clear.end(); ++it)
if ((**it)(member)) return; // found match
throw type_not_registered(member.type().name());
}
2009-05-06 07:13:50 +00:00
bool Serialize::optional() const throw() {
return false;
}
std::set<Serialize::FromNodeFunc> Serialize::_fromNode;
std::set<Serialize::ToNodeFunc> Serialize::_toNode;
2009-05-04 12:47:57 +00:00
std::set<Serialize::ClearFunc> Serialize::_clear;
//=============================================================== Assign Types
2009-04-30 15:10:09 +00:00
template<typename TYPE> bool assignFromNode(Any member,
const xml::Node& node) {
2009-05-04 12:47:57 +00:00
if (!any_cast<TYPE>(&member)) return false;
*any_cast<TYPE>(member) =
2009-04-29 11:58:57 +00:00
(TYPE)dynamic_cast<const xml::String&>(node);
return true;
}
2009-04-30 15:10:09 +00:00
template<typename TYPE> bool assignToNode(const Any member,
xml::Node& node) {
2009-05-04 12:47:57 +00:00
if (!any_cast<TYPE>(&member)) return false;
2009-04-29 11:58:57 +00:00
std::stringstream ss;
2009-05-04 12:47:57 +00:00
ss<<*any_cast<TYPE>(member);
2009-04-29 11:58:57 +00:00
node.text(ss.str());
return true;
}
2009-04-30 15:10:09 +00:00
template<> bool assignFromNode<bool>(Any member,
const xml::Node& node) {
2009-05-04 12:47:57 +00:00
if (member.type()!=typeid(bool)) return false;
2009-04-29 11:58:57 +00:00
std::string s(*dynamic_cast<const xml::String&>(node));
std::string::size_type
start(s.find_first_not_of(" \t\n\r")),
end(s.find_last_not_of(" \t\n\r"));
if (start==std::string::npos) {
2009-05-04 12:47:57 +00:00
*any_cast<bool>(member) = false;
2009-04-29 11:58:57 +00:00
} else {
s = s.substr(start, end-start+1);
2009-05-04 12:47:57 +00:00
*any_cast<bool>(member) =
2009-04-29 11:58:57 +00:00
s!="0" && s!="false" && s!="no" && s!="off";
}
2009-04-29 11:58:57 +00:00
return true;
}
2009-04-30 15:10:09 +00:00
template<> bool assignToNode<bool>(const Any member,
xml::Node& node) {
2009-05-04 12:47:57 +00:00
if (member.type()!=typeid(bool)) return false;
node.text(*any_cast<bool>(member)?"true":"false");
2009-04-29 11:58:57 +00:00
return true;
}
2009-04-30 15:10:09 +00:00
template<> bool assignFromNode<Serialize>(Any member,
const xml::Node& node) {
2009-05-04 12:47:57 +00:00
if (!any_cast<Serialize>(&member)) return false;
2009-05-06 07:13:50 +00:00
if (any_cast<Serialize>(member)->optional()) {
(*any_cast<Serialize>(member)).fromNode(member, node);
return true;
}
2009-04-29 11:58:57 +00:00
//! @todo improve this (inefficient)
std::stringstream ss; // simple but inefficient: rewrite and reread
ss<<node;
2009-05-04 12:47:57 +00:00
any_cast<Serialize>(member)->loadXml(ss, node.name());
/*
2009-05-04 12:47:57 +00:00
Serialize* ser(any_cast<Serialize>(member));
for (xml::Node::size_type i(0); i<node.children(); ++i)
ser->fromNode(ser->_xmlNames[*node[i]], node[i]);*/
2009-04-29 11:58:57 +00:00
return true;
}
2009-04-30 15:10:09 +00:00
template<> bool assignToNode<Serialize>(const Any member,
xml::Node& node) {
2009-05-04 12:47:57 +00:00
if (!any_cast<Serialize>(&member)) return false;
2009-05-06 07:13:50 +00:00
if (any_cast<Serialize>(member)->optional()) {
any_cast<Serialize>(member)->toNode(member, node);
return true;
}
2009-04-29 11:58:57 +00:00
std::stringstream ss;
2009-05-04 12:47:57 +00:00
any_cast<Serialize>(member)->saveXml(ss, node.name());
2009-04-29 11:58:57 +00:00
xml::Factory factory(node);
node = *factory.read(ss);
return true;
}
2009-05-04 12:47:57 +00:00
//================================================================ Clear Types
template<typename TYPE> bool clearMember(Any member) {
if (!any_cast<TYPE>(&member)) return false;
*any_cast<TYPE>(member) = 0;
return true;
}
template<> bool clearMember<bool>(Any member) {
if (member.type()!=typeid(bool)) return false;
*any_cast<bool>(member) = false;
return true;
}
template<> bool clearMember<std::string>(Any member) {
if (member.type()!=typeid(bool)) return false;
any_cast<std::string>(member)->clear();
return true;
}
template<> bool clearMember<Serialize>(Any member) {
if (!any_cast<Serialize>(&member)) return false;
2009-05-06 07:13:50 +00:00
any_cast<Serialize>(member)->clear();
2009-05-04 12:47:57 +00:00
return true;
}
2009-04-29 11:58:57 +00:00
// Init To and From Node ---------------------------------------------------
namespace {
2009-05-04 12:47:57 +00:00
template<int NUM=MAX_NUM> struct RegisterTemplateForStdTypes {
2009-04-29 11:58:57 +00:00
RegisterTemplateForStdTypes<NUM-1> next; // recurse to next until 0
RegisterTemplateForStdTypes() {
Serialize::registerToNode
2009-05-04 12:47:57 +00:00
(&assignToNode<typename ToType<NUM>::Type>);
2009-04-29 11:58:57 +00:00
Serialize::registerFromNode
2009-05-04 12:47:57 +00:00
(&assignFromNode<typename ToType<NUM>::Type>);
Serialize::registerClear
(&clearMember<typename ToType<NUM>::Type>);
2009-04-29 11:58:57 +00:00
}
};
template<> struct RegisterTemplateForStdTypes<0> {}; // stop recursion
static RegisterTemplateForStdTypes<> init; // execute initialisation
}
// ===========================================================================
2009-04-02 13:24:59 +00:00
}