support for inline topojson (in memory string) - closes #2058

This commit is contained in:
Dane Springmeyer 2014-07-28 19:26:35 -07:00
parent 9f9f981731
commit 914b4c2e8b
3 changed files with 58 additions and 16 deletions

View file

@ -146,33 +146,55 @@ topojson_datasource::topojson_datasource(parameters const& params)
type_(datasource::Vector), type_(datasource::Vector),
desc_(topojson_datasource::name(), desc_(topojson_datasource::name(),
*params.get<std::string>("encoding","utf-8")), *params.get<std::string>("encoding","utf-8")),
file_(*params.get<std::string>("file","")), filename_(),
inline_string_(),
extent_(), extent_(),
tr_(new mapnik::transcoder(*params.get<std::string>("encoding","utf-8"))), tr_(new mapnik::transcoder(*params.get<std::string>("encoding","utf-8"))),
tree_(16,1) tree_(16,1)
{ {
if (file_.empty()) throw mapnik::datasource_exception("TopoJSON Plugin: missing <file> parameter"); boost::optional<std::string> inline_string = params.get<std::string>("inline");
if (inline_string)
{
inline_string_ = *inline_string;
}
else
{
boost::optional<std::string> file = params.get<std::string>("file");
if (!file) throw mapnik::datasource_exception("TopoJSON Plugin: missing <file> parameter");
boost::optional<std::string> base = params.get<std::string>("base"); boost::optional<std::string> base = params.get<std::string>("base");
if (base) if (base)
{ filename_ = *base + "/" + *file;
file_ = *base + "/" + file_; else
filename_ = *file;
} }
if (!inline_string_.empty())
using base_iterator_type = std::istreambuf_iterator<char>; {
std::istringstream in(inline_string_);
parse_topojson(in);
}
else
{
#if defined (_WINDOWS) #if defined (_WINDOWS)
std::ifstream is(mapnik::utf8_to_utf16(file_),std::ios_base::in | std::ios_base::binary); std::ifstream in(mapnik::utf8_to_utf16(filename_),std::ios_base::in | std::ios_base::binary);
#else #else
std::ifstream is(file_.c_str(),std::ios_base::in | std::ios_base::binary); std::ifstream in(filename_.c_str(),std::ios_base::in | std::ios_base::binary);
#endif #endif
if (!is.is_open()) if (!in.is_open())
{ {
throw mapnik::datasource_exception("TopoJSON Plugin: could not open: '" + file_ + "'"); throw mapnik::datasource_exception("TopoJSON Plugin: could not open: '" + filename_ + "'");
} }
parse_topojson(in);
in.close();
}
}
template <typename T>
void topojson_datasource::parse_topojson(T & stream)
{
using base_iterator_type = std::istreambuf_iterator<char>;
boost::spirit::multi_pass<base_iterator_type> begin = boost::spirit::multi_pass<base_iterator_type> begin =
boost::spirit::make_default_multi_pass(base_iterator_type(is)); boost::spirit::make_default_multi_pass(base_iterator_type(stream));
boost::spirit::multi_pass<base_iterator_type> end = boost::spirit::multi_pass<base_iterator_type> end =
boost::spirit::make_default_multi_pass(base_iterator_type()); boost::spirit::make_default_multi_pass(base_iterator_type());
@ -182,7 +204,7 @@ topojson_datasource::topojson_datasource(parameters const& params)
bool result = boost::spirit::qi::phrase_parse(begin, end, g, space, topo_); bool result = boost::spirit::qi::phrase_parse(begin, end, g, space, topo_);
if (!result) if (!result)
{ {
throw mapnik::datasource_exception("topojson_datasource: Failed parse TopoJSON file '" + file_ + "'"); throw mapnik::datasource_exception("topojson_datasource: Failed parse TopoJSON file '" + filename_ + "'");
} }
std::size_t count = 0; std::size_t count = 0;

View file

@ -65,11 +65,14 @@ public:
mapnik::box2d<double> envelope() const; mapnik::box2d<double> envelope() const;
mapnik::layer_descriptor get_descriptor() const; mapnik::layer_descriptor get_descriptor() const;
boost::optional<mapnik::datasource::geometry_t> get_geometry_type() const; boost::optional<mapnik::datasource::geometry_t> get_geometry_type() const;
template <typename T>
void parse_topojson(T & stream);
private: private:
mapnik::datasource::datasource_t type_; mapnik::datasource::datasource_t type_;
std::map<std::string, mapnik::parameters> statistics_; std::map<std::string, mapnik::parameters> statistics_;
mapnik::layer_descriptor desc_; mapnik::layer_descriptor desc_;
std::string file_; std::string filename_;
std::string inline_string_;
mapnik::box2d<double> extent_; mapnik::box2d<double> extent_;
std::shared_ptr<mapnik::transcoder> tr_; std::shared_ptr<mapnik::transcoder> tr_;
mapnik::topojson::topology topo_; mapnik::topojson::topology topo_;

View file

@ -54,6 +54,23 @@ if 'topojson' in mapnik.DatasourceCache.plugin_names():
eq_(f['NOM_FR'], u'Qu\xe9bec') eq_(f['NOM_FR'], u'Qu\xe9bec')
eq_(f['NOM_FR'], u'Québec') eq_(f['NOM_FR'], u'Québec')
def test_geojson_from_in_memory_string():
ds = mapnik.Datasource(type='topojson',inline=open('../data/json/escaped.topojson','r').read())
f = ds.all_features()[0]
eq_(len(ds.fields()),7)
desc = ds.describe()
eq_(desc['geometry_type'],mapnik.DataGeometryType.Point)
eq_(f['name'], u'Test')
eq_(f['int'], 1)
eq_(f['description'], u'Test: \u005C')
eq_(f['spaces'], u'this has spaces')
eq_(f['double'], 1.1)
eq_(f['boolean'], True)
eq_(f['NOM_FR'], u'Qu\xe9bec')
eq_(f['NOM_FR'], u'Québec')
# @raises(RuntimeError) # @raises(RuntimeError)
def test_that_nonexistant_query_field_throws(**kwargs): def test_that_nonexistant_query_field_throws(**kwargs):
ds = mapnik.Datasource(type='topojson',file='../data/json/escaped.topojson') ds = mapnik.Datasource(type='topojson',file='../data/json/escaped.topojson')