diff --git a/README.md b/README.md index bdae33e8..82c2c9a0 100644 --- a/README.md +++ b/README.md @@ -148,6 +148,11 @@ If your input is formatted as newline-delimited GeoJSON, use `-P` to make input * `-l` _name_ or `--layer=`_name_: Use the specified layer name instead of deriving a name from the input filename or output tileset. If there are multiple input files specified, the files are all merged into the single named layer, even if they try to specify individual names with `-L`. * `-L` _name_`:`_file.json_ or `--named-layer=`_name_`:`_file.json_: Specify layer names for individual files. If your shell supports it, you can use a subshell redirect like `-L` _name_`:<(cat dir/*.json)` to specify a layer name for the output of streamed input. + * `-L{`_layer-json_`}` or `--named-layer={`_layer-json_`}`: Specify an input file and layer options by a JSON object. The JSON object must contain a `"file"` key to specify the filename to read from. It may also contain a `"layer"` field to specify the name of the layer, and/or a `"description"` field to specify the layer's description in the tileset metadata. Example: + +``` +tippecanoe -z5 -o world.mbtiles -L'{"file":"ne_10m_admin_0_countries.json", "layer":"countries", "description":"Natural Earth countries"}' +``` CSV input files currently support only Point geometries, from columns named `latitude`, `longitude`, `lat`, `lon`, `long`, `lng`, `x`, or `y`. diff --git a/main.cpp b/main.cpp index 8a1eed7b..6816dca5 100644 --- a/main.cpp +++ b/main.cpp @@ -2374,6 +2374,42 @@ void set_attribute_accum(std::map &attribute_accum, c attribute_accum.insert(std::pair(name, t)); } +void parse_json_source(const char *arg, struct source &src) { + json_pull *jp = json_begin_string(arg); + json_object *o = json_read_tree(jp); + + if (o == NULL) { + fprintf(stderr, "%s: -L%s: %s\n", *av, arg, jp->error); + exit(EXIT_FAILURE); + } + + if (o->type != JSON_HASH) { + fprintf(stderr, "%s: -L%s: not a JSON object\n", *av, arg); + exit(EXIT_FAILURE); + } + + json_object *fname = json_hash_get(o, "file"); + if (fname == NULL || fname->type != JSON_STRING) { + fprintf(stderr, "%s: -L%s: requires \"file\": filename\n", *av, arg); + exit(EXIT_FAILURE); + } + + src.file = std::string(fname->string); + + json_object *layer = json_hash_get(o, "layer"); + if (layer != NULL && layer->type == JSON_STRING) { + src.layer = std::string(layer->string); + } + + json_object *description = json_hash_get(o, "description"); + if (description != NULL && description->type == JSON_STRING) { + src.description = std::string(description->string); + } + + json_free(o); + json_end(jp); +} + int main(int argc, char **argv) { #ifdef MTRACE mtrace(); @@ -2607,14 +2643,18 @@ int main(int argc, char **argv) { break; case 'L': { - char *cp = strchr(optarg, ':'); - if (cp == NULL || cp == optarg) { - fprintf(stderr, "%s: -L requires layername:file\n", argv[0]); - exit(EXIT_FAILURE); - } struct source src; - src.layer = std::string(optarg).substr(0, cp - optarg); - src.file = std::string(cp + 1); + if (optarg[0] == '{') { + parse_json_source(optarg, src); + } else { + char *cp = strchr(optarg, ':'); + if (cp == NULL || cp == optarg) { + fprintf(stderr, "%s: -L requires layername:file\n", argv[0]); + exit(EXIT_FAILURE); + } + src.layer = std::string(optarg).substr(0, cp - optarg); + src.file = std::string(cp + 1); + } sources.push_back(src); break; } diff --git a/man/tippecanoe.1 b/man/tippecanoe.1 index 25404ee8..cb2ac244 100644 --- a/man/tippecanoe.1 +++ b/man/tippecanoe.1 @@ -159,6 +159,14 @@ or if metadata fields can't be set. You probably don't want to use this. specified, the files are all merged into the single named layer, even if they try to specify individual names with \fB\fC\-L\fR\&. .IP \(bu 2 \fB\fC\-L\fR \fIname\fP\fB\fC:\fR\fIfile.json\fP or \fB\fC\-\-named\-layer=\fR\fIname\fP\fB\fC:\fR\fIfile.json\fP: Specify layer names for individual files. If your shell supports it, you can use a subshell redirect like \fB\fC\-L\fR \fIname\fP\fB\fC:<(cat dir/*.json)\fR to specify a layer name for the output of streamed input. +.IP \(bu 2 +\fB\fC\-L{\fR\fIlayer\-json\fP\fB\fC}\fR or \fB\fC\-\-named\-layer={\fR\fIlayer\-json\fP\fB\fC}\fR: Specify an input file and layer options by a JSON object. The JSON object must contain a \fB\fC"file"\fR key to specify the filename to read from. It may also contain a \fB\fC"layer"\fR field to specify the name of the layer, and/or a \fB\fC"description"\fR field to specify the layer's description in the tileset metadata. Example: +.RE +.PP +.RS +.nf +tippecanoe \-z5 \-o world.mbtiles \-L'{"file":"ne_10m_admin_0_countries.json", "layer":"countries", "description":"Natural Earth countries"}' +.fi .RE .PP CSV input files currently support only Point geometries, from columns named \fB\fClatitude\fR, \fB\fClongitude\fR, \fB\fClat\fR, \fB\fClon\fR, \fB\fClong\fR, \fB\fClng\fR, \fB\fCx\fR, or \fB\fCy\fR\&.