|
|
|
@ -33,7 +33,7 @@ class MethodTrace { |
|
|
|
|
}; |
|
|
|
|
unsigned int MethodTrace::_level(0); |
|
|
|
|
#define TRACE MethodTrace XXX_METHOD(this, __PRETTY_FUNCTION__) |
|
|
|
|
#define LOG(X) std::clog<<__PRETTY_FUNCTION__<<"\t**** "<<X<<std::endl |
|
|
|
|
#define LOG(X) std::cout<<__PRETTY_FUNCTION__<<"\t**** "<<X<<std::endl |
|
|
|
|
|
|
|
|
|
namespace xml { |
|
|
|
|
|
|
|
|
@ -219,11 +219,12 @@ namespace xml { |
|
|
|
|
//! Nodes must be given a name.
|
|
|
|
|
/*! Unnamed nodes are not allowed, therefore there's no default
|
|
|
|
|
constructor. */ |
|
|
|
|
Node::Node(std::string name) throw(): |
|
|
|
|
_name(name), _parent(0) { |
|
|
|
|
Node::Node(std::string name, size_type min, size_type max) throw(): |
|
|
|
|
_name(name), _parent(0), _limits(min, max) { |
|
|
|
|
} |
|
|
|
|
Node::Node(const Node& o) throw(): |
|
|
|
|
_attributes(o._attributes), _name(o.name()), _parent(0) { |
|
|
|
|
_attributes(o._attributes), _name(o.name()), _parent(0), |
|
|
|
|
_limits(o._limits) { |
|
|
|
|
for (Contents::const_iterator it(o._contents.begin()); |
|
|
|
|
it!=o._contents.end(); ++it) |
|
|
|
|
_contents.push_back((*it)->clone(this).release()); |
|
|
|
@ -232,6 +233,7 @@ namespace xml { |
|
|
|
|
_attributes=o._attributes; |
|
|
|
|
_name = o.name(); |
|
|
|
|
_parent = 0; |
|
|
|
|
_limits = o._limits; |
|
|
|
|
for (Contents::const_iterator it(o._contents.begin()); |
|
|
|
|
it!=o._contents.end(); ++it) |
|
|
|
|
_contents.push_back((*it)->clone(this).release()); |
|
|
|
@ -305,7 +307,12 @@ namespace xml { |
|
|
|
|
return _attributes.find(name)!=_attributes.end(); |
|
|
|
|
} |
|
|
|
|
Node& Node::attr(const std::string& name, bool mandatory) throw() { |
|
|
|
|
_attributes[name] = mandatory?"mandatory":"optional"; |
|
|
|
|
_attributes[name] = mandatory?"xml::mandatory":"xml::optional"; |
|
|
|
|
return *this; |
|
|
|
|
} |
|
|
|
|
Node& Node::attr(const std::string& name, const std::string& deflt) |
|
|
|
|
throw() { |
|
|
|
|
_attributes[name] = deflt; |
|
|
|
|
return *this; |
|
|
|
|
} |
|
|
|
|
std::string Node::attr(const std::string& name) const throw() { |
|
|
|
@ -322,6 +329,17 @@ namespace xml { |
|
|
|
|
if (it!=_attributes.end()) return *it; |
|
|
|
|
throw attribute_not_available(*this, name); |
|
|
|
|
} |
|
|
|
|
const Attributes& Node::attributes() const throw() { |
|
|
|
|
return _attributes; |
|
|
|
|
} |
|
|
|
|
Attributes& Node::attributes() throw() { |
|
|
|
|
return _attributes; |
|
|
|
|
} |
|
|
|
|
Node& Node::limits(size_type min, size_type max) throw() { |
|
|
|
|
_limits.first = min; |
|
|
|
|
_limits.second = max; |
|
|
|
|
return *this; |
|
|
|
|
} |
|
|
|
|
Node::List Node::list(const std::string& name) const throw() { |
|
|
|
|
List res; |
|
|
|
|
for (Contents::const_iterator it(_contents.begin()); |
|
|
|
@ -342,12 +360,12 @@ namespace xml { |
|
|
|
|
return _contents.size(); |
|
|
|
|
} |
|
|
|
|
const Node& Node::operator[](Node::size_type child) const |
|
|
|
|
throw(access_error) try { |
|
|
|
|
throw(out_of_range) try { |
|
|
|
|
return *_contents.at(child); |
|
|
|
|
} catch (...) { |
|
|
|
|
throw out_of_range(*this, child); |
|
|
|
|
} |
|
|
|
|
Node& Node::operator[](Node::size_type child) throw(access_error) try { |
|
|
|
|
Node& Node::operator[](Node::size_type child) throw(out_of_range) try { |
|
|
|
|
return *_contents.at(child); |
|
|
|
|
} catch (...) { |
|
|
|
|
throw out_of_range(*this, child); |
|
|
|
@ -463,34 +481,40 @@ namespace xml { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
|
Factory::Factory(const Node& t) throw(): _template(t.clone()), _line(0) {} |
|
|
|
|
Factory::Factory(const Node& t) throw(): |
|
|
|
|
_template(xml::Node("<xml::start>")<<t), _line(0) {} |
|
|
|
|
const Node& Factory::operator*() const throw() { |
|
|
|
|
return *_template; |
|
|
|
|
return _template[0]; |
|
|
|
|
} |
|
|
|
|
std::auto_ptr<Node> Factory::read(std::istream& is) |
|
|
|
|
throw(wrong_end_tag, wrong_start_tag, tag_expected, type_mismatch, |
|
|
|
|
second_slash_in_tag, |
|
|
|
|
character_after_slash, missing_end_tag, attribute_value_not_quoted, |
|
|
|
|
access_error, duplicate_attribute, |
|
|
|
|
attributes_in_end_tag) try { |
|
|
|
|
attributes_in_end_tag, |
|
|
|
|
illegal_attribute, mandatory_attribute_missing, |
|
|
|
|
wrong_node_number) try { |
|
|
|
|
_line=1; |
|
|
|
|
std::auto_ptr<Node> node(_template->clone()); |
|
|
|
|
node->clear(); |
|
|
|
|
_open=0; |
|
|
|
|
std::auto_ptr<Node> node(read(is, _template)); |
|
|
|
|
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, *node); |
|
|
|
|
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 EMPTY: |
|
|
|
|
return node; // empty
|
|
|
|
|
case START: |
|
|
|
|
if (!res.name.size()) throw tag_expected(*node, res.text); |
|
|
|
|
if (node->name()!=res.name) throw wrong_start_tag(*node, is, res); |
|
|
|
|
return read(is, *_template); |
|
|
|
|
return read(is, _template[res.name]); |
|
|
|
|
//! @todo store instead of ignore
|
|
|
|
|
case SPECIAL: break; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
}*/ |
|
|
|
|
} catch (exception& e) { |
|
|
|
|
e.line(_line); |
|
|
|
|
throw; |
|
|
|
@ -505,37 +529,48 @@ namespace xml { |
|
|
|
|
throw(wrong_end_tag, wrong_start_tag, tag_expected, type_mismatch, |
|
|
|
|
second_slash_in_tag, |
|
|
|
|
character_after_slash, missing_end_tag, attribute_value_not_quoted, |
|
|
|
|
access_error, duplicate_attribute, attributes_in_end_tag) { |
|
|
|
|
access_error, duplicate_attribute, attributes_in_end_tag, |
|
|
|
|
illegal_attribute, mandatory_attribute_missing, |
|
|
|
|
wrong_node_number) { |
|
|
|
|
std::auto_ptr<Node> result(node.clone()); |
|
|
|
|
result->clear(); |
|
|
|
|
for (bool finished(false); is && !finished;) { |
|
|
|
|
while (true) { |
|
|
|
|
Tag res(tag(is, node)); |
|
|
|
|
if (!res.found) return result; |
|
|
|
|
if (res.text.size()) result->text(res.text); |
|
|
|
|
switch (res.type) { |
|
|
|
|
case END: { |
|
|
|
|
--_open; |
|
|
|
|
if (res.attributes.size()) throw attributes_in_end_tag(node, is, res); |
|
|
|
|
if (res.name!=node.name()) throw wrong_end_tag(node, is, res); |
|
|
|
|
finished = true; |
|
|
|
|
} break; |
|
|
|
|
} return result; |
|
|
|
|
case EMPTY: { |
|
|
|
|
*result<<(node[res.name].clone()->clear()<<res.attributes); |
|
|
|
|
} break; |
|
|
|
|
case START: { |
|
|
|
|
++_open; |
|
|
|
|
*result<<(*read(is, node[res.name])<<res.attributes); |
|
|
|
|
} break; |
|
|
|
|
case SPECIAL: break; //! @todo ignored could be stored
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
return result; |
|
|
|
|
} |
|
|
|
|
Tag Factory::tag(std::istream& is, const Node& position) |
|
|
|
|
throw(second_slash_in_tag, character_after_slash, |
|
|
|
|
throw(second_slash_in_tag, character_after_slash, tag_expected, |
|
|
|
|
missing_end_tag, attribute_value_not_quoted, |
|
|
|
|
access_error, duplicate_attribute) { |
|
|
|
|
access_error, duplicate_attribute, attributes_in_end_tag, |
|
|
|
|
illegal_attribute, mandatory_attribute_missing, |
|
|
|
|
wrong_start_tag, wrong_node_number) { |
|
|
|
|
char c(0); |
|
|
|
|
Tag tag((Tag){"", START, "", Attributes()}); |
|
|
|
|
Tag tag((Tag){"", START, "", Attributes(), "", false}); |
|
|
|
|
while (is && is.get(c) && ws(c)); // skip ws
|
|
|
|
|
if (!is) throw missing_end_tag(position, is, tag); |
|
|
|
|
if (is.eof()) { |
|
|
|
|
if (_open>0) |
|
|
|
|
throw missing_end_tag(position, is, tag); |
|
|
|
|
else |
|
|
|
|
return tag; |
|
|
|
|
} |
|
|
|
|
tag.found = true; |
|
|
|
|
if (c!='<') do tag.text+=c; while (is && is.get(c) && c!='<'); |
|
|
|
|
bool nameRead(false); |
|
|
|
|
for (char last(c); is && is.get(c) && c!='>'; last=c) switch (c) { |
|
|
|
@ -559,6 +594,7 @@ namespace xml { |
|
|
|
|
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); |
|
|
|
|
std::string attrname(1, c), attrvalue; |
|
|
|
|
while (is && is.get(c) && c!='=' && c!='>' && !ws(c)) attrname+=c; |
|
|
|
|
while (ws(c) && is && is.get(c)); // skip ws, search '='
|
|
|
|
@ -569,16 +605,40 @@ namespace xml { |
|
|
|
|
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
|
|
|
|
|
} else is.unget(); // read too far
|
|
|
|
|
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); |
|
|
|
|
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); |
|
|
|
|
} |
|
|
|
|
for (Attributes::const_iterator it |
|
|
|
|
(position[tag.name].attributes().begin()); |
|
|
|
|
it!=position[tag.name].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); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
return tag; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|