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