import
This commit is contained in:
16
src/makefile.am
Normal file
16
src/makefile.am
Normal file
@@ -0,0 +1,16 @@
|
||||
## @file
|
||||
##
|
||||
## $Id$
|
||||
##
|
||||
## 1 2 3 4 5 6 7 8
|
||||
## 45678901234567890123456789012345678901234567890123456789012345678901234567890
|
||||
|
||||
if BUILD_WIN
|
||||
else
|
||||
endif
|
||||
|
||||
clean-local:
|
||||
-rm -r ${QMAKE_TARGET}.app
|
||||
|
||||
CLEANFILES =
|
||||
MAINTAINERCLEANFILES = makefile.in
|
438
src/xml.cxx
Normal file
438
src/xml.cxx
Normal file
@@ -0,0 +1,438 @@
|
||||
/*! @file
|
||||
|
||||
@id $Id$
|
||||
*/
|
||||
// 1 2 3 4 5 6 7 8
|
||||
// 45678901234567890123456789012345678901234567890123456789012345678901234567890
|
||||
|
||||
#include <xml.hxx>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <cstdlib>
|
||||
|
||||
#include <iomanip>
|
||||
class MethodTrace {
|
||||
public:
|
||||
MethodTrace(const void* addr, const std::string& name) throw():
|
||||
_addr(addr), _name(name) {
|
||||
std::clog<<std::hex<<std::setw(15)<<_addr<<": "
|
||||
<<std::dec<<std::setw(2+_level)
|
||||
<<std::setfill(' ')<<"\\ "<<_name<<std::endl;
|
||||
++_level;
|
||||
}
|
||||
~MethodTrace() throw() {
|
||||
--_level;
|
||||
std::clog<<std::hex<<std::setw(15)<<_addr<<": "<<std::dec
|
||||
<<std::setw(2+_level)<<std::setfill(' ')
|
||||
<<"/ "<<_name<<std::endl;
|
||||
}
|
||||
private:
|
||||
const void* _addr;
|
||||
const std::string _name;
|
||||
static unsigned int _level;
|
||||
};
|
||||
unsigned int MethodTrace::_level(0);
|
||||
#define TRACE MethodTrace XXX_METHOD(this, __PRETTY_FUNCTION__)
|
||||
#define LOG(X) std::clog<<__PRETTY_FUNCTION__<<"\t**** "<<X<<std::endl
|
||||
|
||||
namespace xml {
|
||||
|
||||
//============================================================================
|
||||
Attributes::Value::Value(const std::string& name) throw():
|
||||
Attributes::value_type(name, std::string()) {
|
||||
}
|
||||
Attributes::value_type& Attributes::Value::operator=(const std::string& value)
|
||||
throw() {
|
||||
second = value;
|
||||
return *this;
|
||||
}
|
||||
Attributes::Attributes() throw(): _active(end()) {}
|
||||
Attributes::Attributes(const std::string& empty) throw() {
|
||||
_active = insert(Value(empty)).first;
|
||||
}
|
||||
Attributes& Attributes::operator<<(const value_type& v) throw() {
|
||||
_active = insert(v).first;
|
||||
return *this;
|
||||
}
|
||||
Attributes& Attributes::operator<<(const std::string& key) throw() {
|
||||
_active = insert(Value(key)).first;
|
||||
return *this;
|
||||
}
|
||||
Attributes& Attributes::operator=(const std::string& value) throw() {
|
||||
if (_active==end()) return *this;
|
||||
_active->second = value;
|
||||
_active = end();
|
||||
return *this;
|
||||
}
|
||||
|
||||
//================================================================= EXCEPTIONS
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
exception::exception(std::string reason, const Node& t) throw():
|
||||
_what(reason), _node(t.clone().release()) {
|
||||
}
|
||||
exception::~exception() throw() {
|
||||
delete _node;
|
||||
}
|
||||
const char* exception::what() const throw() {
|
||||
static std::string w;
|
||||
if (!w.size()) {
|
||||
if (_node)
|
||||
if (_node->isChild())
|
||||
w = _what+"\ntag: "+_node->name()+"\nparent: "+_node->parent().name();
|
||||
else
|
||||
w = _what+"\ntag: "+_node->name()+" (root element)";
|
||||
else
|
||||
w = _what;
|
||||
}
|
||||
return w.c_str();
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
access_error::access_error(const Node& t, const std::string& name) throw():
|
||||
exception("child not available", t), _name(name) {
|
||||
}
|
||||
const char* access_error::what() const throw() {
|
||||
static std::string w;
|
||||
if (!w.size()) w = std::string(exception::what())+"\nchild name: "+_name;
|
||||
return w.c_str();
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
out_of_range::out_of_range(const Node& t, size_t pos) throw():
|
||||
exception("child not available", t), _pos(pos) {
|
||||
}
|
||||
const char* out_of_range::what() const throw() {
|
||||
static std::stringstream w;
|
||||
if (!w.str().size()) w<<exception::what()<<"\nchild number: "<<_pos;
|
||||
return w.str().c_str();
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
cannot_have_children::cannot_have_children(const Node& parent,
|
||||
const Node& child) throw():
|
||||
exception("node does not accept child nodes", parent),
|
||||
_child(child.clone().release()) {
|
||||
}
|
||||
cannot_have_children::~cannot_have_children() throw() {
|
||||
delete _child;
|
||||
}
|
||||
const char* cannot_have_children::what() const throw() {
|
||||
static std::string w;
|
||||
if (!w.size())
|
||||
w = std::string(exception::what())+"\nchild name: "+_child->name();
|
||||
return w.c_str();
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
stream_error::stream_error(const std::string& reason, const Node& t,
|
||||
std::istream& is, Tag tag, char c) throw():
|
||||
exception(reason, t), _pos(is.tellg()), _tag(tag), _char(c) {
|
||||
}
|
||||
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<<")";
|
||||
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();
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
Node::Node(std::string name) throw():
|
||||
_name(name), _parent(0) {
|
||||
}
|
||||
Node::Node(const Node& o) throw():
|
||||
_attributes(o._attributes), _name(o.name()), _parent(0) {
|
||||
for (Contents::const_iterator it(o._contents.begin());
|
||||
it!=o._contents.end(); ++it)
|
||||
_contents.push_back((*it)->clone(this).release());
|
||||
}
|
||||
Node& Node::operator=(const Node& o) throw() {
|
||||
_attributes=o._attributes;
|
||||
_name = o.name();
|
||||
_parent = 0;
|
||||
for (Contents::const_iterator it(o._contents.begin());
|
||||
it!=o._contents.end(); ++it)
|
||||
_contents.push_back((*it)->clone(this).release());
|
||||
}
|
||||
Node::~Node() throw() {
|
||||
clear();
|
||||
}
|
||||
std::auto_ptr<Node> Node::clone() const throw() {
|
||||
std::auto_ptr<Node> res(new Node(*this));
|
||||
res->_parent = 0;
|
||||
return res;
|
||||
}
|
||||
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;
|
||||
}
|
||||
std::string Node::text() const throw() {
|
||||
std::string s;
|
||||
for (Contents::const_iterator it(_contents.begin());
|
||||
it!=_contents.end(); ++it)
|
||||
s+=***it;
|
||||
return s;
|
||||
}
|
||||
Node& Node::text(const std::string& txt) throw(tag_expected) {
|
||||
throw tag_expected(*this, txt);
|
||||
}
|
||||
Node& Node::append(const Node& o) throw(cannot_have_children) {
|
||||
_contents.push_back(o.clone(this).release());
|
||||
return *this;
|
||||
}
|
||||
Node& Node::set(const Attributes& o) throw() {
|
||||
_attributes.insert(o.begin(), o.end());
|
||||
return *this;
|
||||
}
|
||||
Node& Node::clear() throw () {
|
||||
for (Contents::const_iterator it(_contents.begin());
|
||||
it!=_contents.end(); ++it)
|
||||
delete *it;
|
||||
_contents.clear();
|
||||
_attributes.clear();
|
||||
return *this;
|
||||
}
|
||||
std::string Node::name() const throw() {
|
||||
return _name;
|
||||
}
|
||||
bool Node::isChild() const throw() {
|
||||
return _parent;
|
||||
}
|
||||
Node& Node::parent() const throw(no_parent) {
|
||||
if (!_parent) throw no_parent(*this);
|
||||
return *_parent;
|
||||
}
|
||||
bool Node::hasAttr(const std::string& name) const throw() {
|
||||
return _attributes.find(name)!=_attributes.end();
|
||||
}
|
||||
Node& Node::attr(const std::string& name, bool mandatory) throw() {
|
||||
_attributes[name] = mandatory?"mandatory":"optional";
|
||||
return *this;
|
||||
}
|
||||
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();
|
||||
}
|
||||
std::string& Node::attr(const std::string&name) throw() {
|
||||
return _attributes[name];
|
||||
}
|
||||
bool Node::operator()(const std::string& child) const throw() {
|
||||
return find(child);
|
||||
}
|
||||
Node& Node::operator<<(const Node& o) throw(cannot_have_children) {
|
||||
return append(o);
|
||||
}
|
||||
Node& Node::operator<<(const Attributes& o) throw() {
|
||||
return set(o);
|
||||
}
|
||||
Node::size_type Node::children() const throw() {
|
||||
return _contents.size();
|
||||
}
|
||||
const Node& Node::operator[](Node::size_type child) const
|
||||
throw(access_error) try {
|
||||
return *_contents.at(child);
|
||||
} catch (...) {
|
||||
throw out_of_range(*this, child);
|
||||
}
|
||||
Node& Node::operator[](Node::size_type child) throw(access_error) try {
|
||||
return *_contents.at(child);
|
||||
} catch (...) {
|
||||
throw out_of_range(*this, child);
|
||||
}
|
||||
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;
|
||||
}
|
||||
Node& Node::operator[](const std::string& child) throw(access_error) {
|
||||
Node* const t(find(child));
|
||||
if (!t) throw access_error(*this, child);
|
||||
return *t;
|
||||
}
|
||||
std::string Node::operator*() const throw() {
|
||||
return text();
|
||||
}
|
||||
Node& Node::operator=(const std::string& contents) throw(tag_expected) {
|
||||
return text(contents);
|
||||
}
|
||||
std::ostream& operator<<(std::ostream& o, const Node& t) throw() {
|
||||
return t.out(o);
|
||||
}
|
||||
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;
|
||||
}
|
||||
std::auto_ptr<Node> Node::clone(Node* p) const throw() {
|
||||
std::auto_ptr<Node> c(clone());
|
||||
c->_parent = p;
|
||||
return c;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
String::String(std::string name, const std::string& text) throw():
|
||||
Node(name), _text(text) {
|
||||
}
|
||||
std::auto_ptr<Node> String::clone() const throw() {
|
||||
return std::auto_ptr<Node>(new String(*this));
|
||||
}
|
||||
std::string String::text() const throw() {
|
||||
return _text;
|
||||
}
|
||||
String& String::text(const std::string& txt) throw(tag_expected) {
|
||||
_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;
|
||||
}
|
||||
String& String::append(const Node& o) throw(cannot_have_children) {
|
||||
throw cannot_have_children(*this, o);
|
||||
}
|
||||
Node& String::operator=(const std::string& contents) throw() {
|
||||
return text(contents);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
Factory::Factory(const Node& t) throw(): _template(t.clone()) {}
|
||||
const Node& Factory::operator*() const throw() {
|
||||
return *_template;
|
||||
}
|
||||
std::auto_ptr<Node> Factory::read(std::istream& is)
|
||||
throw(wrong_end_tag, wrong_start_tag, tag_expected, second_slash_in_tag,
|
||||
character_after_slash, missing_end_tag, attribute_value_not_quoted,
|
||||
access_error, empty_stream, duplicate_attribute,
|
||||
attributes_in_end_tag) {
|
||||
std::auto_ptr<Node> node(_template->clone());
|
||||
node->clear();
|
||||
Tag res;
|
||||
try {
|
||||
res = tag(is, *node);
|
||||
} catch (missing_end_tag&) {
|
||||
throw empty_stream(*node, is, res);
|
||||
}
|
||||
*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);
|
||||
}
|
||||
abort(); // coding error: should not reach here
|
||||
}
|
||||
bool Factory::ws(char c) const throw() {
|
||||
return c==' '||c=='\t'||c=='\n'||c=='\r';
|
||||
}
|
||||
std::auto_ptr<Node> Factory::read(std::istream& is, const Node& node)
|
||||
throw(wrong_end_tag, wrong_start_tag, tag_expected, second_slash_in_tag,
|
||||
character_after_slash, missing_end_tag, attribute_value_not_quoted,
|
||||
access_error, duplicate_attribute, attributes_in_end_tag) {
|
||||
std::auto_ptr<Node> result(node.clone());
|
||||
result->clear();
|
||||
for (bool finished(false); is && !finished;) {
|
||||
Tag res(tag(is, node));
|
||||
if (res.text.size()) result->text(res.text);
|
||||
switch (res.type) {
|
||||
case END: {
|
||||
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;
|
||||
case EMPTY: {
|
||||
*result<<(node[res.name].clone()->clear()<<res.attributes);
|
||||
} break;
|
||||
case START: {
|
||||
*result<<(*read(is, node[res.name])<<res.attributes);
|
||||
} break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
Tag Factory::tag(std::istream& is, const Node& position)
|
||||
throw(second_slash_in_tag, character_after_slash,
|
||||
missing_end_tag, attribute_value_not_quoted,
|
||||
access_error, duplicate_attribute) {
|
||||
char c(0);
|
||||
Tag tag((Tag){"", START, "", Attributes()});
|
||||
while (is && is.get(c) && ws(c)); // skip ws
|
||||
if (!is) throw missing_end_tag(position, is, tag);
|
||||
if (c!='<') do tag.text+=c; while (is && is.get(c) && c!='<');
|
||||
bool nameRead(false);
|
||||
while (is && is.get(c) && c!='>') {
|
||||
switch (c) {
|
||||
case ' ': case '\t': case '\n': case '\r':
|
||||
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;
|
||||
default:
|
||||
if (tag.type==EMPTY) throw character_after_slash(position, is, tag, c);
|
||||
if (nameRead) { // read attribute
|
||||
std::string attrname(1, c), attrvalue;
|
||||
while (is && is.get(c) && c!='=' && !ws(c)) attrname+=c;
|
||||
while (c!='=' && is && is.get(c) && ws(c)); // skip ws, search '='
|
||||
if (c=='=') { // get the value
|
||||
while (is && is.get(c) && ws(c)); // skip ws
|
||||
if (c!='"')
|
||||
throw attribute_value_not_quoted(position, is, tag, c, attrname);
|
||||
while (is && is.get(c) && c!='"') attrvalue+=c;
|
||||
if (c!='"')
|
||||
throw attribute_value_not_quoted(position, is, tag, c, attrname);
|
||||
} else is.unget(); // read too far
|
||||
if (tag.attributes.find(attrname)!=tag.attributes.end())
|
||||
throw duplicate_attribute(position, is, tag, attrname);
|
||||
tag.attributes[attrname] = attrvalue;
|
||||
} else { // part of a tag name
|
||||
tag.name+=c;
|
||||
}
|
||||
}}
|
||||
return tag;
|
||||
}
|
||||
|
||||
}
|
294
src/xml.hxx
Normal file
294
src/xml.hxx
Normal file
@@ -0,0 +1,294 @@
|
||||
/*! @file
|
||||
|
||||
@id $Id$
|
||||
*/
|
||||
// 1 2 3 4 5 6 7 8
|
||||
// 45678901234567890123456789012345678901234567890123456789012345678901234567890
|
||||
|
||||
#ifndef XML_HXX
|
||||
#define XML_HXX
|
||||
|
||||
#include <istream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
|
||||
/*! @page limitations Known Limitations
|
||||
|
||||
- Templates cannot specify number of sub-elements.
|
||||
- XML-Comments are not supported.
|
||||
- Mixed tags and text is not supported. Tags may either contain
|
||||
other tags only (type xml::Node) or text only (type
|
||||
xml::String).
|
||||
- Unlimited recursion is not possible
|
||||
(e.g. <p><p><p></p></p></p>)
|
||||
- No check yet for optional and mandatory attributes in xml::Factory
|
||||
- Exceptions should be optional, best effort otherwise (option "strict") */
|
||||
namespace xml {
|
||||
|
||||
//============================================================================
|
||||
class Attributes: public std::map<std::string, std::string> {
|
||||
public:
|
||||
class Value: public value_type {
|
||||
public:
|
||||
Value(const std::string& name) throw();
|
||||
value_type& operator=(const std::string& value) throw();
|
||||
private:
|
||||
Value(); // not implemented
|
||||
};
|
||||
Attributes() throw();
|
||||
Attributes(const std::string& empty) throw();
|
||||
Attributes& operator<<(const value_type& v) throw();
|
||||
Attributes& operator<<(const std::string& key) throw();
|
||||
Attributes& operator=(const std::string& value) throw();
|
||||
private:
|
||||
iterator _active;
|
||||
};
|
||||
typedef Attributes::Value Attr;
|
||||
enum NodeType {START, END, EMPTY};
|
||||
struct Tag {
|
||||
std::string name;
|
||||
NodeType type;
|
||||
std::string text;
|
||||
Attributes attributes;
|
||||
};
|
||||
const bool mandatory = true;
|
||||
const bool optional = false;
|
||||
|
||||
//================================================================= EXCEPTIONS
|
||||
class Node;
|
||||
class Factory;
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
class exception: public std::exception {
|
||||
public:
|
||||
exception(std::string reason, const Node& t) throw();
|
||||
~exception() throw();
|
||||
const char* what() const throw();
|
||||
private:
|
||||
std::string _what;
|
||||
Node* _node;
|
||||
};
|
||||
//----------------------------------------------------------------------------
|
||||
class no_parent: public exception {
|
||||
public:
|
||||
no_parent(const Node& t) throw(): exception("node has no parent", t) {}
|
||||
};
|
||||
//----------------------------------------------------------------------------
|
||||
class tag_expected: public exception {
|
||||
public:
|
||||
tag_expected(const Node& t, const std::string& txt) throw():
|
||||
exception("tag ('<') expected, text not allowed\ntext: "+txt, t) {}
|
||||
};
|
||||
//----------------------------------------------------------------------------
|
||||
class access_error: public exception {
|
||||
public:
|
||||
access_error(const Node& t, const std::string& name) throw();
|
||||
~access_error() throw() {}
|
||||
const char* what() const throw();
|
||||
private:
|
||||
std::string _name;
|
||||
};
|
||||
//----------------------------------------------------------------------------
|
||||
class out_of_range: public exception {
|
||||
public:
|
||||
out_of_range(const Node& t, size_t pos) throw();
|
||||
~out_of_range() throw() {}
|
||||
const char* what() const throw();
|
||||
private:
|
||||
size_t _pos;
|
||||
};
|
||||
//----------------------------------------------------------------------------
|
||||
class cannot_have_children: public exception {
|
||||
public:
|
||||
cannot_have_children(const Node& parent, const Node& child) throw();
|
||||
~cannot_have_children() throw();
|
||||
const char* what() const throw();
|
||||
private:
|
||||
Node* _child;
|
||||
};
|
||||
//----------------------------------------------------------------------------
|
||||
class stream_error: public exception {
|
||||
public:
|
||||
stream_error(const std::string& reason, const Node& t,
|
||||
std::istream& is, Tag tag, char c=0) throw();
|
||||
~stream_error() throw() {}
|
||||
const char* what() const throw();
|
||||
private:
|
||||
std::istream::streampos _pos;
|
||||
Tag _tag;
|
||||
char _char;
|
||||
};
|
||||
//----------------------------------------------------------------------------
|
||||
class wrong_end_tag: public stream_error {
|
||||
public:
|
||||
wrong_end_tag(const Node& t, std::istream& is, Tag tag, char c=0)
|
||||
throw():
|
||||
stream_error("mismatching end tag", t, is, tag, c) {
|
||||
}
|
||||
};
|
||||
class missing_end_tag: public stream_error {
|
||||
public:
|
||||
missing_end_tag(const Node& t, std::istream& is, Tag tag, char c=0)
|
||||
throw():
|
||||
stream_error("missing end tag, end of file reached", t, is, tag, c) {
|
||||
}
|
||||
};
|
||||
class empty_stream: public stream_error {
|
||||
public:
|
||||
empty_stream(const Node& t, std::istream& is, Tag tag, char c=0)
|
||||
throw():
|
||||
stream_error("no xml tag found, stream is empty", t, is, tag, c) {
|
||||
}
|
||||
};
|
||||
class wrong_start_tag: public stream_error {
|
||||
public:
|
||||
wrong_start_tag(const Node& t, std::istream& is, Tag tag, char c=0)
|
||||
throw():
|
||||
stream_error("start tag does not match expected tag", t, is, tag, c) {
|
||||
}
|
||||
};
|
||||
class second_slash_in_tag: public stream_error {
|
||||
public:
|
||||
second_slash_in_tag(const Node& t, std::istream& is, Tag tag, char c=0)
|
||||
throw():
|
||||
stream_error("a tag may have no more than one slash", t, is, tag, c) {
|
||||
}
|
||||
};
|
||||
class character_after_slash: public stream_error {
|
||||
public:
|
||||
character_after_slash(const Node& t, std::istream& is, Tag tag, char c=0)
|
||||
throw():
|
||||
stream_error("unexpected character after empty-slash",
|
||||
t, is, tag, c) {
|
||||
}
|
||||
};
|
||||
class attributes_in_end_tag: public stream_error {
|
||||
public:
|
||||
attributes_in_end_tag(const Node& t, std::istream& is, Tag tag)
|
||||
throw():
|
||||
stream_error("attributes are not allowed in end tags",t, is, tag) {
|
||||
}
|
||||
};
|
||||
class attribute_value_not_quoted: public stream_error {
|
||||
public:
|
||||
attribute_value_not_quoted(const Node& t, std::istream& is, Tag tag,
|
||||
char c, std::string attr) throw():
|
||||
stream_error("attribute values must be quoted (\")\nattribute: "+attr,
|
||||
t, is, tag, c) {
|
||||
}
|
||||
};
|
||||
class duplicate_attribute: public stream_error {
|
||||
public:
|
||||
duplicate_attribute(const Node& t, std::istream& is, Tag tag,
|
||||
std::string attr) throw():
|
||||
stream_error("attribute duplicated\nattribute: "+attr,
|
||||
t, is, tag, 0) {
|
||||
}
|
||||
};
|
||||
|
||||
//============================================================================
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
class Node {
|
||||
private:
|
||||
typedef std::vector<Node*> Contents;
|
||||
public:
|
||||
typedef Contents::size_type size_type;
|
||||
Node(std::string name) throw();
|
||||
Node(const Node& o) throw();
|
||||
Node& operator=(const Node& o) throw();
|
||||
virtual ~Node() throw();
|
||||
virtual std::auto_ptr<Node> clone() const throw();
|
||||
virtual std::ostream& out(std::ostream& o, unsigned int level=0) const
|
||||
throw();
|
||||
virtual std::string text() const throw();
|
||||
virtual Node& text(const std::string& txt) throw(tag_expected);
|
||||
virtual Node& append(const Node& o) throw(cannot_have_children);
|
||||
virtual Node& set(const Attributes& o) throw();
|
||||
Node& clear() throw ();
|
||||
std::string name() const throw();
|
||||
bool isChild() const throw();
|
||||
Node& parent() const throw(no_parent);
|
||||
bool hasAttr(const std::string& name) const throw();
|
||||
Node& attr(const std::string& name, bool mandatory) throw();
|
||||
std::string attr(const std::string& name) const throw();
|
||||
std::string& attr(const std::string& name) throw();
|
||||
bool operator()(const std::string& child) const throw();
|
||||
Node& operator<<(const Node& o) throw(cannot_have_children);
|
||||
Node& operator<<(const Attributes& o) throw();
|
||||
//! Get the number of children.
|
||||
size_type children() const throw();
|
||||
//! Get the n-th child.
|
||||
const Node& operator[](size_type child) const throw(access_error);
|
||||
//! Get the n-th child.
|
||||
Node& operator[](size_type child) throw(access_error);
|
||||
//! Get the first named child.
|
||||
const Node& operator[](const std::string& child) const
|
||||
throw(access_error);
|
||||
//! Get the first named child.
|
||||
Node& operator[](const std::string& child) throw(access_error);
|
||||
std::string operator*() const throw();
|
||||
Node& operator=(const std::string& contents) throw(tag_expected);
|
||||
friend std::ostream& operator<<(std::ostream& o, const Node& t) throw();
|
||||
protected:
|
||||
Attributes _attributes;
|
||||
private:
|
||||
Node* find(const std::string& child) const throw();
|
||||
virtual std::auto_ptr<Node> clone(Node* p) const throw();
|
||||
Node(); // not implemented
|
||||
Contents _contents;
|
||||
std::string _name;
|
||||
Node* _parent;
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
class String: public Node {
|
||||
public:
|
||||
String(std::string name, const std::string& text = std::string()) throw();
|
||||
virtual std::auto_ptr<Node> clone() const throw();
|
||||
virtual ~String() throw() {}
|
||||
virtual std::string text() const throw();
|
||||
virtual String& text(const std::string& txt) throw(tag_expected);
|
||||
virtual std::ostream& out(std::ostream& o, unsigned int level=0) const
|
||||
throw();
|
||||
virtual String& append(const Node& o) throw(cannot_have_children);
|
||||
Node& operator=(const std::string& contents) throw();
|
||||
private:
|
||||
std::string _text;
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
class List: public Node {
|
||||
};
|
||||
|
||||
class Factory {
|
||||
public:
|
||||
Factory(const Node& t) throw();
|
||||
const Node& operator*() const throw();
|
||||
std::auto_ptr<Node> read(std::istream& is)
|
||||
throw(wrong_end_tag, wrong_start_tag, tag_expected,
|
||||
second_slash_in_tag, character_after_slash,
|
||||
missing_end_tag, attribute_value_not_quoted, access_error,
|
||||
empty_stream, duplicate_attribute, attributes_in_end_tag);
|
||||
private:
|
||||
friend class stream_error;
|
||||
Factory(); // not implemented
|
||||
Factory(const Factory&); // not implemented
|
||||
bool ws(char c) const throw();
|
||||
std::auto_ptr<Node> read(std::istream& is, const Node& position)
|
||||
throw(wrong_end_tag, wrong_start_tag, tag_expected,
|
||||
second_slash_in_tag, character_after_slash,
|
||||
missing_end_tag,
|
||||
attribute_value_not_quoted, access_error, duplicate_attribute,
|
||||
attributes_in_end_tag);
|
||||
Tag tag(std::istream& is, const Node& position)
|
||||
throw(second_slash_in_tag, character_after_slash,
|
||||
missing_end_tag,
|
||||
attribute_value_not_quoted, access_error, duplicate_attribute);
|
||||
std::auto_ptr<Node> _template;
|
||||
};
|
||||
|
||||
}
|
||||
#endif
|
Reference in New Issue
Block a user