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