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-28 07:36:07 +00:00
|
|
|
|
2009-04-02 13:24:59 +00:00
|
|
|
//================================================================= EXCEPTIONS
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
2009-04-06 07:08:52 +00:00
|
|
|
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,
|
2009-04-06 07:08:52 +00:00
|
|
|
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) {
|
|
|
|
}
|
2009-04-06 07:08:52 +00:00
|
|
|
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-06 07:08:52 +00:00
|
|
|
//----------------------------------------------------------------------------
|
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.
|
2009-04-06 07:08:52 +00:00
|
|
|
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.
|
2009-04-06 07:08:52 +00:00
|
|
|
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.
|
2009-04-06 07:08:52 +00:00
|
|
|
const std::string& Attributes::Value::name() const throw() {
|
|
|
|
return first;
|
|
|
|
}
|
2009-04-07 06:59:17 +00:00
|
|
|
//! Get the attribute value.
|
2009-04-06 07:08:52 +00:00
|
|
|
const std::string& Attributes::Value::value() const throw() {
|
|
|
|
return second;
|
|
|
|
}
|
2009-04-07 06:59:17 +00:00
|
|
|
//! Get the attribute value.
|
2009-04-06 07:08:52 +00:00
|
|
|
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. */
|
2009-04-06 07:08:52 +00:00
|
|
|
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-06 07:08:52 +00:00
|
|
|
}
|
2009-04-07 06:59:17 +00:00
|
|
|
//! Convert the attribute to a number.
|
2009-04-06 07:08:52 +00:00
|
|
|
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() {
|
2009-04-06 07:08:52 +00:00
|
|
|
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.
|
2009-04-06 07:08:52 +00:00
|
|
|
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 */
|
2009-04-06 07:08:52 +00:00
|
|
|
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);
|
2009-04-06 07:08:52 +00:00
|
|
|
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));
|
2009-04-06 07:08:52 +00:00
|
|
|
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-06 07:08:52 +00:00
|
|
|
//----------------------------------------------------------------------------
|
2009-04-07 06:59:17 +00:00
|
|
|
//! Empty attribute list
|
|
|
|
Attributes::Attributes() throw() {}
|
|
|
|
//! Attribute list with first one empty attribute given.
|
2009-04-06 07:08:52 +00:00
|
|
|
Attributes::Attributes(const std::string& empty) throw() {
|
2009-04-07 06:59:17 +00:00
|
|
|
insert(Value(empty));
|
2009-04-06 07:08:52 +00:00
|
|
|
}
|
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-06 07:08:52 +00:00
|
|
|
}
|
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);
|
2009-04-06 07:08:52 +00:00
|
|
|
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));
|
2009-04-06 07:08:52 +00:00
|
|
|
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():
|
2009-04-09 07:01:25 +00:00
|
|
|
_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());
|
|
|
|
}
|
2009-04-23 06:41:50 +00:00
|
|
|
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() {
|
2009-04-23 15:10:21 +00:00
|
|
|
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());
|
|
|
|
}
|
2009-04-30 08:28:52 +00:00
|
|
|
//! 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. */
|
2009-04-03 07:07:49 +00:00
|
|
|
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;
|
|
|
|
}
|
2009-04-27 10:48:27 +00:00
|
|
|
//! 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() {
|
2009-04-09 07:01:25 +00:00
|
|
|
_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() {
|
2009-04-09 07:01:25 +00:00
|
|
|
_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.
|
2009-04-09 07:01:25 +00:00
|
|
|
const Attributes& Node::attributes() const throw() {
|
|
|
|
return _attributes;
|
|
|
|
}
|
2009-04-20 06:42:09 +00:00
|
|
|
//! Get the list of attributes.
|
2009-04-09 07:01:25 +00:00
|
|
|
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. */
|
2009-04-09 07:01:25 +00:00
|
|
|
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;
|
2009-04-09 07:01:25 +00:00
|
|
|
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>=0</code> and
|
|
|
|
<code>child<xml::Node::children()</code> */
|
2009-04-02 13:24:59 +00:00
|
|
|
const Node& Node::operator[](Node::size_type child) const
|
2009-04-09 07:01:25 +00:00
|
|
|
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 */
|
2009-04-09 07:01:25 +00:00
|
|
|
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) */
|
2009-04-03 07:07:49 +00:00
|
|
|
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. */
|
2009-04-03 07:07:49 +00:00
|
|
|
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;
|
|
|
|
}
|
2009-04-27 10:48:27 +00:00
|
|
|
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-03 07:07:49 +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")),
|
2009-04-08 06:44:18 +00:00
|
|
|
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;
|
2009-04-03 07:07:49 +00:00
|
|
|
}
|
2009-04-08 06:44:18 +00:00
|
|
|
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-03 07:07:49 +00:00
|
|
|
}
|
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-03 07:07:49 +00:00
|
|
|
}
|
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-03 07:07:49 +00:00
|
|
|
}
|
|
|
|
|
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.
|
2009-04-09 07:01:25 +00:00
|
|
|
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 {
|
2009-04-09 07:01:25 +00:00
|
|
|
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.
|
2009-04-24 07:13:10 +00:00
|
|
|
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)
|
2009-04-03 07:07:49 +00:00
|
|
|
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,
|
2009-04-08 06:44:18 +00:00
|
|
|
access_error, duplicate_attribute,
|
2009-04-09 07:01:25 +00:00
|
|
|
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
|
|
|
}
|
2009-04-27 10:48:27 +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)
|
2009-04-03 07:07:49 +00:00
|
|
|
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,
|
2009-04-09 07:01:25 +00:00
|
|
|
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();
|
2009-04-09 07:01:25 +00:00
|
|
|
while (true) {
|
2009-04-02 13:24:59 +00:00
|
|
|
Tag res(tag(is, node));
|
2009-04-09 07:01:25 +00:00
|
|
|
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: {
|
2009-04-09 07:01:25 +00:00
|
|
|
--_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);
|
2009-04-09 07:01:25 +00:00
|
|
|
} 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: {
|
2009-04-09 07:01:25 +00:00
|
|
|
++_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;
|
2009-04-03 07:07:49 +00:00
|
|
|
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)
|
2009-04-09 07:01:25 +00:00
|
|
|
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,
|
2009-04-09 07:01:25 +00:00
|
|
|
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);
|
2009-04-09 07:01:25 +00:00
|
|
|
Tag tag((Tag){"", START, "", Attributes(), "", false});
|
2009-04-02 13:24:59 +00:00
|
|
|
while (is && is.get(c) && ws(c)); // skip ws
|
2009-04-09 07:01:25 +00:00
|
|
|
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;
|
2009-04-03 07:07:49 +00:00
|
|
|
case '!': case '?':
|
|
|
|
if (last=='<') { // <! tag or <?xml.. starts
|
2009-04-07 14:31:46 +00:00
|
|
|
tag.special+=last;
|
2009-04-03 07:07:49 +00:00
|
|
|
do tag.special+=c; while (c!='>' && is && is.get(c));
|
2009-04-07 14:31:46 +00:00
|
|
|
tag.type=SPECIAL;
|
2009-04-03 07:07:49 +00:00
|
|
|
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
|
2009-04-09 07:01:25 +00:00
|
|
|
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);
|
2009-04-09 07:01:25 +00:00
|
|
|
} 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);
|
2009-04-09 07:01:25 +00:00
|
|
|
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;
|
|
|
|
}
|
2009-04-03 07:07:49 +00:00
|
|
|
}
|
2009-04-09 07:01:25 +00:00
|
|
|
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)
|
2009-04-09 07:01:25 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2009-04-23 15:10:21 +00:00
|
|
|
//============================================================== Serialization
|
|
|
|
|
2009-04-28 07:36:07 +00:00
|
|
|
|
2009-04-23 15:10:21 +00:00
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
Serialize::Serialize() throw() {}
|
|
|
|
Serialize::Serialize(const std::string& className) throw():
|
|
|
|
_xmlFactory(xml::Node(xml::String(className).limits(1,1))) {
|
|
|
|
}
|
2009-04-27 10:48:27 +00:00
|
|
|
Serialize::Serialize(const Serialize& other) throw() {
|
|
|
|
copy(other);
|
|
|
|
}
|
2009-04-24 15:12:44 +00:00
|
|
|
Serialize::~Serialize() {
|
2009-04-30 08:28:52 +00:00
|
|
|
reset();
|
2009-04-27 10:48:27 +00:00
|
|
|
}
|
|
|
|
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;
|
|
|
|
}
|
2009-04-27 10:48:27 +00:00
|
|
|
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() {
|
2009-04-30 08:28:52 +00:00
|
|
|
checkInit();
|
2009-04-27 10:48:27 +00:00
|
|
|
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());
|
2009-04-28 07:36:07 +00:00
|
|
|
it!=_xmlNames.end(); ++it)
|
|
|
|
toNode(it->second, node[it->first]);
|
2009-04-27 10:48:27 +00:00
|
|
|
os<<node;
|
|
|
|
return os;
|
2009-04-23 15:10:21 +00:00
|
|
|
}
|
2009-04-27 10:48:27 +00:00
|
|
|
std::istream& Serialize::loadXml(std::istream& is, const std::string& name) {
|
2009-04-30 08:28:52 +00:00
|
|
|
checkInit();
|
2009-04-27 10:48:27 +00:00
|
|
|
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
|
2009-04-23 15:10:21 +00:00
|
|
|
it(_xmlNames.begin());
|
2009-04-28 07:36:07 +00:00
|
|
|
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);
|
2009-04-27 10:48:27 +00:00
|
|
|
return is;
|
2009-04-23 15:10:21 +00:00
|
|
|
}
|
2009-04-27 10:48:27 +00:00
|
|
|
std::string Serialize::schema() const throw() {
|
2009-04-30 08:28:52 +00:00
|
|
|
checkInit();
|
2009-04-27 10:48:27 +00:00
|
|
|
std::stringstream ss;
|
|
|
|
ss<<*_xmlFactory;
|
|
|
|
return ss.str();
|
|
|
|
}
|
2009-04-30 08:28:52 +00:00
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
2009-04-30 08:28:52 +00:00
|
|
|
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) {
|
2009-04-30 08:28:52 +00:00
|
|
|
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 08:28:52 +00:00
|
|
|
}
|
2009-04-30 15:10:09 +00:00
|
|
|
void Serialize::toNode(const Any member, xml::Node& node) const {
|
2009-04-30 08:28:52 +00:00
|
|
|
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-04-30 08:28:52 +00:00
|
|
|
}
|
2009-05-06 07:13:50 +00:00
|
|
|
bool Serialize::optional() const throw() {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2009-04-30 08:28:52 +00:00
|
|
|
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;
|
2009-04-30 08:28:52 +00:00
|
|
|
|
|
|
|
//=============================================================== Assign Types
|
2009-04-30 15:10:09 +00:00
|
|
|
template<typename TYPE> bool assignFromNode(Any member,
|
2009-04-28 07:36:07 +00:00
|
|
|
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-28 07:36:07 +00:00
|
|
|
}
|
2009-04-30 15:10:09 +00:00
|
|
|
template<typename TYPE> bool assignToNode(const Any member,
|
2009-04-28 07:36:07 +00:00
|
|
|
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-28 07:36:07 +00:00
|
|
|
}
|
2009-04-30 15:10:09 +00:00
|
|
|
template<> bool assignFromNode<bool>(Any member,
|
2009-04-28 07:36:07 +00:00
|
|
|
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-28 07:36:07 +00:00
|
|
|
}
|
2009-04-29 11:58:57 +00:00
|
|
|
return true;
|
2009-04-28 07:36:07 +00:00
|
|
|
}
|
2009-04-30 15:10:09 +00:00
|
|
|
template<> bool assignToNode<bool>(const Any member,
|
2009-04-28 07:36:07 +00:00
|
|
|
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-28 07:36:07 +00:00
|
|
|
}
|
2009-04-30 15:10:09 +00:00
|
|
|
template<> bool assignFromNode<Serialize>(Any member,
|
2009-04-28 07:36:07 +00:00
|
|
|
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-04-30 08:28:52 +00:00
|
|
|
/*
|
2009-05-04 12:47:57 +00:00
|
|
|
Serialize* ser(any_cast<Serialize>(member));
|
2009-04-30 08:28:52 +00:00
|
|
|
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-28 07:36:07 +00:00
|
|
|
}
|
2009-04-30 15:10:09 +00:00
|
|
|
template<> bool assignToNode<Serialize>(const Any member,
|
2009-04-28 07:36:07 +00:00
|
|
|
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
|
|
|
}
|