fix json_value name clashing + add skeleton feature validation method

This commit is contained in:
artemp 2016-11-14 12:18:36 +01:00
parent 2b6f23890b
commit 92d35d1e40
3 changed files with 71 additions and 50 deletions

View file

@ -38,40 +38,40 @@
namespace mapnik { namespace json {
namespace x3 = boost::spirit::x3;
struct json_value;
using json_array = std::vector<json_value>;
using json_object_element = std::pair<int, json_value>;
using json_object = std::vector<json_object_element>;
using json_value_base = mapnik::util::variant<value_null,
struct geojson_value;
using geojson_array = std::vector<geojson_value>;
using geojson_object_element = std::pair<int, geojson_value>;
using geojson_object = std::vector<geojson_object_element>;
using geojson_value_base = mapnik::util::variant<value_null,
value_bool,
value_integer,
value_double,
std::string,
mapnik::geometry::geometry_types,
positions,
json_array,
json_object>;
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 <typename T>
json_value(T && val)
: json_value_base(std::forward<T>(val)) {}
geojson_value(T && val)
: geojson_value_base(std::forward<T>(val)) {}
#endif
};
namespace grammar {
using geojson_grammar_type = x3::rule<class geojson_tag, json_value>;
using key_value_type = x3::rule<class key_value_tag, json_object_element>;
using geojson_grammar_type = x3::rule<class geojson_tag, geojson_value>;
using key_value_type = x3::rule<class key_value_tag, geojson_object_element>;
BOOST_SPIRIT_DECLARE(geojson_grammar_type);
BOOST_SPIRIT_DECLARE(key_value_type);
}

View file

@ -91,24 +91,24 @@ struct geometry_type_ : x3::symbols<mapnik::geometry::geometry_types>
geojson_grammar_type const value("JSON Value");
key_value_type const key_value("JSON key/value");
// rules
x3::rule<class json_object_tag, json_object> object("JSON Object");
x3::rule<class json_array_tag, json_array> array("JSON Array");
x3::rule<class json_number_tag, json_value> number("JSON Number");
//x3::rule<class key_value_tag, json_object_element> key_value("JSON key/value");
x3::rule<class json_object_tag, geojson_object> object("JSON Object");
x3::rule<class json_array_tag, geojson_array> array("JSON Array");
x3::rule<class json_number_tag, geojson_value> number("JSON Number");
//x3::rule<class key_value_tag, geojson_object_element> key_value("JSON key/value");
// GeoJSON
x3::rule<class geojson_coordinates_tag, json_object_element> coordinates("GeoJSON Coordinates");
x3::rule<class geojson_geometry_type_tag, json_object_element> geometry_type("GeoJSON Geometry Type");
x3::rule<class geojson_key_value_type_tag, json_object_element> geojson_key_value("GeoJSON Key/Value Type");
auto const json_double = x3::real_parser<value_double, x3::strict_real_policies<value_double>>();
auto const json_integer = x3::int_parser<value_integer, 10, 1, -1>();
x3::rule<class geojson_coordinates_tag, geojson_object_element> coordinates("GeoJSON Coordinates");
x3::rule<class geojson_geometry_type_tag, geojson_object_element> geometry_type("GeoJSON Geometry Type");
x3::rule<class geojson_key_value_type_tag, geojson_object_element> geojson_key_value("GeoJSON Key/Value Type");
auto const geojson_double = x3::real_parser<value_double, x3::strict_real_policies<value_double>>();
auto const geojson_integer = x3::int_parser<value_integer, 10, 1, -1>();
// 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]

View file

@ -41,28 +41,21 @@
namespace {
template <typename T>
struct feature_validate_callback
template <typename Keys>
bool validate_geojson_feature(mapnik::json::geojson_value const& value, Keys const& keys)
{
feature_validate_callback(mapnik::box2d<T> const& box)
: box_(box) {}
void operator() (mapnik::feature_ptr const& f) const
if (!value.is<mapnik::json::geojson_object>())
{
if (box_ != box_)
{
throw std::runtime_error("Bounding boxes mismatch validation feature");
}
std::clog << "Expecting an GeoJSON object" << std::endl;
return false;
}
mapnik::box2d<T> const& box_;
mapnik::json::geojson_object const& feature = mapnik::util::get<mapnik::json::geojson_object>(value);
return true;
};
using box_type = mapnik::box2d<float>;
using boxes_type = std::vector<std::pair<box_type, std::pair<std::size_t, std::size_t>>>;
using base_iterator_type = char const*;
//const mapnik::json::extract_bounding_box_grammar<base_iterator_type, boxes_type> geojson_datasource_static_bbox_grammar;
//const mapnik::transcoder tr("utf8");
//const mapnik::json::feature_grammar_callback<base_iterator_type, mapnik::feature_impl, feature_validate_callback<float>> fc_grammar(tr);
}
namespace mapnik { namespace json {
@ -182,14 +175,14 @@ auto const bounding_box = x3::rule<struct bounding_box_rule_tag, std::tuple<boos
|
coordinates_rule[assign_bbox]
|
omit[json_string]
omit[geojson_string]
|
omit[char_]))][assign_range];
auto const feature = bounding_box[on_feature_callback];
auto const key_value_ = omit[json_string] > 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<struct feature_collection_tag> {}
namespace {
struct collect_features
{
collect_features(std::vector<mapnik::json::json_value> & values)
collect_features(std::vector<mapnik::json::geojson_value> & 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<mapnik::json::json_value> & values_;
std::vector<mapnik::json::geojson_value> & values_;
};
template <typename Iterator, typename Boxes>
@ -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<bool,typename T::value_type::first_type> process_geojson_file_x3(T & b
return std::make_pair(false, extent);
}
mapnik::context_ptr ctx = std::make_shared<mapnik::context_type>();
//std::size_t start_id = 1;
auto feature_grammar = x3::with<mapnik::json::keys_tag>(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<std::string::const_iterator> 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);