From 92d35d1e40244a44e2097bc036fcc0705c38e51b Mon Sep 17 00:00:00 2001 From: artemp Date: Mon, 14 Nov 2016 12:18:36 +0100 Subject: [PATCH] fix json_value name clashing + add skeleton feature validation method --- include/mapnik/json/geojson_grammar_x3.hpp | 28 ++++---- .../mapnik/json/geojson_grammar_x3_def.hpp | 28 ++++---- .../mapnik-index/process_geojson_file_x3.cpp | 65 ++++++++++++------- 3 files changed, 71 insertions(+), 50 deletions(-) diff --git a/include/mapnik/json/geojson_grammar_x3.hpp b/include/mapnik/json/geojson_grammar_x3.hpp index 557db176f..36fe6ea42 100644 --- a/include/mapnik/json/geojson_grammar_x3.hpp +++ b/include/mapnik/json/geojson_grammar_x3.hpp @@ -38,40 +38,40 @@ namespace mapnik { namespace json { namespace x3 = boost::spirit::x3; -struct json_value; -using json_array = std::vector; -using json_object_element = std::pair; -using json_object = std::vector; -using json_value_base = mapnik::util::variant; +using geojson_object_element = std::pair; +using geojson_object = std::vector; +using geojson_value_base = mapnik::util::variant; -struct json_value : json_value_base + geojson_array, + geojson_object>; +struct geojson_value : geojson_value_base { #if __cpp_inheriting_constructors >= 200802 - using json_value_base::json_value_base; + using geojson_value_base::geojson_value_base; #else - json_value() = default; + geojson_value() = default; template - json_value(T && val) - : json_value_base(std::forward(val)) {} + geojson_value(T && val) + : geojson_value_base(std::forward(val)) {} #endif }; namespace grammar { -using geojson_grammar_type = x3::rule; -using key_value_type = x3::rule; +using geojson_grammar_type = x3::rule; +using key_value_type = x3::rule; BOOST_SPIRIT_DECLARE(geojson_grammar_type); BOOST_SPIRIT_DECLARE(key_value_type); } diff --git a/include/mapnik/json/geojson_grammar_x3_def.hpp b/include/mapnik/json/geojson_grammar_x3_def.hpp index f299ab0d6..5b784d47e 100644 --- a/include/mapnik/json/geojson_grammar_x3_def.hpp +++ b/include/mapnik/json/geojson_grammar_x3_def.hpp @@ -91,24 +91,24 @@ struct geometry_type_ : x3::symbols geojson_grammar_type const value("JSON Value"); key_value_type const key_value("JSON key/value"); // rules -x3::rule object("JSON Object"); -x3::rule array("JSON Array"); -x3::rule number("JSON Number"); -//x3::rule key_value("JSON key/value"); +x3::rule object("JSON Object"); +x3::rule array("JSON Array"); +x3::rule number("JSON Number"); +//x3::rule key_value("JSON key/value"); // GeoJSON -x3::rule coordinates("GeoJSON Coordinates"); -x3::rule geometry_type("GeoJSON Geometry Type"); -x3::rule geojson_key_value("GeoJSON Key/Value Type"); -auto const json_double = x3::real_parser>(); -auto const json_integer = x3::int_parser(); +x3::rule coordinates("GeoJSON Coordinates"); +x3::rule geometry_type("GeoJSON Geometry Type"); +x3::rule geojson_key_value("GeoJSON Key/Value Type"); +auto const geojson_double = x3::real_parser>(); +auto const geojson_integer = x3::int_parser(); // import unicode string rule -namespace { auto const& json_string = mapnik::json::unicode_string_grammar(); } +namespace { auto const& geojson_string = mapnik::json::unicode_string_grammar(); } // import positions rule namespace { auto const& positions_rule = mapnik::json::positions_grammar(); } // GeoJSON types -auto const value_def = object | array | json_string | number +auto const value_def = object | array | geojson_string | number ; auto const coordinates_def = string("\"coordinates\"")[assign_key] > lit(':') > (positions_rule[assign_value] | value[assign_value]) @@ -117,7 +117,7 @@ auto const coordinates_def = string("\"coordinates\"")[assign_key] > lit(':') > auto const geometry_type_def = string("\"type\"")[assign_key] > lit(':') > (geometry_type_sym[assign_value] | value[assign_value]) ; -auto const key_value_def = json_string[assign_key] > lit(':') > value[assign_value] +auto const key_value_def = geojson_string[assign_key] > lit(':') > value[assign_value] ; auto const geojson_key_value_def = @@ -138,8 +138,8 @@ auto const array_def = lit('[') > lit(']') ; -auto const number_def = json_double[assign] - | json_integer[assign] +auto const number_def = geojson_double[assign] + | geojson_integer[assign] | lit("true") [make_true] | lit ("false") [make_false] | lit("null")[make_null] diff --git a/utils/mapnik-index/process_geojson_file_x3.cpp b/utils/mapnik-index/process_geojson_file_x3.cpp index a9ac4a129..d6283cf3d 100644 --- a/utils/mapnik-index/process_geojson_file_x3.cpp +++ b/utils/mapnik-index/process_geojson_file_x3.cpp @@ -41,28 +41,21 @@ namespace { -template -struct feature_validate_callback +template +bool validate_geojson_feature(mapnik::json::geojson_value const& value, Keys const& keys) { - feature_validate_callback(mapnik::box2d const& box) - : box_(box) {} - - void operator() (mapnik::feature_ptr const& f) const + if (!value.is()) { - if (box_ != box_) - { - throw std::runtime_error("Bounding boxes mismatch validation feature"); - } + std::clog << "Expecting an GeoJSON object" << std::endl; + return false; } - mapnik::box2d const& box_; + mapnik::json::geojson_object const& feature = mapnik::util::get(value); + return true; }; using box_type = mapnik::box2d; using boxes_type = std::vector>>; using base_iterator_type = char const*; -//const mapnik::json::extract_bounding_box_grammar geojson_datasource_static_bbox_grammar; -//const mapnik::transcoder tr("utf8"); -//const mapnik::json::feature_grammar_callback> fc_grammar(tr); } namespace mapnik { namespace json { @@ -182,14 +175,14 @@ auto const bounding_box = x3::rule lit(':') > omit[geojson_value] ; +auto const key_value_ = omit[geojson_string] > lit(':') > omit[geojson_value] ; auto const features = lit("\"features\"") > lit(':') > lit('[') > -(omit[feature] % lit(',')) > lit(']'); @@ -205,13 +198,13 @@ auto const feature_collection = x3::rule {} namespace { struct collect_features { - collect_features(std::vector & values) + collect_features(std::vector & values) : values_(values) {} - void operator() (mapnik::json::json_value && val) const + void operator() (mapnik::json::geojson_value && val) const { values_.push_back(std::move(val)); } - std::vector & values_; + std::vector & values_; }; template @@ -230,7 +223,6 @@ struct extract_positions auto size = std::distance(r.begin(), r.end()); boxes_.emplace_back(std::make_pair(bbox,std::make_pair(offset, size))); //boxes_.emplace_back(std::make_tuple(bbox,offset, size)); - //std::clog << offset << ":" << size << " " << bbox << std::endl; } Iterator start_; Boxes & boxes_; @@ -308,14 +300,43 @@ std::pair process_geojson_file_x3(T & b return std::make_pair(false, extent); } - mapnik::context_ptr ctx = std::make_shared(); - //std::size_t start_id = 1; + auto feature_grammar = x3::with(std::ref(keys)) + [ mapnik::json::grammar::geojson_value ]; for (auto const& item : boxes) { if (item.first.valid()) { if (!extent.valid()) extent = item.first; else extent.expand_to_include(item.first); + + if (validate_features) + { + base_iterator_type feat_itr = start + item.second.first; + base_iterator_type feat_end = feat_itr + item.second.second; + mapnik::json::geojson_value feature_value; + try + { + bool result = x3::phrase_parse(feat_itr, feat_end, feature_grammar, space_type(), feature_value); + if (!result || feat_itr != feat_end) + { + if (verbose) std::clog << std::string(start + item.second.first, feat_end ) << std::endl; + return std::make_pair(false, extent); + } + } + catch (x3::expectation_failure const& ex) + { + if (verbose) std::clog << ex.what() << std::endl; + return std::make_pair(false, extent); + } + catch (...) + { + return std::make_pair(false, extent); + } + if (!validate_geojson_feature(feature_value, keys)) + { + return std::make_pair(false, extent); + } + } } } return std::make_pair(true, extent);