geojson - feature_collection_parser

(allow single feature and geometry input)
This commit is contained in:
artemp 2013-11-04 12:39:10 +00:00
parent 9428f7f018
commit afd58da6e2
10 changed files with 122 additions and 56 deletions

View file

@ -43,6 +43,7 @@
#include <mapnik/wkt/wkt_factory.hpp>
#include <mapnik/json/feature_parser.hpp>
#include <mapnik/json/geojson_generator.hpp>
#include <mapnik/json/generic_json.hpp>
// stl
#include <stdexcept>
@ -74,7 +75,8 @@ mapnik::feature_ptr from_geojson_impl(std::string const& json, mapnik::context_p
{
mapnik::transcoder tr("utf8");
mapnik::feature_ptr feature(mapnik::feature_factory::create(ctx,1));
mapnik::json::feature_parser<std::string::const_iterator> parser(tr);
mapnik::json::generic_json<std::string::const_iterator> json_base;
mapnik::json::feature_parser<std::string::const_iterator> parser(json_base, tr);
if (!parser.parse(json.begin(), json.end(), *feature))
{
throw std::runtime_error("Failed to parse geojson feature");

View file

@ -25,6 +25,7 @@
// mapnik
#include <mapnik/unicode.hpp>
#include <mapnik/json/geometry_grammar.hpp>
#include <mapnik/json/feature_grammar.hpp>
#include <mapnik/feature.hpp>
@ -53,14 +54,15 @@ struct generate_id
mutable int id_;
};
template <typename Iterator, typename FeatureType>
struct feature_collection_grammar :
qi::grammar<Iterator, std::vector<feature_ptr>(), space_type>
{
feature_collection_grammar(context_ptr const& ctx, mapnik::transcoder const& tr)
: feature_collection_grammar::base_type(feature_collection,"feature-collection"),
feature_collection_grammar( generic_json<Iterator> & json, context_ptr const& ctx, mapnik::transcoder const& tr)
: feature_collection_grammar::base_type(start,"start"),
feature_g(json,tr),
ctx_(ctx),
feature_g(tr),
generate_id_(1)
{
using qi::lit;
@ -74,27 +76,38 @@ struct feature_collection_grammar :
using phoenix::new_;
using phoenix::val;
start = feature_collection | feature_from_geometry(_val) | feature(_val)
;
feature_collection = lit('{') >> (type | features) % lit(',') >> lit('}')
;
type = lit("\"type\"") > lit(':') > lit("\"FeatureCollection\"")
type = lit("\"type\"") >> lit(':') >> lit("\"FeatureCollection\"")
;
features = lit("\"features\"")
> lit(':')
> lit('[')
> -(feature(_val) % lit(','))
> lit(']')
>> lit(':')
>> lit('[')
>> -(feature(_val) % lit(','))
>> lit(']')
;
feature = eps[_a = phoenix::construct<mapnik::feature_ptr>(new_<mapnik::feature_impl>(ctx_,generate_id_()))]
>> feature_g(*_a)[push_back(_r1,_a)]
;
feature_from_geometry =
eps[_a = phoenix::construct<mapnik::feature_ptr>(new_<mapnik::feature_impl>(ctx_,generate_id_()))]
>> geometry_g(extract_geometry_(*_a)) [push_back(_r1, _a)]
;
start.name("start");
type.name("type");
features.name("features");
feature.name("feature");
feature_from_geometry.name("feature-from-geometry");
feature_g.name("feature-grammar");
geometry_g.name("geometry-grammar");
qi::on_error<qi::fail>
(
@ -109,12 +122,16 @@ struct feature_collection_grammar :
);
}
feature_grammar<Iterator,FeatureType> feature_g;
geometry_grammar<Iterator> geometry_g;
phoenix::function<extract_geometry> extract_geometry_;
context_ptr ctx_;
qi::rule<Iterator, std::vector<feature_ptr>(), space_type> feature_collection; // START
qi::rule<Iterator, std::vector<feature_ptr>(), space_type> start; // START
qi::rule<Iterator, std::vector<feature_ptr>(), space_type> feature_collection;
qi::rule<Iterator, space_type> type;
qi::rule<Iterator, std::vector<feature_ptr>(), space_type> features;
qi::rule<Iterator, qi::locals<feature_ptr,int>, void(std::vector<feature_ptr>&), space_type> feature;
feature_grammar<Iterator,FeatureType> feature_g;
qi::rule<Iterator, qi::locals<feature_ptr,int>, void(std::vector<feature_ptr>&), space_type> feature_from_geometry;
boost::phoenix::function<generate_id> generate_id_;
};

View file

@ -38,6 +38,7 @@
namespace mapnik { namespace json {
template <typename Iterator, typename FeatureType> struct feature_collection_grammar;
template <typename Iterator> struct generic_json;
template <typename Iterator>
class MAPNIK_DECL feature_collection_parser : private mapnik::noncopyable
@ -45,7 +46,7 @@ class MAPNIK_DECL feature_collection_parser : private mapnik::noncopyable
typedef Iterator iterator_type;
typedef mapnik::feature_impl feature_type;
public:
feature_collection_parser(mapnik::context_ptr const& ctx, mapnik::transcoder const& tr);
feature_collection_parser(generic_json<Iterator> & json, mapnik::context_ptr const& ctx, mapnik::transcoder const& tr);
~feature_collection_parser();
bool parse(iterator_type first, iterator_type last, std::vector<mapnik::feature_ptr> & features);
private:

View file

@ -2,7 +2,7 @@
*
* This file is part of Mapnik (c++ mapping toolkit)
*
* Copyright (C) 2012 Artem Pavlenko
* Copyright (C) 2013 Artem Pavlenko
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@ -29,6 +29,7 @@
#include <mapnik/feature.hpp>
#include <mapnik/unicode.hpp>
#include <mapnik/value.hpp>
#include <mapnik/json/generic_json.hpp>
// spirit::qi
#include <boost/variant/static_visitor.hpp>
@ -126,33 +127,16 @@ struct extract_geometry
};
#endif
template <typename Iterator>
struct generic_json
{
qi::rule<Iterator,space_type> value;
qi::symbols<char const, char const> unesc_char;
qi::uint_parser< unsigned, 16, 4, 4 > hex4 ;
qi::int_parser<mapnik::value_integer,10,1,-1> int__;
qi::rule<Iterator,std::string(), space_type> string_;
qi::rule<Iterator,space_type> key_value;
qi::rule<Iterator,boost::variant<value_null,bool,
value_integer,value_double>(),space_type> number;
qi::rule<Iterator,space_type> object;
qi::rule<Iterator,space_type> array;
qi::rule<Iterator,space_type> pairs;
qi::real_parser<double, qi::strict_real_policies<double> > strict_double;
};
template <typename Iterator, typename FeatureType>
struct feature_grammar :
qi::grammar<Iterator, void(FeatureType&),
space_type>
{
feature_grammar(mapnik::transcoder const& tr);
feature_grammar(generic_json<Iterator> & json, mapnik::transcoder const& tr);
// start
// generic JSON
generic_json<Iterator> json;
generic_json<Iterator> & json_;
// geoJSON
qi::rule<Iterator,void(FeatureType&),space_type> feature; // START

View file

@ -38,6 +38,7 @@
namespace mapnik { namespace json {
template <typename Iterator, typename FeatureType> struct feature_grammar;
template <typename Iterator> struct generic_json;
template <typename Iterator>
class MAPNIK_DECL feature_parser : private mapnik::noncopyable
@ -45,7 +46,7 @@ class MAPNIK_DECL feature_parser : private mapnik::noncopyable
typedef Iterator iterator_type;
typedef mapnik::feature_impl feature_type;
public:
feature_parser(mapnik::transcoder const& tr);
feature_parser(generic_json<Iterator> & json, mapnik::transcoder const& tr);
~feature_parser();
bool parse(iterator_type first, iterator_type last, mapnik::feature_impl & f);
private:

View file

@ -0,0 +1,55 @@
/*****************************************************************************
*
* This file is part of Mapnik (c++ mapping toolkit)
*
* Copyright (C) 2013 Artem Pavlenko
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*****************************************************************************/
#ifndef MAPNIK_GENERIC_JSON_HPP
#define MAPNIK_GENERIC_JSON_HPP
#include <boost/variant.hpp>
#include <boost/spirit/include/qi.hpp>
namespace mapnik { namespace json {
namespace qi = boost::spirit::qi;
namespace standard_wide = boost::spirit::standard_wide;
using standard_wide::space_type;
template <typename Iterator>
struct generic_json
{
qi::rule<Iterator,space_type> value;
qi::symbols<char const, char const> unesc_char;
qi::uint_parser< unsigned, 16, 4, 4 > hex4 ;
qi::int_parser<mapnik::value_integer,10,1,-1> int__;
qi::rule<Iterator,std::string(), space_type> string_;
qi::rule<Iterator,space_type> key_value;
qi::rule<Iterator,boost::variant<value_null,bool,
value_integer,value_double>(),space_type> number;
qi::rule<Iterator,space_type> object;
qi::rule<Iterator,space_type> array;
qi::rule<Iterator,space_type> pairs;
qi::real_parser<double, qi::strict_real_policies<double> > strict_double;
};
}}
#endif // MAPNIK_GENERIC_JSON_HPP

View file

@ -48,6 +48,7 @@
#include <mapnik/projection.hpp>
#include <mapnik/util/geometry_to_ds_type.hpp>
#include <mapnik/json/feature_collection_parser.hpp>
#include <mapnik/json/generic_json.hpp>
using mapnik::datasource;
using mapnik::parameters;
@ -130,7 +131,8 @@ geojson_datasource::geojson_datasource(parameters const& params)
boost::spirit::make_default_multi_pass(base_iterator_type());
mapnik::context_ptr ctx = std::make_shared<mapnik::context_type>();
mapnik::json::feature_collection_parser<boost::spirit::multi_pass<base_iterator_type> > p(ctx,*tr_);
mapnik::json::generic_json<boost::spirit::multi_pass<base_iterator_type> > json;
mapnik::json::feature_collection_parser<boost::spirit::multi_pass<base_iterator_type> > p(json, ctx,*tr_);
bool result = p.parse(begin,end, features_);
if (!result)
{

View file

@ -45,8 +45,10 @@ namespace mapnik { namespace json {
#if BOOST_VERSION >= 104700
template <typename Iterator>
feature_collection_parser<Iterator>::feature_collection_parser(mapnik::context_ptr const& ctx, mapnik::transcoder const& tr)
: grammar_(new feature_collection_grammar<iterator_type,feature_type>(ctx,tr)) {}
feature_collection_parser<Iterator>::feature_collection_parser(generic_json<Iterator> & json,
mapnik::context_ptr const& ctx,
mapnik::transcoder const& tr)
: grammar_(new feature_collection_grammar<iterator_type,feature_type>(json, ctx,tr)) {}
template <typename Iterator>
feature_collection_parser<Iterator>::~feature_collection_parser() {}

View file

@ -33,8 +33,9 @@
namespace mapnik { namespace json {
template <typename Iterator, typename FeatureType>
feature_grammar<Iterator,FeatureType>::feature_grammar(mapnik::transcoder const& tr)
feature_grammar<Iterator,FeatureType>::feature_grammar(generic_json<Iterator> & json, mapnik::transcoder const& tr)
: feature_grammar::base_type(feature,"feature"),
json_(json),
put_property_(put_property(tr))
{
using qi::lit;
@ -66,37 +67,37 @@ feature_grammar<Iterator,FeatureType>::feature_grammar(mapnik::transcoder const&
using phoenix::construct;
// generic json types
json.value = json.object | json.array | json.string_
| json.number
json_.value = json_.object | json_.array | json_.string_
| json_.number
;
json.pairs = json.key_value % lit(',')
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_.object = lit('{')
>> *json_.pairs
>> lit('}')
;
json.array = lit('[')
>> json.value >> *(lit(',') >> json.value)
json_.array = lit('[')
>> json_.value >> *(lit(',') >> json_.value)
>> lit(']')
;
// https://github.com/mapnik/mapnik/issues/1342
#if BOOST_VERSION >= 104700
json.number %= json.strict_double
json_.number %= json_.strict_double
#else
json.number = json.strict_double
json_.number = json_.strict_double
#endif
| json.int__
| json_.int__
| lit("true") [_val = true]
| lit ("false") [_val = false]
| lit("null")[_val = construct<value_null>()]
;
json.unesc_char.add
json_.unesc_char.add
("\\\"", '\"') // quotation mark
("\\\\", '\\') // reverse solidus
("\\/", '/') // solidus
@ -107,10 +108,10 @@ feature_grammar<Iterator,FeatureType>::feature_grammar(mapnik::transcoder const&
("\\t", '\t') // tab
;
#if BOOST_VERSION > 104200
json.string_ %= lit('"') >> no_skip[*(json.unesc_char | "\\u" >> json.hex4 | (char_ - lit('"')))] >> lit('"')
json_.string_ %= lit('"') >> no_skip[*(json_.unesc_char | "\\u" >> json_.hex4 | (char_ - lit('"')))] >> lit('"')
;
#else
json.string_ %= lit('"') >> lexeme[*(json.unesc_char | "\\u" >> json.hex4 | (char_ - lit('"')))] >> lit('"')
json_.string_ %= lit('"') >> lexeme[*(json_.unesc_char | "\\u" >> json_.hex4 | (char_ - lit('"')))] >> lit('"')
;
#endif
// geojson types
@ -121,7 +122,8 @@ feature_grammar<Iterator,FeatureType>::feature_grammar(mapnik::transcoder const&
;
feature = lit('{')
>> (feature_type | (lit("\"geometry\"") > lit(':') > geometry_grammar_(extract_geometry_(_r1))) | properties(_r1) | json.key_value) % lit(',')
>> (feature_type | (lit("\"geometry\"") >> lit(':')
>> geometry_grammar_(extract_geometry_(_r1))) | properties(_r1) | json_.key_value) % lit(',')
>> lit('}')
;
@ -129,10 +131,10 @@ feature_grammar<Iterator,FeatureType>::feature_grammar(mapnik::transcoder const&
>> lit(':') >> (lit('{') >> attributes(_r1) >> lit('}')) | lit("null")
;
attributes = (json.string_ [_a = _1] >> lit(':') >> attribute_value [put_property_(_r1,_a,_1)]) % lit(',')
attributes = (json_.string_ [_a = _1] >> lit(':') >> attribute_value [put_property_(_r1,_a,_1)]) % lit(',')
;
attribute_value %= json.number | json.string_ ;
attribute_value %= json_.number | json_.string_ ;
feature.name("Feature");
properties.name("Properties");

View file

@ -35,8 +35,8 @@ namespace mapnik { namespace json {
#if BOOST_VERSION >= 104700
template <typename Iterator>
feature_parser<Iterator>::feature_parser(mapnik::transcoder const& tr)
: grammar_(new feature_grammar<iterator_type,feature_type>(tr)) {}
feature_parser<Iterator>::feature_parser(generic_json<Iterator> & json, mapnik::transcoder const& tr)
: grammar_(new feature_grammar<iterator_type,feature_type>(json, tr)) {}
template <typename Iterator>
feature_parser<Iterator>::~feature_parser() {}