backport geojson parsing/generation fixes from master to 2.3.x - refs #2083
This commit is contained in:
parent
15373f8e48
commit
e5bb5ed8aa
16 changed files with 213 additions and 81 deletions
|
@ -41,6 +41,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>
|
||||
|
@ -72,7 +73,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;
|
||||
|
||||
feature_collection = lit('{') >> (type | features) % lit(",") >> lit('}')
|
||||
start = feature_collection | feature_from_geometry(_val) | feature(_val)
|
||||
;
|
||||
|
||||
type = lit("\"type\"") > lit(":") > lit("\"FeatureCollection\"")
|
||||
feature_collection = lit('{') >> (type | features) % lit(',') >> lit('}')
|
||||
;
|
||||
|
||||
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>
|
||||
(
|
||||
|
@ -104,17 +117,21 @@ struct feature_collection_grammar :
|
|||
<< qi::_4
|
||||
<< phoenix::val(" here: \"")
|
||||
<< construct<std::string>(qi::_3, qi::_2)
|
||||
<< phoenix::val("\"")
|
||||
<< phoenix::val('\"')
|
||||
<< std::endl
|
||||
);
|
||||
}
|
||||
|
||||
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,11 +46,11 @@ 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:
|
||||
boost::scoped_ptr<feature_collection_grammar<iterator_type,feature_type> > grammar_;
|
||||
const boost::scoped_ptr<feature_collection_grammar<iterator_type,feature_type> > grammar_;
|
||||
};
|
||||
|
||||
}}
|
||||
|
|
|
@ -188,8 +188,6 @@ struct feature_generator_grammar:
|
|||
using boost::spirit::karma::lit;
|
||||
using boost::spirit::karma::uint_;
|
||||
using boost::spirit::karma::bool_;
|
||||
//using boost::spirit::karma::int_;
|
||||
//using boost::spirit::karma::long_long;
|
||||
using boost::spirit::karma::double_;
|
||||
using boost::spirit::karma::_val;
|
||||
using boost::spirit::karma::_1;
|
||||
|
|
|
@ -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>
|
||||
|
@ -75,8 +76,7 @@ struct put_property
|
|||
template <typename T0,typename T1, typename T2>
|
||||
result_type operator() (T0 & feature, T1 const& key, T2 const& val) const
|
||||
{
|
||||
mapnik::value v = boost::apply_visitor(attribute_value_visitor(tr_),val); // TODO: optimize
|
||||
feature.put_new(key, v);
|
||||
feature.put_new(key, boost::apply_visitor(attribute_value_visitor(tr_),val));
|
||||
}
|
||||
mapnik::transcoder const& tr_;
|
||||
};
|
||||
|
@ -132,22 +132,11 @@ 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
|
||||
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;
|
||||
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,11 +46,11 @@ 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:
|
||||
boost::scoped_ptr<feature_grammar<iterator_type,feature_type> > grammar_;
|
||||
const boost::scoped_ptr<feature_grammar<iterator_type,feature_type> > grammar_;
|
||||
};
|
||||
|
||||
}}
|
||||
|
|
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
|
|
@ -46,7 +46,7 @@ public:
|
|||
~feature_generator();
|
||||
bool generate(std::string & geojson, mapnik::feature_impl const& f);
|
||||
private:
|
||||
boost::scoped_ptr<feature_generator_grammar<sink_type> > grammar_;
|
||||
const boost::scoped_ptr<feature_generator_grammar<sink_type> > grammar_;
|
||||
};
|
||||
|
||||
class MAPNIK_DECL geometry_generator : private mapnik::noncopyable
|
||||
|
@ -57,7 +57,7 @@ public:
|
|||
~geometry_generator();
|
||||
bool generate(std::string & geojson, mapnik::geometry_container const& g);
|
||||
private:
|
||||
boost::scoped_ptr<multi_geometry_generator_grammar<sink_type> > grammar_;
|
||||
const boost::scoped_ptr<multi_geometry_generator_grammar<sink_type> > grammar_;
|
||||
};
|
||||
|
||||
#else
|
||||
|
|
|
@ -38,8 +38,8 @@
|
|||
#include <boost/spirit/include/phoenix_fusion.hpp>
|
||||
#include <boost/spirit/include/phoenix_function.hpp>
|
||||
#include <boost/spirit/include/phoenix_statement.hpp>
|
||||
#include <boost/fusion/include/boost_tuple.hpp>
|
||||
#include <boost/math/special_functions/trunc.hpp> // for vc++
|
||||
#include <boost/fusion/adapted/boost_tuple.hpp>
|
||||
#include <boost/math/special_functions/trunc.hpp> // for vc++ and android whose c++11 libs lack std::trunct
|
||||
|
||||
namespace boost { namespace spirit { namespace traits {
|
||||
|
||||
|
@ -103,6 +103,20 @@ struct multi_geometry_type
|
|||
return boost::tuple<unsigned,bool>(type, collection);
|
||||
}
|
||||
};
|
||||
|
||||
struct not_empty
|
||||
{
|
||||
typedef bool result_type;
|
||||
result_type operator() (geometry_container const& cont) const
|
||||
{
|
||||
for (auto const& geom : cont)
|
||||
{
|
||||
if (geom.size() > 0) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
#else
|
||||
struct get_type
|
||||
{
|
||||
|
@ -154,6 +168,27 @@ struct multi_geometry_type
|
|||
return boost::tuple<unsigned,bool>(type, collection);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct not_empty
|
||||
{
|
||||
template <typename T>
|
||||
struct result { typedef bool type; };
|
||||
|
||||
bool operator() (geometry_container const& cont) const
|
||||
{
|
||||
geometry_container::const_iterator itr = cont.begin();
|
||||
geometry_container::const_iterator end = cont.end();
|
||||
|
||||
for (; itr!=end; ++itr)
|
||||
{
|
||||
if (itr->size() > 0) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
@ -197,6 +232,7 @@ struct geometry_generator_grammar :
|
|||
: geometry_generator_grammar::base_type(coordinates)
|
||||
{
|
||||
using boost::spirit::karma::uint_;
|
||||
using boost::spirit::bool_;
|
||||
using boost::spirit::karma::_val;
|
||||
using boost::spirit::karma::_1;
|
||||
using boost::spirit::karma::lit;
|
||||
|
@ -226,7 +262,7 @@ struct geometry_generator_grammar :
|
|||
point_coord = &uint_
|
||||
<< lit('[')
|
||||
<< coord_type << lit(',') << coord_type
|
||||
<< lit("]")
|
||||
<< lit(']')
|
||||
;
|
||||
|
||||
polygon_coord %= ( &uint_(mapnik::SEG_MOVETO) << eps[_r1 += 1]
|
||||
|
@ -234,10 +270,7 @@ struct geometry_generator_grammar :
|
|||
.else_[_1 = '[' ]]
|
||||
|
|
||||
&uint_(mapnik::SEG_LINETO)
|
||||
<< lit(','))
|
||||
<< lit('[') << coord_type
|
||||
<< lit(',')
|
||||
<< coord_type << lit(']')
|
||||
<< lit(',')) << lit('[') << coord_type << lit(',') << coord_type << lit(']')
|
||||
;
|
||||
|
||||
coords2 %= *polygon_coord(_a)
|
||||
|
@ -252,7 +285,6 @@ struct geometry_generator_grammar :
|
|||
karma::rule<OutputIterator, geometry_type const& ()> point;
|
||||
karma::rule<OutputIterator, geometry_type const& ()> linestring;
|
||||
karma::rule<OutputIterator, geometry_type const& ()> polygon;
|
||||
|
||||
karma::rule<OutputIterator, geometry_type const& ()> coords;
|
||||
karma::rule<OutputIterator, karma::locals<unsigned>, geometry_type const& ()> coords2;
|
||||
karma::rule<OutputIterator, geometry_type::value_type ()> point_coord;
|
||||
|
@ -282,6 +314,7 @@ struct multi_geometry_generator_grammar :
|
|||
using boost::spirit::karma::_1;
|
||||
using boost::spirit::karma::_a;
|
||||
using boost::spirit::karma::_r1;
|
||||
using boost::spirit::bool_;
|
||||
|
||||
geometry_types.add
|
||||
(mapnik::Point,"\"Point\"")
|
||||
|
@ -292,7 +325,7 @@ struct multi_geometry_generator_grammar :
|
|||
(mapnik::Polygon + 3,"\"MultiPolygon\"")
|
||||
;
|
||||
|
||||
start %= ( eps(phoenix::at_c<1>(_a))[_a = _multi_type(_val)]
|
||||
start %= ( eps(phoenix::at_c<1>(_a))[_a = multi_type_(_val)]
|
||||
<< lit("{\"type\":\"GeometryCollection\",\"geometries\":[")
|
||||
<< geometry_collection << lit("]}")
|
||||
|
|
||||
|
@ -302,13 +335,13 @@ struct multi_geometry_generator_grammar :
|
|||
geometry_collection = -(geometry2 % lit(','))
|
||||
;
|
||||
|
||||
geometry = (lit("{\"type\":")
|
||||
<< geometry_types[_1 = phoenix::at_c<0>(_a)][_a = _multi_type(_val)]
|
||||
<< lit(",\"coordinates\":")
|
||||
<< karma::string[ phoenix::if_ (phoenix::at_c<0>(_a) > 3) [_1 = '['].else_[_1 = ""]]
|
||||
<< coordinates
|
||||
<< karma::string[ phoenix::if_ (phoenix::at_c<0>(_a) > 3) [_1 = ']'].else_[_1 = ""]]
|
||||
<< lit('}')) | lit("null")
|
||||
geometry = ( &bool_(true)[_1 = not_empty_(_val)] << lit("{\"type\":")
|
||||
<< geometry_types[_1 = phoenix::at_c<0>(_a)][_a = multi_type_(_val)]
|
||||
<< lit(",\"coordinates\":")
|
||||
<< karma::string[ phoenix::if_ (phoenix::at_c<0>(_a) > 3) [_1 = '['].else_[_1 = ""]]
|
||||
<< coordinates
|
||||
<< karma::string[ phoenix::if_ (phoenix::at_c<0>(_a) > 3) [_1 = ']'].else_[_1 = ""]]
|
||||
<< lit('}')) | lit("null")
|
||||
;
|
||||
|
||||
geometry2 = lit("{\"type\":")
|
||||
|
@ -334,8 +367,9 @@ struct multi_geometry_generator_grammar :
|
|||
karma::rule<OutputIterator, geometry_container const&()> coordinates;
|
||||
geometry_generator_grammar<OutputIterator> path;
|
||||
// phoenix
|
||||
phoenix::function<multi_geometry_type> _multi_type;
|
||||
phoenix::function<multi_geometry_type> multi_type_;
|
||||
phoenix::function<get_type > type_;
|
||||
phoenix::function<not_empty> not_empty_;
|
||||
// symbols table
|
||||
karma::symbols<unsigned, char const*> geometry_types;
|
||||
};
|
||||
|
|
|
@ -58,7 +58,10 @@ struct close_path
|
|||
result_type operator() (T path) const
|
||||
{
|
||||
BOOST_ASSERT( path!=0 );
|
||||
path->close_path();
|
||||
if (path->size() > 2u) // to form a polygon ring we need at least 3 vertices
|
||||
{
|
||||
path->close_path();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -114,8 +117,11 @@ struct close_path
|
|||
void operator() (T path) const
|
||||
{
|
||||
BOOST_ASSERT( path!=0 );
|
||||
path->close_path();
|
||||
}
|
||||
if (path->size() > 2u) // to form a polygon ring we need at least 3 vertices
|
||||
{
|
||||
path->close_path();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct cleanup
|
||||
|
|
|
@ -49,7 +49,7 @@ public:
|
|||
~geometry_parser();
|
||||
bool parse(iterator_type first, iterator_type last, boost::ptr_vector<mapnik::geometry_type>&);
|
||||
private:
|
||||
boost::scoped_ptr<geometry_grammar<iterator_type> > grammar_;
|
||||
const boost::scoped_ptr<geometry_grammar<iterator_type> > grammar_;
|
||||
};
|
||||
|
||||
}}
|
||||
|
|
|
@ -49,6 +49,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;
|
||||
|
@ -131,7 +132,8 @@ geojson_datasource::geojson_datasource(parameters const& params)
|
|||
boost::spirit::make_default_multi_pass(base_iterator_type());
|
||||
|
||||
mapnik::context_ptr ctx = boost::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
|
||||
value = object | array | string_
|
||||
| number
|
||||
json_.value = json_.object | json_.array | json_.string_
|
||||
| json_.number
|
||||
;
|
||||
|
||||
pairs = key_value % lit(',')
|
||||
json_.pairs = json_.key_value % lit(',')
|
||||
;
|
||||
|
||||
key_value = (string_ >> lit(':') >> value)
|
||||
json_.key_value = (json_.string_ >> lit(':') >> json_.value)
|
||||
;
|
||||
|
||||
object = lit('{')
|
||||
>> *pairs
|
||||
json_.object = lit('{')
|
||||
>> *json_.pairs
|
||||
>> lit('}')
|
||||
;
|
||||
array = lit('[')
|
||||
>> value >> *(lit(',') >> value)
|
||||
json_.array = lit('[')
|
||||
>> json_.value >> *(lit(',') >> json_.value)
|
||||
>> lit(']')
|
||||
;
|
||||
// https://github.com/mapnik/mapnik/issues/1342
|
||||
#if BOOST_VERSION >= 104700
|
||||
number %= strict_double
|
||||
json_.number %= json_.strict_double
|
||||
#else
|
||||
number = strict_double
|
||||
json_.number = json_.strict_double
|
||||
#endif
|
||||
| int__
|
||||
| json_.int__
|
||||
| lit("true") [_val = true]
|
||||
| lit ("false") [_val = false]
|
||||
| lit("null")[_val = construct<value_null>()]
|
||||
;
|
||||
|
||||
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
|
||||
string_ %= lit('"') >> no_skip[*(unesc_char | "\\u" >> hex4 | (char_ - lit('"')))] >> lit('"')
|
||||
json_.string_ %= lit('"') >> no_skip[*(json_.unesc_char | "\\u" >> json_.hex4 | (char_ - lit('"')))] >> lit('"')
|
||||
;
|
||||
#else
|
||||
string_ %= lit('"') >> lexeme[*(unesc_char | "\\u" >> 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) | 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 = (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 %= number | 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() {}
|
||||
|
|
|
@ -48,6 +48,19 @@ geojson = [
|
|||
[2,'{"type":"MultiPolygon","coordinates":[[[[-178.32319,71.518365],[-178.321586,71.518439],[-178.259635,71.510688],[-178.304862,71.513129],[-178.32319,71.518365]]],[[[-178.32319,71.518365],[-178.341544,71.517524],[-178.32244,71.505439],[-178.215323,71.478034],[-178.193473,71.47663],[-178.147757,71.485175],[-178.124442,71.481879],[-178.005729,71.448615],[-178.017203,71.441413],[-178.054191,71.428778],[-178.047049,71.425727],[-178.033439,71.417792],[-178.026236,71.415107],[-178.030082,71.413459],[-178.039908,71.40766],[-177.970878,71.39643],[-177.779837,71.333197],[-177.718375,71.305243],[-177.706412,71.3039],[-177.68212,71.304877],[-177.670279,71.301825],[-177.655387,71.293158],[-177.587577,71.285956],[-177.548575,71.294867],[-177.531119,71.296332],[-177.51409,71.293402],[-177.498649,71.284735],[-177.506217,71.268622],[-177.486991,71.258734],[-177.459708,71.249884],[-177.443412,71.237006],[-177.445914,71.222663],[-177.457755,71.209357],[-177.507804,71.173774],[-177.581168,71.147589],[-177.637626,71.117011],[-177.684134,71.110968],[-177.751883,71.092963],[-177.819266,71.084662],[-177.877677,71.052558],[-177.930472,71.041449],[-178.206595,71.038398],[-178.310111,71.013617],[-178.875907,70.981024],[-178.980277,70.95069],[-179.342093,70.908026],[-179.336234,70.911078],[-179.322257,70.921698],[-179.364493,70.930243],[-179.457511,70.915534],[-179.501212,70.919684],[-179.666007,70.965461],[-179.853385,70.979438],[-179.888785,70.993598],[-179.907523,70.996772],[-179.999989,70.992011],[-179.999989,71.024848],[-179.999989,71.058661],[-179.999989,71.126166],[-179.999989,71.187018],[-179.999989,71.224189],[-179.999989,71.27497],[-179.999989,71.312079],[-179.999989,71.356024],[-179.999989,71.410041],[-179.999989,71.487799],[-179.999989,71.536689],[-179.862845,71.538642],[-179.912223,71.555854],[-179.900748,71.558478],[-179.798819,71.569098],[-179.757438,71.583197],[-179.735953,71.586432],[-179.715445,71.583258],[-179.697501,71.577338],[-179.678702,71.573676],[-179.610831,71.585211],[-179.372062,71.569098],[-179.326774,71.555487],[-179.306815,71.557563],[-179.287162,71.562934],[-179.24285,71.569098],[-179.204642,71.583197],[-179.074576,71.600043],[-178.395438,71.539008],[-178.32319,71.518365]]]]}']
|
||||
]
|
||||
|
||||
geojson_nulls = [
|
||||
'{ "type": "Feature", "properties": { }, "geometry": null }',
|
||||
'{ "type": "Feature", "properties": { }, "geometry": { "type": "Point", "coordinates": [] }}',
|
||||
'{ "type": "Feature", "properties": { }, "geometry": { "type": "LineString", "coordinates": [ [] ] }}',
|
||||
'{ "type": "Feature", "properties": { }, "geometry": { "type": "Polygon", "coordinates": [ [ [] ] ] } }',
|
||||
'{ "type": "Feature", "properties": { }, "geometry": { "type": "MultiPoint", "coordinates": [ [] ] }}',
|
||||
'{ "type": "Feature", "properties": { }, "geometry": { "type": "MultiPoint", "coordinates": [ [],[] ] }}',
|
||||
'{ "type": "Feature", "properties": { }, "geometry": { "type": "MultiLineString", "coordinates": [ [] ] }}',
|
||||
'{ "type": "Feature", "properties": { }, "geometry": { "type": "MultiLineString", "coordinates": [ [ [] ] ] }}',
|
||||
'{ "type": "Feature", "properties": { }, "geometry": { "type": "MultiPolygon", "coordinates": [ [] ] }}',
|
||||
'{ "type": "Feature", "properties": { }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [] ] ] }}',
|
||||
'{ "type": "Feature", "properties": { }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [] ] ] ] }}',
|
||||
]
|
||||
|
||||
wkbs = [
|
||||
[ 0, "Point EMPTY", '010400000000000000'],
|
||||
|
@ -275,6 +288,16 @@ def test_creating_feature_from_geojson():
|
|||
eq_(feat.id(),1)
|
||||
eq_(feat['name'],u'value')
|
||||
|
||||
def test_handling_geojson_null_geoms():
|
||||
for json in geojson_nulls:
|
||||
ctx = mapnik.Context()
|
||||
out_json = mapnik.Feature.from_geojson(json,ctx).to_geojson()
|
||||
expected = '{"type":"Feature","id":1,"geometry":null,"properties":{}}'
|
||||
eq_(out_json,expected)
|
||||
# ensure it round trips
|
||||
eq_(mapnik.Feature.from_geojson(out_json,ctx).to_geojson(),expected)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
setup()
|
||||
run_all(eval(x) for x in dir() if x.startswith("test_"))
|
||||
|
|
Loading…
Add table
Reference in a new issue