295 lines
11 KiB
C++
295 lines
11 KiB
C++
![]() |
/*! @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
|