diff --git a/include/mapnik/json/feature_grammar.hpp b/include/mapnik/json/feature_grammar.hpp index ae59e3bf0..e63052eb5 100644 --- a/include/mapnik/json/feature_grammar.hpp +++ b/include/mapnik/json/feature_grammar.hpp @@ -31,6 +31,7 @@ #include #include #include +#include #pragma GCC diagnostic push #include @@ -45,8 +46,72 @@ namespace qi = boost::spirit::qi; namespace phoenix = boost::phoenix; namespace fusion = boost::fusion; -class attribute_value_visitor +namespace { +struct stringifier +{ + std::string operator()(std::string const& val) const + { + return "\"" + val + "\""; + } + std::string operator()(value_null) const + { + return "null"; + } + + std::string operator()(value_bool val) const + { + return val ? "true" : "false"; + } + + std::string operator()(value_integer val) const + { + std::string str; + util::to_string(str, val); + return str; + } + + std::string operator()(value_double val) const + { + std::string str; + util::to_string(str, val); + return str; + } + + std::string operator()(std::vector const& array) const + { + std::string str = "["; + bool first = true; + for (auto const& val : array) + { + if (first) first = false; + else str += ","; + str += mapnik::util::apply_visitor(*this, val); + } + str += "]"; + return str; + } + + std::string operator()(std::unordered_map const& object) const + { + std::string str = "{"; + bool first = true; + for (auto const& kv : object) + { + if (first) first = false; + else str += ","; + str += kv.first; + str += ":"; + str += mapnik::util::apply_visitor(*this, kv.second); + } + str += "}"; + return str; + } +}; + +} // anonymous ns + +struct attribute_value_visitor { public: attribute_value_visitor(mapnik::transcoder const& tr) @@ -57,6 +122,18 @@ public: return mapnik::value(tr_.transcode(val.c_str())); } + mapnik::value operator()(std::vector const& array) const + { + std::string str = stringifier()(array); + return mapnik::value(tr_.transcode(str.c_str())); + } + + mapnik::value operator()(std::unordered_map const& object) const + { + std::string str = stringifier()(object); + return mapnik::value(tr_.transcode(str.c_str())); + } + template mapnik::value operator()(T const& val) const { @@ -102,8 +179,6 @@ struct feature_grammar : qi::grammar qi::rule properties; qi::rule, void(FeatureType &),space_type> attributes; qi::rule attribute_value; - qi::rule, std::string(), space_type> stringify_object; - qi::rule, std::string(), space_type> stringify_array; // functions phoenix::function put_property_; phoenix::function set_geometry; diff --git a/include/mapnik/json/feature_grammar_impl.hpp b/include/mapnik/json/feature_grammar_impl.hpp index 1ddf95581..c6340d779 100644 --- a/include/mapnik/json/feature_grammar_impl.hpp +++ b/include/mapnik/json/feature_grammar_impl.hpp @@ -44,7 +44,6 @@ feature_grammar::feature_grammar(mapnik::tran qi::_r1_type _r1; qi::eps_type eps; qi::char_type char_; - qi::no_skip_type no_skip; using qi::fail; using qi::on_error; using phoenix::new_; @@ -57,17 +56,19 @@ feature_grammar::feature_grammar(mapnik::tran json_.pairs = json_.key_value % lit(',') ; - json_.key_value = (json_.string_ > lit(':') > json_.value) + json_.key_value = json_.string_ > lit(':') > json_.value ; json_.object = lit('{') - > *json_.pairs + > json_.pairs > lit('}') ; + json_.array = lit('[') > json_.value > *(lit(',') > json_.value) > lit(']') ; + json_.number = json_.strict_double[_val = json_.double_converter(_1)] | json_.int__[_val = json_.integer_converter(_1)] | lit("true") [_val = true] @@ -99,13 +100,7 @@ feature_grammar::feature_grammar(mapnik::tran attributes = (json_.string_ [_a = _1] > lit(':') > attribute_value [put_property_(_r1,_a,_1)]) % lit(',') ; - attribute_value %= json_.number | json_.string_ | stringify_object | stringify_array - ; - - stringify_object %= char_('{')[_a = 1 ] > no_skip[*(eps(_a > 0) > (char_('{')[_a +=1] | char_('}')[_a -=1] | char_))] - ; - - stringify_array %= char_('[')[_a = 1 ] > no_skip[*(eps(_a > 0) > (char_('[')[_a +=1] | char_(']')[_a -=1] | char_))] + attribute_value %= json_.number | json_.string_ | json_.object | json_.array ; feature.name("Feature");