Skip to content

Commit

Permalink
v.info: add JSON support (OSGeo#3755)
Browse files Browse the repository at this point in the history
Use parson to have JSON as an output format support. The module has various flags to control the fields being output in case of plain shell format controlled by flags. All (-get) of these are enabled when using format=shell. format=plain now allows use of flags. This may need special handling in the future to resolve the edge cases in a better way.
  • Loading branch information
kritibirda26 authored Jun 18, 2024
1 parent 04fd63c commit f3204e7
Show file tree
Hide file tree
Showing 8 changed files with 491 additions and 101 deletions.
4 changes: 3 additions & 1 deletion lib/gis/testsuite/test_parser_json.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,13 +97,15 @@ def test_v_info(self):
inputs = [
{"param": "map", "value": "hospitals@PERMANENT"},
{"param": "layer", "value": "1"},
{"param": "format", "value": "plain"},
]

stdout, stderr = subprocess.Popen(args, stdout=subprocess.PIPE).communicate()
print(stdout)
json_code = json.loads(decode(stdout))
print(json_code)
self.assertEqual(json_code["module"], "v.info")
self.assertEqual(len(json_code["inputs"]), 2)
self.assertEqual(len(json_code["inputs"]), 3)
self.assertEqual(json_code["inputs"], inputs)


Expand Down
2 changes: 1 addition & 1 deletion vector/v.info/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ MODULE_TOPDIR = ../..

PGM = v.info

LIBES = $(VECTORLIB) $(DIG2LIB) $(DBMILIB) $(GISLIB)
LIBES = $(VECTORLIB) $(DIG2LIB) $(DBMILIB) $(GISLIB) $(PARSONLIB)
DEPENDENCIES = $(VECTORDEP) $(DIG2DEP) $(DBMIDEP) $(GISDEP)
EXTRA_INC = $(VECT_INC)
EXTRA_CFLAGS = $(VECT_CFLAGS)
Expand Down
13 changes: 9 additions & 4 deletions vector/v.info/local_proto.h
Original file line number Diff line number Diff line change
@@ -1,20 +1,25 @@
#include <grass/vector.h>
#include <grass/parson.h>

#define SHELL_NO 0x00
#define SHELL_BASIC 0x02
#define SHELL_REGION 0x04
#define SHELL_TOPO 0x08

enum OutputFormat { PLAIN, SHELL, JSON };

/* level1.c */
int level_one_info(struct Map_info *);

/* parse.c */
void parse_args(int, char **, char **, char **, int *, int *, int *);
void parse_args(int, char **, char **, char **, int *, int *, int *,
enum OutputFormat *);

/* print.c */
void format_double(double, char *);
void print_region(struct Map_info *);
void print_topo(struct Map_info *);
void print_region(struct Map_info *, enum OutputFormat, JSON_Object *);
void print_topo(struct Map_info *, enum OutputFormat, JSON_Object *);
void print_columns(struct Map_info *, const char *, const char *);
void print_info(struct Map_info *);
void print_shell(struct Map_info *, const char *);
void print_shell(struct Map_info *, const char *, enum OutputFormat,
JSON_Object *);
36 changes: 28 additions & 8 deletions vector/v.info/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,11 @@ int main(int argc, char *argv[])
char *input_opt, *field_opt;
int hist_flag, col_flag, shell_flag;

enum OutputFormat format;

JSON_Value *root_value;
JSON_Object *root_object;

struct Map_info Map;

G_gisinit(argv[0]);
Expand All @@ -47,7 +52,12 @@ int main(int argc, char *argv[])
G_debug(1, "LFS is %s", sizeof(off_t) == 8 ? "available" : "not available");

parse_args(argc, argv, &input_opt, &field_opt, &hist_flag, &col_flag,
&shell_flag);
&shell_flag, &format);

if (format == JSON) {
root_value = json_value_init_object();
root_object = json_value_get_object(root_value);
}

/* try to open head-only on level 2 */
if (Vect_open_old_head2(&Map, input_opt, "", field_opt) < 2) {
Expand Down Expand Up @@ -82,19 +92,29 @@ int main(int argc, char *argv[])
return (EXIT_SUCCESS);
}

if (shell_flag & SHELL_BASIC) {
print_shell(&Map, field_opt);
if ((shell_flag & SHELL_BASIC) || format == JSON) {
print_shell(&Map, field_opt, format, root_object);
}
if (shell_flag & SHELL_REGION) {
print_region(&Map);
if ((shell_flag & SHELL_REGION) || format == JSON) {
print_region(&Map, format, root_object);
}
if (shell_flag & SHELL_TOPO) {
print_topo(&Map);
if ((shell_flag & SHELL_TOPO) || format == JSON) {
print_topo(&Map, format, root_object);
}
if (shell_flag == 0) {
if (shell_flag == 0 && format == PLAIN) {
print_info(&Map);
}

if (format == JSON) {
char *serialized_string = json_serialize_to_string_pretty(root_value);
if (serialized_string == NULL) {
G_fatal_error(_("Failed to initialize pretty JSON string."));
}
puts(serialized_string);
json_free_serialized_string(serialized_string);
json_value_free(root_value);
}

Vect_close(&Map);

return (EXIT_SUCCESS);
Expand Down
34 changes: 32 additions & 2 deletions vector/v.info/parse.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@
#include "local_proto.h"

void parse_args(int argc, char **argv, char **input, char **field, int *history,
int *columns, int *shell)
int *columns, int *shell, enum OutputFormat *format_ptr)
{
struct Option *input_opt, *field_opt;
struct Option *input_opt, *field_opt, *format_opt;
struct Flag *hist_flag, *col_flag, *shell_flag, *region_flag, *topo_flag;

input_opt = G_define_standard_option(G_OPT_V_MAP);
Expand Down Expand Up @@ -42,6 +42,13 @@ void parse_args(int argc, char **argv, char **input, char **field, int *history,
topo_flag->description = _("Print topology info in shell script style");
topo_flag->guisection = _("Print");

format_opt = G_define_standard_option(G_OPT_F_FORMAT);
format_opt->options = "plain,shell,json";
format_opt->descriptions = _("plain;Human readable text output;"
"shell;shell script style text output;"
"json;JSON (JavaScript Object Notation);");
format_opt->guisection = _("Print");

if (G_parser(argc, argv))
exit(EXIT_FAILURE);

Expand All @@ -56,4 +63,27 @@ void parse_args(int argc, char **argv, char **input, char **field, int *history,
*shell |= SHELL_REGION;
if (topo_flag->answer)
*shell |= SHELL_TOPO;

if (strcmp(format_opt->answer, "plain") == 0) {
// if shell flags are specified and format=PLAIN (default),
// print in shell script format
if (*shell != 0) {
*format_ptr = SHELL;
}
else {
*format_ptr = PLAIN;
}
}
else if (strcmp(format_opt->answer, "json") == 0)
*format_ptr = JSON;
else {
*format_ptr = SHELL;
// if shell flags are specified with format=shell, obey them
// if only format=shell is specified, print all info
if (*shell == 0) {
*shell |= SHELL_BASIC;
*shell |= SHELL_REGION;
*shell |= SHELL_TOPO;
}
}
}
Loading

0 comments on commit f3204e7

Please sign in to comment.