new tests, cleanup, prepared for node-limits
This commit is contained in:
@@ -9,6 +9,7 @@
|
|||||||
#define LIB_XML_CXX_HXX
|
#define LIB_XML_CXX_HXX
|
||||||
|
|
||||||
#include <istream>
|
#include <istream>
|
||||||
|
#include <sstream>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <map>
|
#include <map>
|
||||||
@@ -244,6 +245,37 @@ namespace xml {
|
|||||||
t, is, tag, 0) {
|
t, is, tag, 0) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
class illegal_attribute: public stream_error {
|
||||||
|
public:
|
||||||
|
illegal_attribute(const Node& t, std::istream& is, const Tag& tag,
|
||||||
|
std::string attr) throw():
|
||||||
|
stream_error("illegal attribute found\nattribute: "+attr,
|
||||||
|
t, is, tag, 0) {
|
||||||
|
}
|
||||||
|
};
|
||||||
|
class mandatory_attribute_missing: public stream_error {
|
||||||
|
public:
|
||||||
|
mandatory_attribute_missing(const Node& t, std::istream& is,
|
||||||
|
const Tag& tag, std::string attr) throw():
|
||||||
|
stream_error("mandatory attribute missing\nattribute: "+attr,
|
||||||
|
t, is, tag, 0) {
|
||||||
|
}
|
||||||
|
};
|
||||||
|
class wrong_node_number: public stream_error {
|
||||||
|
public:
|
||||||
|
wrong_node_number(const Node& t, std::istream& is,
|
||||||
|
const Tag& tag, const std::string& name,
|
||||||
|
unsigned long num,
|
||||||
|
unsigned long min, unsigned long max) throw():
|
||||||
|
stream_error(((std::stringstream&)
|
||||||
|
(std::stringstream()
|
||||||
|
<<"wrong number of child nodes\nname of child: "<<name
|
||||||
|
<<"\nnumber of nodes: "<<num
|
||||||
|
<<"\nminimuml number: "<<min
|
||||||
|
<<"\nmaximum number: "<<max)).str(),
|
||||||
|
t, is, tag, 0) {
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
//============================================================================
|
//============================================================================
|
||||||
|
|
||||||
@@ -298,6 +330,7 @@ namespace xml {
|
|||||||
std::string text;
|
std::string text;
|
||||||
Attributes attributes;
|
Attributes attributes;
|
||||||
std::string special;
|
std::string special;
|
||||||
|
bool found;
|
||||||
};
|
};
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
@@ -311,7 +344,7 @@ namespace xml {
|
|||||||
public:
|
public:
|
||||||
typedef Contents::size_type size_type;
|
typedef Contents::size_type size_type;
|
||||||
typedef std::vector<Node*> List;
|
typedef std::vector<Node*> List;
|
||||||
Node(std::string name) throw();
|
Node(std::string name, size_type min=0, size_type max=0) throw();
|
||||||
Node(const Node& o) throw();
|
Node(const Node& o) throw();
|
||||||
Node& operator=(const Node& o) throw();
|
Node& operator=(const Node& o) throw();
|
||||||
virtual ~Node() throw();
|
virtual ~Node() throw();
|
||||||
@@ -329,10 +362,14 @@ namespace xml {
|
|||||||
Node& parent() const throw(no_parent);
|
Node& parent() const throw(no_parent);
|
||||||
bool hasAttr(const std::string& name) const throw();
|
bool hasAttr(const std::string& name) const throw();
|
||||||
Node& attr(const std::string& name, bool mandatory) throw();
|
Node& attr(const std::string& name, bool mandatory) throw();
|
||||||
|
Node& attr(const std::string& name, const std::string& deflt) throw();
|
||||||
std::string attr(const std::string& name) const throw();
|
std::string attr(const std::string& name) const throw();
|
||||||
std::string& attr(const std::string& name) throw();
|
std::string& attr(const std::string& name) throw();
|
||||||
const Attributes::Value attribute(const std::string& name)
|
const Attributes::Value attribute(const std::string& name)
|
||||||
const throw(attribute_not_available);
|
const throw(attribute_not_available);
|
||||||
|
const Attributes& attributes() const throw();
|
||||||
|
Attributes& attributes() throw();
|
||||||
|
Node& limits(size_type min=0, size_type max=0) throw();
|
||||||
List list(const std::string& name) const throw();
|
List list(const std::string& name) const throw();
|
||||||
bool operator()(const std::string& child) const throw();
|
bool operator()(const std::string& child) const throw();
|
||||||
Node& operator<<(const Node& o) throw(cannot_have_children);
|
Node& operator<<(const Node& o) throw(cannot_have_children);
|
||||||
@@ -340,9 +377,9 @@ namespace xml {
|
|||||||
//! Get the number of children.
|
//! Get the number of children.
|
||||||
size_type children() const throw();
|
size_type children() const throw();
|
||||||
//! Get the n-th child.
|
//! Get the n-th child.
|
||||||
const Node& operator[](size_type child) const throw(access_error);
|
const Node& operator[](size_type child) const throw(out_of_range);
|
||||||
//! Get the n-th child.
|
//! Get the n-th child.
|
||||||
Node& operator[](size_type child) throw(access_error);
|
Node& operator[](size_type child) throw(out_of_range);
|
||||||
//! Get the first named child.
|
//! Get the first named child.
|
||||||
const Node& operator[](const std::string& child) const
|
const Node& operator[](const std::string& child) const
|
||||||
throw(access_error);
|
throw(access_error);
|
||||||
@@ -361,6 +398,8 @@ namespace xml {
|
|||||||
Contents _contents;
|
Contents _contents;
|
||||||
std::string _name;
|
std::string _name;
|
||||||
Node* _parent;
|
Node* _parent;
|
||||||
|
typedef std::pair<Node::size_type, Node::size_type> Limits;
|
||||||
|
Limits _limits;
|
||||||
};
|
};
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
@@ -401,7 +440,9 @@ namespace xml {
|
|||||||
throw(wrong_end_tag, wrong_start_tag, tag_expected, type_mismatch,
|
throw(wrong_end_tag, wrong_start_tag, tag_expected, type_mismatch,
|
||||||
second_slash_in_tag, character_after_slash,
|
second_slash_in_tag, character_after_slash,
|
||||||
missing_end_tag, attribute_value_not_quoted, access_error,
|
missing_end_tag, attribute_value_not_quoted, access_error,
|
||||||
duplicate_attribute, attributes_in_end_tag);
|
duplicate_attribute, attributes_in_end_tag,
|
||||||
|
illegal_attribute, mandatory_attribute_missing,
|
||||||
|
wrong_node_number);
|
||||||
private:
|
private:
|
||||||
friend class stream_error;
|
friend class stream_error;
|
||||||
Factory(); // not implemented
|
Factory(); // not implemented
|
||||||
@@ -412,13 +453,18 @@ namespace xml {
|
|||||||
second_slash_in_tag, character_after_slash,
|
second_slash_in_tag, character_after_slash,
|
||||||
missing_end_tag,
|
missing_end_tag,
|
||||||
attribute_value_not_quoted, access_error, duplicate_attribute,
|
attribute_value_not_quoted, access_error, duplicate_attribute,
|
||||||
attributes_in_end_tag);
|
attributes_in_end_tag,
|
||||||
|
illegal_attribute, mandatory_attribute_missing,
|
||||||
|
wrong_node_number);
|
||||||
Tag tag(std::istream& is, const Node& position)
|
Tag tag(std::istream& is, const Node& position)
|
||||||
throw(second_slash_in_tag, character_after_slash,
|
throw(second_slash_in_tag, wrong_start_tag, character_after_slash,
|
||||||
missing_end_tag,
|
missing_end_tag, attributes_in_end_tag, tag_expected,
|
||||||
attribute_value_not_quoted, access_error, duplicate_attribute);
|
attribute_value_not_quoted, access_error, duplicate_attribute,
|
||||||
std::auto_ptr<Node> _template;
|
illegal_attribute, mandatory_attribute_missing,
|
||||||
|
wrong_node_number);
|
||||||
|
Node _template;
|
||||||
unsigned long _line;
|
unsigned long _line;
|
||||||
|
long _open;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
120
src/xml.cxx
120
src/xml.cxx
@@ -33,7 +33,7 @@ class MethodTrace {
|
|||||||
};
|
};
|
||||||
unsigned int MethodTrace::_level(0);
|
unsigned int MethodTrace::_level(0);
|
||||||
#define TRACE MethodTrace XXX_METHOD(this, __PRETTY_FUNCTION__)
|
#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 {
|
namespace xml {
|
||||||
|
|
||||||
@@ -219,11 +219,12 @@ namespace xml {
|
|||||||
//! Nodes must be given a name.
|
//! Nodes must be given a name.
|
||||||
/*! Unnamed nodes are not allowed, therefore there's no default
|
/*! Unnamed nodes are not allowed, therefore there's no default
|
||||||
constructor. */
|
constructor. */
|
||||||
Node::Node(std::string name) throw():
|
Node::Node(std::string name, size_type min, size_type max) throw():
|
||||||
_name(name), _parent(0) {
|
_name(name), _parent(0), _limits(min, max) {
|
||||||
}
|
}
|
||||||
Node::Node(const Node& o) throw():
|
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());
|
for (Contents::const_iterator it(o._contents.begin());
|
||||||
it!=o._contents.end(); ++it)
|
it!=o._contents.end(); ++it)
|
||||||
_contents.push_back((*it)->clone(this).release());
|
_contents.push_back((*it)->clone(this).release());
|
||||||
@@ -232,6 +233,7 @@ namespace xml {
|
|||||||
_attributes=o._attributes;
|
_attributes=o._attributes;
|
||||||
_name = o.name();
|
_name = o.name();
|
||||||
_parent = 0;
|
_parent = 0;
|
||||||
|
_limits = o._limits;
|
||||||
for (Contents::const_iterator it(o._contents.begin());
|
for (Contents::const_iterator it(o._contents.begin());
|
||||||
it!=o._contents.end(); ++it)
|
it!=o._contents.end(); ++it)
|
||||||
_contents.push_back((*it)->clone(this).release());
|
_contents.push_back((*it)->clone(this).release());
|
||||||
@@ -305,7 +307,12 @@ namespace xml {
|
|||||||
return _attributes.find(name)!=_attributes.end();
|
return _attributes.find(name)!=_attributes.end();
|
||||||
}
|
}
|
||||||
Node& Node::attr(const std::string& name, bool mandatory) throw() {
|
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;
|
return *this;
|
||||||
}
|
}
|
||||||
std::string Node::attr(const std::string& name) const throw() {
|
std::string Node::attr(const std::string& name) const throw() {
|
||||||
@@ -322,6 +329,17 @@ namespace xml {
|
|||||||
if (it!=_attributes.end()) return *it;
|
if (it!=_attributes.end()) return *it;
|
||||||
throw attribute_not_available(*this, name);
|
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() {
|
Node::List Node::list(const std::string& name) const throw() {
|
||||||
List res;
|
List res;
|
||||||
for (Contents::const_iterator it(_contents.begin());
|
for (Contents::const_iterator it(_contents.begin());
|
||||||
@@ -342,12 +360,12 @@ namespace xml {
|
|||||||
return _contents.size();
|
return _contents.size();
|
||||||
}
|
}
|
||||||
const Node& Node::operator[](Node::size_type child) const
|
const Node& Node::operator[](Node::size_type child) const
|
||||||
throw(access_error) try {
|
throw(out_of_range) try {
|
||||||
return *_contents.at(child);
|
return *_contents.at(child);
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
throw out_of_range(*this, child);
|
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);
|
return *_contents.at(child);
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
throw out_of_range(*this, child);
|
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() {
|
const Node& Factory::operator*() const throw() {
|
||||||
return *_template;
|
return _template[0];
|
||||||
}
|
}
|
||||||
std::auto_ptr<Node> Factory::read(std::istream& is)
|
std::auto_ptr<Node> Factory::read(std::istream& is)
|
||||||
throw(wrong_end_tag, wrong_start_tag, tag_expected, type_mismatch,
|
throw(wrong_end_tag, wrong_start_tag, tag_expected, type_mismatch,
|
||||||
second_slash_in_tag,
|
second_slash_in_tag,
|
||||||
character_after_slash, missing_end_tag, attribute_value_not_quoted,
|
character_after_slash, missing_end_tag, attribute_value_not_quoted,
|
||||||
access_error, duplicate_attribute,
|
access_error, duplicate_attribute,
|
||||||
attributes_in_end_tag) try {
|
attributes_in_end_tag,
|
||||||
|
illegal_attribute, mandatory_attribute_missing,
|
||||||
|
wrong_node_number) try {
|
||||||
_line=1;
|
_line=1;
|
||||||
std::auto_ptr<Node> node(_template->clone());
|
_open=0;
|
||||||
node->clear();
|
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;
|
Tag res;
|
||||||
while (true) {
|
while (true) {
|
||||||
res = tag(is, *node);
|
res = tag(is, _template);
|
||||||
*node<<res.attributes;
|
*node<<res.attributes;
|
||||||
switch (res.type) {
|
switch (res.type) {
|
||||||
case END: throw wrong_end_tag(*node, is, res);
|
case END: throw wrong_end_tag(*node, is, res);
|
||||||
case EMPTY: return node; // empty
|
case EMPTY:
|
||||||
|
return node; // empty
|
||||||
case START:
|
case START:
|
||||||
if (!res.name.size()) throw tag_expected(*node, res.text);
|
return read(is, _template[res.name]);
|
||||||
if (node->name()!=res.name) throw wrong_start_tag(*node, is, res);
|
|
||||||
return read(is, *_template);
|
|
||||||
//! @todo store instead of ignore
|
//! @todo store instead of ignore
|
||||||
case SPECIAL: break;
|
case SPECIAL: break;
|
||||||
}
|
}
|
||||||
}
|
}*/
|
||||||
} catch (exception& e) {
|
} catch (exception& e) {
|
||||||
e.line(_line);
|
e.line(_line);
|
||||||
throw;
|
throw;
|
||||||
@@ -505,37 +529,48 @@ namespace xml {
|
|||||||
throw(wrong_end_tag, wrong_start_tag, tag_expected, type_mismatch,
|
throw(wrong_end_tag, wrong_start_tag, tag_expected, type_mismatch,
|
||||||
second_slash_in_tag,
|
second_slash_in_tag,
|
||||||
character_after_slash, missing_end_tag, attribute_value_not_quoted,
|
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());
|
std::auto_ptr<Node> result(node.clone());
|
||||||
result->clear();
|
result->clear();
|
||||||
for (bool finished(false); is && !finished;) {
|
while (true) {
|
||||||
Tag res(tag(is, node));
|
Tag res(tag(is, node));
|
||||||
|
if (!res.found) return result;
|
||||||
if (res.text.size()) result->text(res.text);
|
if (res.text.size()) result->text(res.text);
|
||||||
switch (res.type) {
|
switch (res.type) {
|
||||||
case END: {
|
case END: {
|
||||||
|
--_open;
|
||||||
if (res.attributes.size()) throw attributes_in_end_tag(node, is, res);
|
if (res.attributes.size()) throw attributes_in_end_tag(node, is, res);
|
||||||
if (res.name!=node.name()) throw wrong_end_tag(node, is, res);
|
if (res.name!=node.name()) throw wrong_end_tag(node, is, res);
|
||||||
finished = true;
|
} return result;
|
||||||
} break;
|
|
||||||
case EMPTY: {
|
case EMPTY: {
|
||||||
*result<<(node[res.name].clone()->clear()<<res.attributes);
|
*result<<(node[res.name].clone()->clear()<<res.attributes);
|
||||||
} break;
|
} break;
|
||||||
case START: {
|
case START: {
|
||||||
|
++_open;
|
||||||
*result<<(*read(is, node[res.name])<<res.attributes);
|
*result<<(*read(is, node[res.name])<<res.attributes);
|
||||||
} break;
|
} break;
|
||||||
case SPECIAL: break; //! @todo ignored could be stored
|
case SPECIAL: break; //! @todo ignored could be stored
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
Tag Factory::tag(std::istream& is, const Node& position)
|
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,
|
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);
|
char c(0);
|
||||||
Tag tag((Tag){"", START, "", Attributes()});
|
Tag tag((Tag){"", START, "", Attributes(), "", false});
|
||||||
while (is && is.get(c) && ws(c)); // skip ws
|
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!='<');
|
if (c!='<') do tag.text+=c; while (is && is.get(c) && c!='<');
|
||||||
bool nameRead(false);
|
bool nameRead(false);
|
||||||
for (char last(c); is && is.get(c) && c!='>'; last=c) switch (c) {
|
for (char last(c); is && is.get(c) && c!='>'; last=c) switch (c) {
|
||||||
@@ -559,6 +594,7 @@ namespace xml {
|
|||||||
default:
|
default:
|
||||||
if (tag.type==EMPTY) throw character_after_slash(position, is, tag, c);
|
if (tag.type==EMPTY) throw character_after_slash(position, is, tag, c);
|
||||||
if (nameRead) { // read attribute
|
if (nameRead) { // read attribute
|
||||||
|
if (tag.type!=START) throw attributes_in_end_tag(position, is, tag);
|
||||||
std::string attrname(1, c), attrvalue;
|
std::string attrname(1, c), attrvalue;
|
||||||
while (is && is.get(c) && c!='=' && c!='>' && !ws(c)) attrname+=c;
|
while (is && is.get(c) && c!='=' && c!='>' && !ws(c)) attrname+=c;
|
||||||
while (ws(c) && is && is.get(c)); // skip ws, search '='
|
while (ws(c) && is && is.get(c)); // skip ws, search '='
|
||||||
@@ -569,16 +605,40 @@ namespace xml {
|
|||||||
while (is && is.get(c) && c!='"') attrvalue+=c;
|
while (is && is.get(c) && c!='"') attrvalue+=c;
|
||||||
if (c!='"')
|
if (c!='"')
|
||||||
throw attribute_value_not_quoted(position, is, tag, c, attrname);
|
throw attribute_value_not_quoted(position, is, tag, c, attrname);
|
||||||
} else {
|
} else is.unget(); // read too far
|
||||||
is.unget();
|
|
||||||
}// read too far
|
|
||||||
if (tag.attributes.find(attrname)!=tag.attributes.end())
|
if (tag.attributes.find(attrname)!=tag.attributes.end())
|
||||||
throw duplicate_attribute(position, is, tag, attrname);
|
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;
|
tag.attributes[attrname] = attrvalue;
|
||||||
} else { // part of a tag name
|
} else { // part of a tag name
|
||||||
tag.name+=c;
|
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;
|
return tag;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -199,13 +199,16 @@ class ComplexTest: public CppUnit::TestFixture {
|
|||||||
<<"<child/>"
|
<<"<child/>"
|
||||||
<<"< otherchild >< / otherchild >< otherchild / >"<<std::endl
|
<<"< otherchild >< / otherchild >< otherchild / >"<<std::endl
|
||||||
<<"</base>";
|
<<"</base>";
|
||||||
CPPUNIT_ASSERT_THROW(factory.read(file2), xml::access_error);
|
CPPUNIT_ASSERT_THROW(factory.read(file2), xml::wrong_start_tag);
|
||||||
{
|
{
|
||||||
std::stringstream file("<base></xyz>");
|
std::stringstream file("<base></xyz>");
|
||||||
CPPUNIT_ASSERT_THROW(factory.read(file), xml::wrong_end_tag);
|
CPPUNIT_ASSERT_THROW(factory.read(file), xml::wrong_end_tag);
|
||||||
} {
|
} {
|
||||||
std::stringstream file("<xyz></xyz>");
|
std::stringstream file("<xyz></xyz>");
|
||||||
CPPUNIT_ASSERT_THROW(factory.read(file), xml::wrong_start_tag);
|
CPPUNIT_ASSERT_THROW(factory.read(file), xml::wrong_start_tag);
|
||||||
|
} {
|
||||||
|
std::stringstream file("<xyz/>");
|
||||||
|
CPPUNIT_ASSERT_THROW(factory.read(file), xml::wrong_start_tag);
|
||||||
} {
|
} {
|
||||||
std::stringstream file("base");
|
std::stringstream file("base");
|
||||||
CPPUNIT_ASSERT_THROW(factory.read(file), xml::tag_expected);
|
CPPUNIT_ASSERT_THROW(factory.read(file), xml::tag_expected);
|
||||||
@@ -234,7 +237,7 @@ class ComplexTest: public CppUnit::TestFixture {
|
|||||||
CPPUNIT_ASSERT_THROW(factory.read(file), xml::missing_end_tag);
|
CPPUNIT_ASSERT_THROW(factory.read(file), xml::missing_end_tag);
|
||||||
} {
|
} {
|
||||||
std::stringstream file;
|
std::stringstream file;
|
||||||
CPPUNIT_ASSERT_THROW(factory.read(file), xml::missing_end_tag);
|
CPPUNIT_ASSERT_THROW(factory.read(file), xml::tag_expected);
|
||||||
} {
|
} {
|
||||||
std::stringstream file("<base><child a=b></base>");
|
std::stringstream file("<base><child a=b></base>");
|
||||||
CPPUNIT_ASSERT_THROW(factory.read(file),
|
CPPUNIT_ASSERT_THROW(factory.read(file),
|
||||||
@@ -249,14 +252,50 @@ class ComplexTest: public CppUnit::TestFixture {
|
|||||||
}
|
}
|
||||||
void attributes() {
|
void attributes() {
|
||||||
xml::Factory factory(xml::Node("base")
|
xml::Factory factory(xml::Node("base")
|
||||||
|
.attr("one", xml::mandatory)
|
||||||
|
.attr("two", xml::optional)
|
||||||
<<(xml::Node("child")
|
<<(xml::Node("child")
|
||||||
<<xml::String("childofchild")
|
<<xml::String("childofchild")
|
||||||
<<xml::UnsignedInteger("number"))
|
<<xml::UnsignedInteger("number"))
|
||||||
<<xml::Node("otherchild"));
|
<<xml::Node("otherchild"));
|
||||||
|
{
|
||||||
|
std::stringstream file("<base></base>");
|
||||||
|
CPPUNIT_ASSERT_THROW(factory.read(file),
|
||||||
|
xml::mandatory_attribute_missing);
|
||||||
|
} {
|
||||||
|
std::stringstream file("<base one two three></base>");
|
||||||
|
CPPUNIT_ASSERT_THROW(factory.read(file), xml::illegal_attribute);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void ranges() {
|
||||||
|
xml::Factory factory(xml::Node("base", 2, 2)
|
||||||
|
<<xml::Node("mandatory", 1)
|
||||||
|
<<xml::Node("optional", 0, 1));
|
||||||
|
{
|
||||||
|
std::stringstream file("<base><mandatory></mandatory></base>"
|
||||||
|
"<base><mandatory/><optional/></base>");
|
||||||
|
CPPUNIT_ASSERT_NO_THROW(factory.read(file));
|
||||||
|
} /*{
|
||||||
|
std::stringstream file("<base><mandatory></mandatory></base>"
|
||||||
|
"<base><mandatory/><optional/></base>");
|
||||||
|
CPPUNIT_ASSERT_THROW(factory.read(file),
|
||||||
|
xml::wrong_node_number);
|
||||||
|
} {
|
||||||
|
std::stringstream file("<base><mandatory></mandatory></base>"
|
||||||
|
"<base><mandatory/><optional/></base>");
|
||||||
|
CPPUNIT_ASSERT_THROW(factory.read(file),
|
||||||
|
xml::wrong_node_number);
|
||||||
|
} {
|
||||||
|
std::stringstream file("<base><mandatory></mandatory></base>"
|
||||||
|
"<base><mandatory/><optional/></base>");
|
||||||
|
CPPUNIT_ASSERT_THROW(factory.read(file),
|
||||||
|
xml::wrong_node_number);
|
||||||
|
}*/
|
||||||
}
|
}
|
||||||
CPPUNIT_TEST_SUITE(ComplexTest);
|
CPPUNIT_TEST_SUITE(ComplexTest);
|
||||||
CPPUNIT_TEST(nodes);
|
CPPUNIT_TEST(nodes);
|
||||||
CPPUNIT_TEST(attributes);
|
CPPUNIT_TEST(attributes);
|
||||||
|
CPPUNIT_TEST(ranges);
|
||||||
CPPUNIT_TEST_SUITE_END();
|
CPPUNIT_TEST_SUITE_END();
|
||||||
};
|
};
|
||||||
CPPUNIT_TEST_SUITE_REGISTRATION(ComplexTest);
|
CPPUNIT_TEST_SUITE_REGISTRATION(ComplexTest);
|
||||||
@@ -293,7 +332,7 @@ class FunTest: public CppUnit::TestFixture {
|
|||||||
<<(xml::Node("head")
|
<<(xml::Node("head")
|
||||||
<<xml::String("title"))
|
<<xml::String("title"))
|
||||||
<<(xml::Node("body")
|
<<(xml::Node("body")
|
||||||
<<xml::String("h1")
|
<<xml::String("h1").attr("class", xml::optional)
|
||||||
<<xml::String("h2")
|
<<xml::String("h2")
|
||||||
<<xml::String("p")));
|
<<xml::String("p")));
|
||||||
std::auto_ptr<xml::Node> read(factory.read(ss)); // read back the example
|
std::auto_ptr<xml::Node> read(factory.read(ss)); // read back the example
|
||||||
|
Reference in New Issue
Block a user