00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #ifndef MAPNIK_CONFIG_HELPERS_INCLUDED
00024 #define MAPNIK_CONFIG_HELPERS_INCLUDED
00025
00026 #include <mapnik/enumeration.hpp>
00027 #include <mapnik/config_error.hpp>
00028 #include <mapnik/color_factory.hpp>
00029
00030 #include <boost/property_tree/ptree.hpp>
00031 #include <boost/lexical_cast.hpp>
00032 #include <boost/optional.hpp>
00033
00034 #include <iostream>
00035 #include <sstream>
00036
00037 namespace mapnik {
00038
00039 template <typename T>
00040 T get(const boost::property_tree::ptree & node, const std::string & name, bool is_attribute,
00041 const T & default_value);
00042 template <typename T>
00043 T get(const boost::property_tree::ptree & node, const std::string & name, bool is_attribute);
00044 template <typename T>
00045 T get_own(const boost::property_tree::ptree & node, const std::string & name);
00046 template <typename T>
00047 boost::optional<T> get_optional(const boost::property_tree::ptree & node, const std::string & name,
00048 bool is_attribute);
00049
00050 template <typename T>
00051 boost::optional<T> get_opt_attr( const boost::property_tree::ptree & node,
00052 const std::string & name)
00053 {
00054 return get_optional<T>( node, name, true);
00055 }
00056
00057 template <typename T>
00058 boost::optional<T> get_opt_child( const boost::property_tree::ptree & node,
00059 const std::string & name)
00060 {
00061 return get_optional<T>( node, name, false);
00062 }
00063
00064 template <typename T>
00065 T get_attr( const boost::property_tree::ptree & node, const std::string & name,
00066 const T & default_value )
00067 {
00068 return get<T>( node, name, true, default_value);
00069 }
00070
00071 template <typename T>
00072 T get_attr( const boost::property_tree::ptree & node, const std::string & name )
00073 {
00074 return get<T>( node, name, true );
00075 }
00076
00077 template <typename T>
00078 T get_css( const boost::property_tree::ptree & node, const std::string & name )
00079 {
00080 return get_own<T>( node, std::string("CSS parameter '") + name + "'");
00081 }
00082
00084 template <typename charT, typename traits>
00085 std::basic_istream<charT, traits> &
00086 operator >> ( std::basic_istream<charT, traits> & s, mapnik::Color & c )
00087 {
00088 std::string word;
00089 s >> word;
00090 if ( s )
00091 {
00092 try
00093 {
00094 c = mapnik::color_factory::from_string( word.c_str() );
00095 }
00096 catch (...)
00097 {
00098 s.setstate( std::ios::failbit );
00099 }
00100 }
00101 return s;
00102 }
00103
00104 template <typename charT, typename traits>
00105 std::basic_ostream<charT, traits> &
00106 operator << ( std::basic_ostream<charT, traits> & s, const mapnik::Color & c )
00107 {
00108 std::string hex_string( c.to_hex_string() );
00109 s << hex_string;
00110 return s;
00111 }
00112
00114 class boolean {
00115 public:
00116 boolean() {}
00117 boolean(bool b) : b_(b) {}
00118 boolean(const boolean & b) : b_(b.b_) {}
00119
00120 operator bool() const
00121 {
00122 return b_;
00123 }
00124 boolean & operator = (const boolean & other)
00125 {
00126 b_ = other.b_;
00127 return * this;
00128 }
00129 boolean & operator = (bool other)
00130 {
00131 b_ = other;
00132 return * this;
00133 }
00134 private:
00135 bool b_;
00136 };
00137
00139 template <typename charT, typename traits>
00140 std::basic_istream<charT, traits> &
00141 operator >> ( std::basic_istream<charT, traits> & s, boolean & b )
00142 {
00143 std::string word;
00144 s >> word;
00145 if ( s )
00146 {
00147 if ( word == "true" || word == "yes" || word == "on" ||
00148 word == "1")
00149 {
00150 b = true;
00151 }
00152 else if ( word == "false" || word == "no" || word == "off" ||
00153 word == "0")
00154 {
00155 b = false;
00156 }
00157 else
00158 {
00159 s.setstate( std::ios::failbit );
00160 }
00161 }
00162 return s;
00163 }
00164
00165 template <typename charT, typename traits>
00166 std::basic_ostream<charT, traits> &
00167 operator << ( std::basic_ostream<charT, traits> & s, const boolean & b )
00168 {
00169 s << ( b ? "true" : "false" );
00170 return s;
00171 }
00172
00173 template <typename T>
00174 void set_attr(boost::property_tree::ptree & pt, const std::string & name, const T & v)
00175 {
00176 pt.put("<xmlattr>." + name, v);
00177 }
00178
00179
00180
00181
00182
00183
00184
00185
00186
00187 class boolean;
00188
00189 template <typename T>
00190 void set_css(boost::property_tree::ptree & pt, const std::string & name, const T & v)
00191 {
00192 boost::property_tree::ptree & css_node = pt.push_back(
00193 boost::property_tree::ptree::value_type("CssParameter",
00194 boost::property_tree::ptree()))->second;
00195 css_node.put("<xmlattr>.name", name );
00196 css_node.put_own( v );
00197 }
00198
00199 template <typename T>
00200 struct name_trait
00201 {
00202 static std::string name()
00203 {
00204 return "<unknown>";
00205 }
00206
00207
00208
00209
00210 BOOST_STATIC_ASSERT( sizeof(T) == 0 );
00211 };
00212
00213 #define DEFINE_NAME_TRAIT_WITH_NAME( type, type_name ) \
00214 template <> \
00215 struct name_trait<type> \
00216 { \
00217 static std::string name() { return std::string("type ") + type_name; } \
00218 };
00219
00220 #define DEFINE_NAME_TRAIT( type ) \
00221 DEFINE_NAME_TRAIT_WITH_NAME( type, #type );
00222
00223 DEFINE_NAME_TRAIT( double );
00224 DEFINE_NAME_TRAIT( float );
00225 DEFINE_NAME_TRAIT( unsigned );
00226 DEFINE_NAME_TRAIT( boolean );
00227 DEFINE_NAME_TRAIT_WITH_NAME( int, "integer" );
00228 DEFINE_NAME_TRAIT_WITH_NAME( std::string, "string" );
00229 DEFINE_NAME_TRAIT_WITH_NAME( Color, "color" );
00230
00231 template <typename ENUM, int MAX>
00232 struct name_trait< mapnik::enumeration<ENUM, MAX> >
00233 {
00234 typedef enumeration<ENUM, MAX> Enum;
00235
00236 static std::string name()
00237 {
00238 std::string value_list("one of [");
00239 for (unsigned i = 0; i < Enum::MAX; ++i)
00240 {
00241 value_list += Enum::get_string( i );
00242 if ( i + 1 < Enum::MAX ) value_list += ", ";
00243 }
00244 value_list += "]";
00245
00246 return value_list;
00247 }
00248 };
00249
00250 template <typename T>
00251 T get(const boost::property_tree::ptree & node, const std::string & name, bool is_attribute,
00252 const T & default_value)
00253 {
00254 boost::optional<std::string> str;
00255 if (is_attribute)
00256 {
00257 str = node.get_optional<std::string>( std::string("<xmlattr>.") + name );
00258 }
00259 else
00260 {
00261 str = node.get_optional<std::string>(name );
00262 }
00263
00264 if ( str ) {
00265 try
00266 {
00267 return boost::lexical_cast<T>( * str );
00268 }
00269 catch (const boost::bad_lexical_cast & )
00270 {
00271 throw config_error(string("Failed to parse ") +
00272 (is_attribute ? "attribute" : "child node") + " '" +
00273 name + "'. Expected " + name_trait<T>::name() +
00274 " but got '" + *str + "'");
00275 }
00276 } else {
00277 return default_value;
00278 }
00279 }
00280
00281 template <typename T>
00282 T get(const boost::property_tree::ptree & node, const std::string & name, bool is_attribute)
00283 {
00284 boost::optional<std::string> str;
00285 if (is_attribute)
00286 {
00287 str = node.get_optional<std::string>( std::string("<xmlattr>.") + name);
00288 }
00289 else
00290 {
00291 str = node.get_optional<std::string>(name);
00292 }
00293
00294 if ( ! str ) {
00295 throw config_error(string("Required ") +
00296 (is_attribute ? "attribute " : "child node ") +
00297 "'" + name + "' is missing");
00298 }
00299 try
00300 {
00301 return boost::lexical_cast<T>( *str );
00302 }
00303 catch (const boost::bad_lexical_cast & )
00304 {
00305 throw config_error(string("Failed to parse ") +
00306 (is_attribute ? "attribute" : "child node") + " '" +
00307 name + "'. Expected " + name_trait<T>::name() +
00308 " but got '" + *str + "'");
00309 }
00310 }
00311
00312 template <typename T>
00313 T get_own(const boost::property_tree::ptree & node, const std::string & name)
00314 {
00315 try
00316 {
00317 return node.get_own<T>();
00318 }
00319 catch (...)
00320 {
00321 throw config_error(string("Failed to parse ") +
00322 name + ". Expected " + name_trait<T>::name() +
00323 " but got '" + node.data() + "'");
00324 }
00325 }
00326
00327 template <typename T>
00328 boost::optional<T> get_optional(const boost::property_tree::ptree & node, const std::string & name,
00329 bool is_attribute)
00330 {
00331 boost::optional<std::string> str;
00332 if (is_attribute)
00333 {
00334 str = node.get_optional<std::string>( std::string("<xmlattr>.") + name);
00335 }
00336 else
00337 {
00338 str = node.get_optional<std::string>(name);
00339 }
00340
00341 boost::optional<T> result;
00342 if ( str ) {
00343 try
00344 {
00345 result = boost::lexical_cast<T>( *str );
00346 }
00347 catch (const boost::bad_lexical_cast &)
00348 {
00349 throw config_error(string("Failed to parse ") +
00350 (is_attribute ? "attribute" : "child node") + " '" +
00351 name + "'. Expected " + name_trait<T>::name() +
00352 " but got '" + *str + "'");
00353 }
00354
00355 }
00356 return result;
00357 }
00358 }
00359
00360 #endif // MAPNIK_CONFIG_HELPERS_INCLUDED