diff --git a/include/mapnik/xml_tree.hpp b/include/mapnik/xml_tree.hpp index 137fa83ab..534228e79 100644 --- a/include/mapnik/xml_tree.hpp +++ b/include/mapnik/xml_tree.hpp @@ -40,6 +40,7 @@ class color; class xml_attribute { public: + xml_attribute(std::string const& value); std::string value; mutable bool processed; }; @@ -47,16 +48,34 @@ public: class node_not_found: public std::exception { public: - node_not_found(std::string node_name) : node_name_(node_name) {} - virtual const char* what() const throw() - { - return ("Node "+node_name_+ "not found").c_str(); - } + node_not_found(std::string node_name); + virtual const char* what() const throw(); ~node_not_found() throw (); private: std::string node_name_; }; +class attribute_not_found: public std::exception +{ +public: + attribute_not_found(std::string const& node_name, std::string const& attribute_name); + virtual const char* what() const throw(); + ~attribute_not_found() throw (); +private: + std::string node_name_; + std::string attribute_name_; +}; + +class more_than_one_child: public std::exception +{ +public: + more_than_one_child(std::string const& node_name); + virtual const char* what() const throw(); + ~more_than_one_child() throw (); +private: + std::string node_name_; +}; + class xml_node { public: @@ -70,14 +89,15 @@ public: xml_node &add_child(std::string const& name, unsigned line=0, bool text_node = false); void add_attribute(std::string const& name, std::string const& value); - void set_processed(bool processed); + + void set_processed(bool processed) const; const_iterator begin() const; const_iterator end() const; xml_node & get_child(std::string const& name); xml_node const& get_child(std::string const& name) const; - xml_node *get_opt_child(std::string const& name) const; + xml_node const* get_opt_child(std::string const& name) const; bool has_child(std::string const& name) const; template diff --git a/src/load_map.cpp b/src/load_map.cpp index 1fbeff3d5..1d03075d4 100644 --- a/src/load_map.cpp +++ b/src/load_map.cpp @@ -708,7 +708,7 @@ void map_parser::parse_rule(feature_type_style & style, xml_node const& r) name = r.get_attr("name", std::string()); rule rule(name); - xml_node *child = r.get_opt_child("Filter"); + xml_node const* child = r.get_opt_child("Filter"); if (child) { rule.set_filter(child->get_value()); diff --git a/src/xml_tree.cpp b/src/xml_tree.cpp index 5ed24c351..415107da8 100644 --- a/src/xml_tree.cpp +++ b/src/xml_tree.cpp @@ -25,6 +25,8 @@ #include #include #include +#include +#include //boost #include @@ -152,6 +154,68 @@ xml_node &xml_tree::root() return node_; } +/****************************************************************************/ +xml_attribute::xml_attribute(std::string const& value_) + : value(value_), processed(false) +{ + +} + +/****************************************************************************/ + +node_not_found::node_not_found(std::string node_name) + : node_name_(node_name) +{ + +} + +const char* node_not_found::what() const throw() +{ + return ("Node "+node_name_+ "not found").c_str(); +} + +node_not_found::~node_not_found() throw() +{ + +} + + +attribute_not_found::attribute_not_found( + std::string const& node_name, + std::string const& attribute_name) + : + node_name_(node_name), + attribute_name_(attribute_name) +{ + +} + +const char* attribute_not_found::what() const throw() +{ + return ("Attribute '" + attribute_name_ +"' not found in node '"+node_name_+ "'").c_str(); +} + +attribute_not_found::~attribute_not_found() throw() +{ + +} + +more_than_one_child::more_than_one_child(std::string const& node_name) + : node_name_(node_name) +{ + +} + +const char* more_than_one_child::what() const throw() +{ + return ("More than one child node in node '" + node_name_ +"'").c_str(); +} + +more_than_one_child::~more_than_one_child() throw() +{ + +} + /****************************************************************************/ xml_node::xml_node(xml_tree &tree, std::string name, unsigned line, bool text_node) @@ -169,7 +233,7 @@ std::string xml_node::name() const if (!text_node_) return name_; else - return ""; //TODO: throw + return ""; } std::string xml_node::text() const @@ -180,9 +244,19 @@ std::string xml_node::text() const return "NOT A TEXT NODE"; //TODO: throw } -void xml_node::set_processed(bool processed) +bool xml_node::is_text() const { - processed_ = processed; + return text_node_; +} + +bool xml_node::is(std::string const& name) const +{ + if (name_ == name) + { + processed_ = true; + return true; + } + return false; } xml_node &xml_node::add_child(std::string const& name, unsigned line, bool text_node) @@ -191,6 +265,26 @@ xml_node &xml_node::add_child(std::string const& name, unsigned line, bool text_ return children_.back(); } +void xml_node::add_attribute(std::string const& name, std::string const& value) +{ + attributes_.insert(std::make_pair(name,xml_attribute(value))); +} + +void xml_node::set_processed(bool processed) const +{ + processed_ = processed; +} + +xml_node::const_iterator xml_node::begin() const +{ + return children_.begin(); +} + +xml_node::const_iterator xml_node::end() const +{ + return children_.end(); +} + xml_node & xml_node::get_child(std::string const& name) { std::list::iterator itr = children_.begin(); @@ -206,20 +300,100 @@ xml_node & xml_node::get_child(std::string const& name) throw node_not_found(name); } +xml_node const& xml_node::get_child(std::string const& name) const +{ + xml_node const* node = get_opt_child(name); + if (!node) throw node_not_found(name); + return *node; +} + +xml_node const* xml_node::get_opt_child(std::string const& name) const +{ + const_iterator itr = children_.begin(); + const_iterator end = children_.end(); + for (; itr != end; itr++) + { + if (!(itr->text_node_) && itr->name_ == name) + { + itr->set_processed(true); + return &(*itr); + } + } + return 0; +} + +bool xml_node::has_child(std::string const& name) const +{ + return get_opt_child(name) != 0; +} + template boost::optional xml_node::get_opt_attr(std::string const& name) const { std::map::const_iterator itr = attributes_.find(name); if (itr == attributes_.end()) return boost::optional(); - boost::optional result = fast_cast(itr->second); + itr->second.processed = true; + boost::optional result = fast_cast(tree_, itr->second.value); if (!result) { throw config_error(std::string("Failed to parse attribute '") + name + "'. Expected " + name_trait::name() + - " but got '" + itr->second + "'"); + " but got '" + itr->second.value + "'"); } return result; } +template +T xml_node::get_attr(std::string const& name, T const& default_value) const +{ + boost::optional value = get_opt_attr(name); + if (value) return *value; + return default_value; +} +template +T xml_node::get_attr(std::string const& name) const +{ + boost::optional value = get_opt_attr(name); + if (value) return *value; + throw attribute_not_found(name_, name); +} + +std::string xml_node::get_text() const +{ + if (children_.size() == 0) + { + return ""; + } + if (children_.size() == 1) + { + return children_.front().text(); + } + throw more_than_one_child(name_); +} + + +template +T xml_node::get_value() const +{ + boost::optional result = fast_cast(get_text()); + if (!result) + { + throw config_error(std::string("Failed to parse value in node '") + + name_ + "'. Expected " + name_trait::name() + + " but got '" + get_text() + "'"); + } + return result; +} + +#define compile_get_opt_attr(T) template boost::optional xml_node::get_opt_attr(std::string const&) const + +//compile_get_opt_attr(boolean); +compile_get_opt_attr(std::string); +compile_get_opt_attr(unsigned); +compile_get_opt_attr(float); +compile_get_opt_attr(double); +compile_get_opt_attr(color); +compile_get_opt_attr(gamma_method_e); +compile_get_opt_attr(line_rasterizer_e); } //ns mapnik