Skip to content

Commit

Permalink
r.category: add JSON support (#4018)
Browse files Browse the repository at this point in the history
* r.category: add JSON support

* add test and docs

* address PR feedback
  • Loading branch information
kritibirda26 committed Jul 19, 2024
1 parent 456546a commit c1f55e3
Show file tree
Hide file tree
Showing 5 changed files with 126 additions and 13 deletions.
2 changes: 1 addition & 1 deletion raster/r.category/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ MODULE_TOPDIR = ../..

PGM = r.category

LIBES = $(RASTERLIB) $(GISLIB)
LIBES = $(RASTERLIB) $(GISLIB) $(PARSONLIB)
DEPENDENCIES = $(RASTERDEP) $(GISDEP)

include $(MODULE_TOPDIR)/include/Make/Module.make
Expand Down
9 changes: 7 additions & 2 deletions raster/r.category/local_proto.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,18 @@
#ifndef __LOCAL_PROTO_H__
#define __LOCAL_PROTO_H__

#include <grass/parson.h>

enum OutputFormat { PLAIN, JSON };

/* cats.c */
int get_cats(const char *, const char *);
int next_cat(long *);

/* main.c */
int print_label(long);
int print_d_label(double);
void print_json(JSON_Value *);
int print_label(long, enum OutputFormat, JSON_Array *);
int print_d_label(double, enum OutputFormat, JSON_Array *);
int scan_cats(const char *, long *, long *);
int scan_vals(const char *, double *);

Expand Down
92 changes: 82 additions & 10 deletions raster/r.category/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include <grass/gis.h>
#include <grass/raster.h>
#include <grass/glocale.h>
#include <grass/parson.h>
#include "local_proto.h"

static struct Categories cats;
Expand All @@ -39,9 +40,13 @@ int main(int argc, char *argv[])
int from_stdin = FALSE;
struct GModule *module;

enum OutputFormat format;
JSON_Value *root_value;
JSON_Array *root_array;

struct {
struct Option *map, *fs, *cats, *vals, *raster, *file, *fmt_str,
*fmt_coeff;
*fmt_coeff, *format;
} parm;

G_gisinit(argv[0]);
Expand Down Expand Up @@ -103,9 +108,25 @@ int main(int argc, char *argv[])
parm.fmt_coeff->description =
_("Two pairs of category multiplier and offsets, for $1 and $2");

parm.format = G_define_standard_option(G_OPT_F_FORMAT);
parm.format->key = "output_format";
parm.format->guisection = _("Print");

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

if (strcmp(parm.format->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 {
format = PLAIN;
}

name = parm.map->answer;

fs = G_option_to_separator(parm.fs);
Expand Down Expand Up @@ -282,7 +303,10 @@ int main(int argc, char *argv[])
if (map_type == CELL_TYPE) {
get_cats(name, mapset);
while (next_cat(&x))
print_label(x);
print_label(x, format, root_array);
if (format == JSON) {
print_json(root_value);
}
exit(EXIT_SUCCESS);
}
}
Expand All @@ -300,7 +324,10 @@ int main(int argc, char *argv[])
for (i = 0; parm.cats->answers[i]; i++) {
scan_cats(parm.cats->answers[i], &x, &y);
while (x <= y)
print_label(x++);
print_label(x++, format, root_array);
}
if (format == JSON) {
print_json(root_value);
}
exit(EXIT_SUCCESS);
}
Expand All @@ -315,31 +342,76 @@ int main(int argc, char *argv[])
}
for (i = 0; parm.vals->answers[i]; i++) {
scan_vals(parm.vals->answers[i], &dx);
print_d_label(dx);
print_d_label(dx, format, root_array);
}

if (format == JSON) {
print_json(root_value);
}

exit(EXIT_SUCCESS);
}

int print_label(long x)
void print_json(JSON_Value *root_value)
{
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);
}

int print_label(long x, enum OutputFormat format, JSON_Array *root_array)
{
char *label;
JSON_Value *category_value;
JSON_Object *category;

G_squeeze(label = Rast_get_c_cat((CELL *)&x, &cats));
fprintf(stdout, "%ld%s%s\n", x, fs, label);

switch (format) {
case PLAIN:
fprintf(stdout, "%ld%s%s\n", x, fs, label);
break;
case JSON:
category_value = json_value_init_object();
category = json_object(category_value);
json_object_set_number(category, "category", x);
json_object_set_string(category, "description", label);
json_array_append_value(root_array, category_value);
break;
}

return 0;
}

int print_d_label(double x)
int print_d_label(double x, enum OutputFormat format, JSON_Array *root_array)
{
char *label, tmp[40];
DCELL dtmp;
JSON_Value *category_value;
JSON_Object *category;

dtmp = x;
G_squeeze(label = Rast_get_d_cat(&dtmp, &cats));
sprintf(tmp, "%.10f", x);
G_trim_decimal(tmp);
fprintf(stdout, "%s%s%s\n", tmp, fs, label);

switch (format) {
case PLAIN:
sprintf(tmp, "%.10f", x);
G_trim_decimal(tmp);
fprintf(stdout, "%s%s%s\n", tmp, fs, label);
break;
case JSON:
category_value = json_value_init_object();
category = json_object(category_value);
json_object_set_number(category, "category", x);
json_object_set_string(category, "description", label);
json_array_append_value(root_array, category_value);
break;
}

return 0;
}
Expand Down
20 changes: 20 additions & 0 deletions raster/r.category/r.category.html
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,26 @@ <h3>Printing categories</h3>
as the character separating the category values from the category
values in the output.

<p>
<div class="code"><pre>
r.category map=landclass96 cats=3,4 output_format=json
</pre></div>

generates the following JSON output:

<div class="code"><pre>
[
{
"category": 3,
"description": "herbaceous"
},
{
"category": 4,
"description": "shrubland"
}
]
</pre></div>

<h3>Adding categories</h3>

Example for defining new category labels, using a colon as separator:
Expand Down
16 changes: 16 additions & 0 deletions raster/r.category/test_rcategory_doctest.txt
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,22 @@ Some of these commands should not work and return 1.
<BLANKLINE>


JSON Output
===========
>>> print(read_command('r.category', map='test', output_format='json'))
[
{
"category": 1,
"description": "trees, very green"
},
{
"category": 2,
"description": "water, very deep"
}
]
<BLANKLINE>


Clean the results
=================

Expand Down

0 comments on commit c1f55e3

Please sign in to comment.