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