From 2a1e5c6e61a57ad855afb04c1bb6b24e8ee091a5 Mon Sep 17 00:00:00 2001 From: Kriti Birda Date: Wed, 10 Jul 2024 22:40:49 +0530 Subject: [PATCH] v.category: add json support --- vector/v.category/Makefile | 2 +- vector/v.category/main.c | 75 ++++++++++++++++++- .../v.category/testsuite/test_v_category.py | 23 ++++++ vector/v.category/v.category.html | 24 ++++++ 4 files changed, 119 insertions(+), 5 deletions(-) create mode 100644 vector/v.category/testsuite/test_v_category.py diff --git a/vector/v.category/Makefile b/vector/v.category/Makefile index 174dc96a90d..271f5166995 100644 --- a/vector/v.category/Makefile +++ b/vector/v.category/Makefile @@ -3,7 +3,7 @@ MODULE_TOPDIR = ../.. PGM = v.category -LIBES = $(VECTORLIB) $(GISLIB) +LIBES = $(VECTORLIB) $(GISLIB) $(PARSONLIB) DEPENDENCIES = $(VECTORDEP) $(GISDEP) EXTRA_INC = $(VECT_INC) EXTRA_CFLAGS = $(VECT_CFLAGS) diff --git a/vector/v.category/main.c b/vector/v.category/main.c index 3e280a4464e..66b1a93890c 100644 --- a/vector/v.category/main.c +++ b/vector/v.category/main.c @@ -20,6 +20,7 @@ #include #include #include +#include #define O_ADD 1 #define O_DEL 2 @@ -50,6 +51,25 @@ typedef struct { int min[FRTYPES], max[FRTYPES]; } FREPORT; +enum OutputFormat { PLAIN, SHELL, JSON }; + +void format_json_fr(FREPORT *freport, int fr_type, char *name, + JSON_Array *array) +{ + JSON_Object *object; + JSON_Value *value; + if (freport->count[fr_type] > 0) { + value = json_value_init_object(); + object = json_object(value); + json_object_set_string(object, "type", name); + json_object_set_number(object, "field", freport->field); + json_object_set_number(object, "count", freport->count[fr_type]); + json_object_set_number(object, "min", freport->min[fr_type]); + json_object_set_number(object, "max", freport->max[fr_type]); + json_array_append_value(array, value); + } +} + int main(int argc, char *argv[]) { struct Map_info In, Out; @@ -64,12 +84,16 @@ int main(int argc, char *argv[]) int cat, ocat, scat, *fields, nfields, field; struct GModule *module; struct Option *in_opt, *out_opt, *option_opt, *type_opt; - struct Option *cat_opt, *field_opt, *step_opt, *id_opt; + struct Option *cat_opt, *field_opt, *step_opt, *id_opt, *format_opt; struct Flag *shell, *notab; FREPORT **freps; int nfreps, rtype, fld; char *desc; + enum OutputFormat format; + JSON_Array *root_array; + JSON_Value *root_value; + module = G_define_module(); G_add_keyword(_("vector")); G_add_keyword(_("category")); @@ -137,6 +161,13 @@ int main(int argc, char *argv[]) step_opt->answer = "1"; step_opt->description = _("Category increment"); + 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"); + shell = G_define_flag(); shell->key = 'g'; shell->label = _("Shell script style, currently only for report"); @@ -231,6 +262,21 @@ int main(int argc, char *argv[]) Clist = NULL; } + if (strcmp(format_opt->answer, "json") == 0) { + format = JSON; + root_value = json_value_init_array(); + if (root_value == NULL) { + G_fatal_error(_("Failed to initialize JSON array. Out of memory?")); + } + root_array = json_array(root_value); + } + else if ((strcmp(format_opt->answer, "shell") == 0) || shell->answer) { + format = SHELL; + } + else { + format = PLAIN; + } + if ((option != O_REP) && (option != O_PRN) && (option != O_LYR)) { if (out_opt->answer == NULL) G_fatal_error(_("Output vector wasn't entered")); @@ -627,7 +673,8 @@ int main(int argc, char *argv[]) } } for (i = 0; i < nfreps; i++) { - if (shell->answer) { + switch (format) { + case SHELL: if (freps[i]->count[FR_POINT] > 0) fprintf(stdout, "%d point %d %d %d\n", freps[i]->field, freps[i]->count[FR_POINT], @@ -690,8 +737,8 @@ int main(int argc, char *argv[]) freps[i]->count[FR_ALL], (freps[i]->min[FR_ALL] < 0 ? 0 : freps[i]->min[FR_ALL]), freps[i]->max[FR_ALL]); - } - else { + break; + case PLAIN: if (freps[i]->table != NULL) { fprintf(stdout, "%s: %d/%s\n", _("Layer/table"), freps[i]->field, freps[i]->table); @@ -742,7 +789,27 @@ int main(int argc, char *argv[]) freps[i]->count[FR_ALL], (freps[i]->min[FR_ALL] < 0) ? 0 : freps[i]->min[FR_ALL], freps[i]->max[FR_ALL]); + break; + case JSON: + format_json_fr(freps[i], FR_POINT, "point", root_array); + format_json_fr(freps[i], FR_LINE, "line", root_array); + format_json_fr(freps[i], FR_BOUNDARY, "boundary", root_array); + format_json_fr(freps[i], FR_CENTROID, "centroid", root_array); + format_json_fr(freps[i], FR_AREA, "area", root_array); + format_json_fr(freps[i], FR_FACE, "face", root_array); + format_json_fr(freps[i], FR_ALL, "all", root_array); + break; + } + } + if (format == JSON) { + char *serialized_string = NULL; + 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); } break; diff --git a/vector/v.category/testsuite/test_v_category.py b/vector/v.category/testsuite/test_v_category.py new file mode 100644 index 00000000000..3236cd9e3d6 --- /dev/null +++ b/vector/v.category/testsuite/test_v_category.py @@ -0,0 +1,23 @@ +import json + +from grass.gunittest.case import TestCase +from grass.gunittest.gmodules import call_module + + +class TestVCategory(TestCase): + + def test_d_flag(self): + expected = [ + {"type": "point", "field": 1, "count": 10938, "min": 1, "max": 10938}, + {"type": "all", "field": 1, "count": 10938, "min": 1, "max": 10938}, + ] + output = call_module( + "v.category", input="bridges", option="report", format="json" + ) + self.assertListEqual(expected, json.loads(output)) + + +if __name__ == "__main__": + from grass.gunittest.main import test + + test() diff --git a/vector/v.category/v.category.html b/vector/v.category/v.category.html index 1f5f0de2e3e..fbe2ea08928 100644 --- a/vector/v.category/v.category.html +++ b/vector/v.category/v.category.html @@ -80,6 +80,30 @@

Report vector categories

all 1379 1 1379 +

Report in JSON format

+
+v.category input=testmap option=report format=json
+
+ +
+[
+    {
+        "type": "line",
+        "field": 1,
+        "count": 1379,
+        "min": 1,
+        "max": 1379
+    },
+    {
+        "type": "all",
+        "field": 1,
+        "count": 1379,
+        "min": 1,
+        "max": 1379
+    }
+]
+
+

Delete all vector categories in layer 1