From fe53ecc6d4626d44488943f7394720b0a185e324 Mon Sep 17 00:00:00 2001 From: Jan-Piet Mens Date: Wed, 16 Sep 2015 15:27:11 +0200 Subject: [PATCH] New XML in ocat --- README.md | 26 ++++++++++++++++ ocat.c | 91 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ storage.h | 1 + 3 files changed, 118 insertions(+) diff --git a/README.md b/README.md index 2647c2e..7132967 100644 --- a/README.md +++ b/README.md @@ -99,6 +99,32 @@ Some example uses we consider useful: print the LAST position of all users, devices. Can be combined with `--user` and `--device`. * `ocat ... --format csv` produces CSV. Limit the fields you want extracted with `--fields lat,lon,cc` for example. +* `ocat ... --format xml` + produces XML. Limit the fields you want extracted with `--fields lat,lon,cc` for example. +``` + + + + + 1440395361 + 3000.000000 + 51 + 10.027857 + 29.000000 + -1 + 52.378886 + -1 + NE + 96 + u1r1upq + DE + Heidecker Weg 86, 31275 Lehrte, Germany + 2015-08-24T05:55:07Z + 2015-08-24T05:49:21Z + + ... + +``` * `ocat ... --limit 10` prints data for the current month, starting now and going backwards; only 10 locations will be printed. Generally, the `--limit` option reads the storage back to front which makes no sense in some combinations. diff --git a/ocat.c b/ocat.c index 4d12fdd..cc73425 100644 --- a/ocat.c +++ b/ocat.c @@ -55,6 +55,44 @@ static void print_one(JsonNode *j, JsonNode *inttypes) } } +/* + * Print the value in a single JSON node as XML. If string, easy. If number account for + * what we call 'integer' types which shouldn't be printed as floats. + */ + +static void emit_one(JsonNode *j, JsonNode *inttypes) +{ + if (!strcmp(j->key, "_type")) + return; + + printf(" <%s>", j->key); + /* Check if the value should be an "integer" (ie not float) */ + if (j->tag == JSON_NUMBER) { + if (json_find_member(inttypes, j->key)) { + printf("%.lf", j->number_); + } else { + printf("%lf", j->number_); + } + } else if (j->tag == JSON_STRING) { + char *bp; + + for (bp = j->string_; bp && *bp; bp++) { + switch (*bp) { + case '&': printf("&"); break; + case '<': printf("<"); break; + case '>': printf(">"); break; + case '"': printf("""); break; + case '\'': printf("'"); break; + default: putc(*bp, stdout); break; + } + } + } else if (j->tag == JSON_BOOL) { + printf("%s", (j->bool_) ? "true" : "false"); + } else if (j->tag == JSON_NULL) { + printf("null"); + } + printf("\n", j->key); +} /* * Output location data as CSV. If `fields' is not NULL, it's a JSON * array of JSON elment names which should be printed instead of the @@ -116,6 +154,47 @@ void csv_output(JsonNode *json, output_type otype, JsonNode *fields) json_delete(inttypes); } + +void xml_output(JsonNode *json, output_type otype, JsonNode *fields) +{ + JsonNode *node, *inttypes; + JsonNode *arr, *one, *j; + + /* Prime the inttypes object with types we consider "integer" */ + inttypes = json_mkobject(); + json_append_member(inttypes, "batt", json_mkbool(1)); + json_append_member(inttypes, "vel", json_mkbool(1)); + json_append_member(inttypes, "cog", json_mkbool(1)); + json_append_member(inttypes, "tst", json_mkbool(1)); + json_append_member(inttypes, "alt", json_mkbool(1)); + json_append_member(inttypes, "dist", json_mkbool(1)); + json_append_member(inttypes, "trip", json_mkbool(1)); + + printf("\n\ + \n"); + printf("\n"); + + arr = json_find_member(json, "locations"); + json_foreach(one, arr) { + printf(" \n"); + if (fields) { + json_foreach(node, fields) { + if ((j = json_find_member(one, node->string_)) != NULL) { + emit_one(j, inttypes); + } + } + } else { + json_foreach(j, one) { + emit_one(j, inttypes); + } + } + printf(" \n\n"); + } + printf("\n"); + + json_delete(inttypes); +} + void usage(char *prog) { printf("Usage: %s [options..] [file ...]\n", prog); @@ -136,6 +215,7 @@ void usage(char *prog) printf(" geojson Geo-JSON points\n"); printf(" linestring Geo-JSON LineString\n"); printf(" gpx\n"); + printf(" xml\n"); printf(" raw\n"); printf(" payload Like RAW but JSON payload only\n"); printf(" --fields tst,lat,lon,... Choose fields for CSV. (dflt: ALL)\n"); @@ -303,6 +383,8 @@ int main(int argc, char **argv) otype = RAW; else if (!strcmp(optarg, "payload")) otype = RAWPAYLOAD; + else if (!strcmp(optarg, "xml")) + otype = XML; else if (!strcmp(optarg, "gpx")) otype = GPX; else if (!strcmp(optarg, "csv")) @@ -392,6 +474,13 @@ int main(int argc, char **argv) csv_output(o, CSV, fields); json_delete(o); + } else if (otype == XML) { + JsonNode *o = json_mkobject(); + + json_append_member(o, "locations", user_array); + xml_output(o, CSV, fields); + json_delete(o); + } else { fprintf(stderr, "%s: unsupported output type for LAST\n", progname); } @@ -503,6 +592,8 @@ int main(int argc, char **argv) } else if (otype == CSV) { csv_output(obj, CSV, fields); + } else if (otype == XML) { + xml_output(obj, XML, fields); } else if (otype == RAW || otype == RAWPAYLOAD) { /* We've already done what we need to do in locations() */ } else if (otype == LINESTRING) { diff --git a/storage.h b/storage.h index 15326ad..35c3131 100644 --- a/storage.h +++ b/storage.h @@ -15,6 +15,7 @@ typedef enum { GPX, RAWPAYLOAD, LINESTRING, + XML, } output_type; JsonNode *lister(char *username, char *device, time_t s_lo, time_t s_hi, int reverse);