geojson - feature_collection_parser
(allow single feature and geometry input)
This commit is contained in:
parent
9428f7f018
commit
afd58da6e2
10 changed files with 122 additions and 56 deletions
|
@ -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");
|
||||
|
|
|
@ -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_;
|
||||
};
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
|
55
include/mapnik/json/generic_json.hpp
Normal file
55
include/mapnik/json/generic_json.hpp
Normal 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
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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() {}
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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() {}
|
||||
|
|
Loading…
Add table
Reference in a new issue