|
|
|
@ -10,6 +10,7 @@ |
|
|
|
|
#include <sstream> |
|
|
|
|
#include <cstdlib> |
|
|
|
|
|
|
|
|
|
#include <cassert> |
|
|
|
|
#include <iomanip> |
|
|
|
|
class MethodTrace { |
|
|
|
|
public: |
|
|
|
@ -33,7 +34,7 @@ class MethodTrace { |
|
|
|
|
}; |
|
|
|
|
unsigned int MethodTrace::_level(0); |
|
|
|
|
#define TRACE MethodTrace XXX_METHOD(this, __PRETTY_FUNCTION__) |
|
|
|
|
#define LOG(X) std::cout<<__PRETTY_FUNCTION__<<"\t**** "<<X<<std::endl |
|
|
|
|
#define LOG(X) std::clog<<__PRETTY_FUNCTION__<<"\t**** "<<X<<std::endl |
|
|
|
|
|
|
|
|
|
namespace xml { |
|
|
|
|
|
|
|
|
@ -105,6 +106,10 @@ namespace xml { |
|
|
|
|
std::istream& is, const Tag& tag, char c) throw(): |
|
|
|
|
exception(reason, t), _pos(is.tellg()), _tag(new Tag(tag)), _char(c) { |
|
|
|
|
} |
|
|
|
|
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; |
|
|
|
|
} |
|
|
|
@ -117,12 +122,14 @@ namespace xml { |
|
|
|
|
if (_char) |
|
|
|
|
ss<<"\nactual character: "<<(_char>31?_char:'?') |
|
|
|
|
<<" (ascii="<<(int)_char<<")"; |
|
|
|
|
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; |
|
|
|
|
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; |
|
|
|
|
} |
|
|
|
|
w = ss.str(); |
|
|
|
|
} |
|
|
|
|
return w.c_str(); |
|
|
|
@ -193,6 +200,12 @@ namespace xml { |
|
|
|
|
l.push_back(second.substr(it, pos-it)); |
|
|
|
|
return l; |
|
|
|
|
} |
|
|
|
|
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(); |
|
|
|
|
} |
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
|
//! Empty attribute list
|
|
|
|
|
Attributes::Attributes() throw() {} |
|
|
|
@ -219,12 +232,13 @@ namespace xml { |
|
|
|
|
//! Nodes must be given a name.
|
|
|
|
|
/*! Unnamed nodes are not allowed, therefore there's no default
|
|
|
|
|
constructor. */ |
|
|
|
|
Node::Node(std::string name, size_type min, size_type max) throw(): |
|
|
|
|
_name(name), _parent(0), _limits(min, max) { |
|
|
|
|
Node::Node(std::string name, |
|
|
|
|
Node::size_type min, Node::size_type max) throw(): |
|
|
|
|
_name(name), _parent(0), _min(min), _max(max) { |
|
|
|
|
} |
|
|
|
|
Node::Node(const Node& o) throw(): |
|
|
|
|
_attributes(o._attributes), _name(o.name()), _parent(0), |
|
|
|
|
_limits(o._limits) { |
|
|
|
|
_min(o._min), _max(o._max) { |
|
|
|
|
for (Contents::const_iterator it(o._contents.begin()); |
|
|
|
|
it!=o._contents.end(); ++it) |
|
|
|
|
_contents.push_back((*it)->clone(this).release()); |
|
|
|
@ -233,7 +247,8 @@ namespace xml { |
|
|
|
|
_attributes=o._attributes; |
|
|
|
|
_name = o.name(); |
|
|
|
|
_parent = 0; |
|
|
|
|
_limits = o._limits; |
|
|
|
|
_min = o._min; |
|
|
|
|
_max = o._max; |
|
|
|
|
for (Contents::const_iterator it(o._contents.begin()); |
|
|
|
|
it!=o._contents.end(); ++it) |
|
|
|
|
_contents.push_back((*it)->clone(this).release()); |
|
|
|
@ -296,6 +311,20 @@ namespace xml { |
|
|
|
|
std::string Node::name() const throw() { |
|
|
|
|
return _name; |
|
|
|
|
} |
|
|
|
|
Node& Node::min(Node::size_type m) throw() { |
|
|
|
|
_min = m; |
|
|
|
|
return *this; |
|
|
|
|
} |
|
|
|
|
Node::size_type Node::min() const throw() { |
|
|
|
|
return _min; |
|
|
|
|
} |
|
|
|
|
Node& Node::max(Node::size_type m) throw() { |
|
|
|
|
_max = m; |
|
|
|
|
return *this; |
|
|
|
|
} |
|
|
|
|
Node::size_type Node::max() const throw() { |
|
|
|
|
return _max; |
|
|
|
|
} |
|
|
|
|
bool Node::isChild() const throw() { |
|
|
|
|
return _parent; |
|
|
|
|
} |
|
|
|
@ -336,8 +365,8 @@ namespace xml { |
|
|
|
|
return _attributes; |
|
|
|
|
} |
|
|
|
|
Node& Node::limits(size_type min, size_type max) throw() { |
|
|
|
|
_limits.first = min; |
|
|
|
|
_limits.second = max; |
|
|
|
|
_min = min; |
|
|
|
|
_min = max; |
|
|
|
|
return *this; |
|
|
|
|
} |
|
|
|
|
Node::List Node::list(const std::string& name) const throw() { |
|
|
|
@ -405,8 +434,13 @@ namespace xml { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
|
String::String(std::string name, const std::string& text) throw(): |
|
|
|
|
Node(name), _text(text) { |
|
|
|
|
String::String(std::string name, |
|
|
|
|
Node::size_type min, Node::size_type max) throw(): |
|
|
|
|
Node(name, min, max) { |
|
|
|
|
} |
|
|
|
|
String::String(std::string name, const std::string& text, |
|
|
|
|
Node::size_type min, Node::size_type max) throw(): |
|
|
|
|
Node(name, min, max), _text(text) { |
|
|
|
|
} |
|
|
|
|
std::auto_ptr<Node> String::clone() const throw() { |
|
|
|
|
return std::auto_ptr<Node>(new String(*this)); |
|
|
|
@ -443,9 +477,11 @@ namespace xml { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
|
UnsignedInteger::UnsignedInteger(std::string name, unsigned long i) throw(): |
|
|
|
|
UnsignedInteger::UnsignedInteger(std::string name, unsigned long i, |
|
|
|
|
size_type min, size_type max) throw(): |
|
|
|
|
String(name, |
|
|
|
|
dynamic_cast<std::stringstream&>(std::stringstream()<<i).str()) { |
|
|
|
|
dynamic_cast<std::stringstream&>(std::stringstream()<<i).str(), |
|
|
|
|
min, max) { |
|
|
|
|
} |
|
|
|
|
std::auto_ptr<Node> UnsignedInteger::clone() const throw() { |
|
|
|
|
return std::auto_ptr<Node>(new UnsignedInteger(*this)); |
|
|
|
@ -482,7 +518,10 @@ namespace xml { |
|
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
|
Factory::Factory(const Node& t) throw(): |
|
|
|
|
_template(xml::Node("<xml::start>")<<t), _line(0) {} |
|
|
|
|
_template(xml::Node("<xml::start>")<<t), _line(0) { |
|
|
|
|
_template[0].min(1); |
|
|
|
|
_template[0].max(1); |
|
|
|
|
} |
|
|
|
|
const Node& Factory::operator*() const throw() { |
|
|
|
|
return _template[0]; |
|
|
|
|
} |
|
|
|
@ -500,21 +539,6 @@ namespace xml { |
|
|
|
|
if (node->children()==0) |
|
|
|
|
throw tag_expected(_template[0], _template[0].name()); |
|
|
|
|
return (*node)[0].clone(); |
|
|
|
|
/*node->clear();
|
|
|
|
|
Tag res; |
|
|
|
|
while (true) { |
|
|
|
|
res = tag(is, _template); |
|
|
|
|
*node<<res.attributes; |
|
|
|
|
switch (res.type) { |
|
|
|
|
case END: throw wrong_end_tag(*node, is, res); |
|
|
|
|
case EMPTY: |
|
|
|
|
return node; // empty
|
|
|
|
|
case START: |
|
|
|
|
return read(is, _template[res.name]); |
|
|
|
|
//! @todo store instead of ignore
|
|
|
|
|
case SPECIAL: break; |
|
|
|
|
} |
|
|
|
|
}*/ |
|
|
|
|
} catch (exception& e) { |
|
|
|
|
e.line(_line); |
|
|
|
|
throw; |
|
|
|
@ -545,22 +569,37 @@ namespace xml { |
|
|
|
|
if (res.name!=node.name()) throw wrong_end_tag(node, is, res); |
|
|
|
|
} return result; |
|
|
|
|
case EMPTY: { |
|
|
|
|
*result<<(node[res.name].clone()->clear()<<res.attributes); |
|
|
|
|
std::auto_ptr<Node> current(node[res.name].clone()); |
|
|
|
|
current->clear()<<res.attributes; |
|
|
|
|
*result<<*checkChildren(node[res.name], current, is); |
|
|
|
|
} break; |
|
|
|
|
case START: { |
|
|
|
|
++_open; |
|
|
|
|
*result<<(*read(is, node[res.name])<<res.attributes); |
|
|
|
|
*result<<(*checkChildren(node[res.name], read(is, node[res.name]), is) |
|
|
|
|
<<res.attributes); |
|
|
|
|
} break; |
|
|
|
|
case SPECIAL: break; //! @todo ignored could be stored
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
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; |
|
|
|
|
} |
|
|
|
|
Tag Factory::tag(std::istream& is, const Node& position) |
|
|
|
|
throw(second_slash_in_tag, character_after_slash, tag_expected, |
|
|
|
|
missing_end_tag, attribute_value_not_quoted, |
|
|
|
|
access_error, duplicate_attribute, attributes_in_end_tag, |
|
|
|
|
illegal_attribute, mandatory_attribute_missing, |
|
|
|
|
wrong_start_tag, wrong_node_number) { |
|
|
|
|
wrong_start_tag) { |
|
|
|
|
char c(0); |
|
|
|
|
Tag tag((Tag){"", START, "", Attributes(), "", false}); |
|
|
|
|
while (is && is.get(c) && ws(c)); // skip ws
|
|
|
|
@ -596,7 +635,8 @@ namespace xml { |
|
|
|
|
if (nameRead) { // read attribute
|
|
|
|
|
if (tag.type!=START) throw attributes_in_end_tag(position, is, tag); |
|
|
|
|
std::string attrname(1, c), attrvalue; |
|
|
|
|
while (is && is.get(c) && c!='=' && c!='>' && !ws(c)) attrname+=c; |
|
|
|
|
while (is && is.get(c) && c!='=' && c!='>' && c!='/' |
|
|
|
|
&& !ws(c)) attrname+=c; |
|
|
|
|
while (ws(c) && is && is.get(c)); // skip ws, search '='
|
|
|
|
|
if (c=='=') { // get the value
|
|
|
|
|
while (is && is.get(c) && ws(c)); // skip ws
|
|
|
|
@ -629,9 +669,9 @@ namespace xml { |
|
|
|
|
else |
|
|
|
|
throw tag_expected(position, tag.text); |
|
|
|
|
} |
|
|
|
|
for (Attributes::const_iterator it |
|
|
|
|
(position[tag.name].attributes().begin()); |
|
|
|
|
it!=position[tag.name].attributes().end(); ++it) |
|
|
|
|
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); |
|
|
|
|