blob: 1cd69c23571817d57dcf165a4726ecaa6a667e03 [file] [log] [blame]
Radek Krejci94ca54b2015-07-08 15:48:47 +02001/**
2 * @file printer/json.c
3 * @author Radek Krejci <rkrejci@cesnet.cz>
4 * @brief JSON printer for libyang data structure
5 *
6 * Copyright (c) 2015 CESNET, z.s.p.o.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
16 * distribution.
17 * 3. Neither the name of the Company nor the names of its contributors
18 * may be used to endorse or promote products derived from this
19 * software without specific prior written permission.
20 */
21
22#include <stdlib.h>
23#include <stdio.h>
24#include <string.h>
25#include <assert.h>
Radek Krejci7511f402015-07-10 09:56:30 +020026#include <inttypes.h>
Radek Krejci94ca54b2015-07-08 15:48:47 +020027
28#include "../common.h"
Michal Vaskoab8e4402015-07-17 12:54:28 +020029#include "../xml.h"
Radek Krejci94ca54b2015-07-08 15:48:47 +020030#include "../tree.h"
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +020031#include "../resolve.h"
Michal Vaskoc82396e2015-07-17 15:31:25 +020032#include "../tree_internal.h"
Radek Krejci94ca54b2015-07-08 15:48:47 +020033
34#define INDENT ""
35#define LEVEL (level*2)
36
37void json_print_node(FILE *f, int level, struct lyd_node *node);
38
39/* 0 - same, 1 - different */
40static int
41nscmp(struct lyd_node *node1, struct lyd_node *node2)
42{
Radek Krejcib8048692015-08-05 13:36:34 +020043 struct lys_module *m1, *m2;
Radek Krejci94ca54b2015-07-08 15:48:47 +020044
45 /* we have to cover submodules belonging to the same module */
46 if (node1->schema->module->type) {
Radek Krejcib8048692015-08-05 13:36:34 +020047 m1 = ((struct lys_submodule *)node1->schema->module)->belongsto;
Radek Krejci94ca54b2015-07-08 15:48:47 +020048 } else {
49 m1 = node1->schema->module;
50 }
51 if (node2->schema->module->type) {
Radek Krejcib8048692015-08-05 13:36:34 +020052 m2 = ((struct lys_submodule *)node2->schema->module)->belongsto;
Radek Krejci94ca54b2015-07-08 15:48:47 +020053 } else {
54 m2 = node2->schema->module;
55 }
56 if (m1 == m2) {
57 /* belongs to the same module */
58 return 0;
59 } else {
60 /* different modules */
61 return 1;
62 }
63}
64
65static void
Michal Vaskoc82396e2015-07-17 15:31:25 +020066json_print_text_dquote(FILE *f, const char *str, int str_len)
67{
68 const char *ptr;
69
70 while ((ptr = strnchr(str, '\"', str_len))) {
71 fprintf(f, "%.*s\\\"", (int)(ptr-str), str);
72 str_len -= (ptr-str)+1;
73 str = ptr+1;
74 }
75
76 fprintf(f, "%.*s", str_len, str);
77}
78
79static void
80json_print_instid(FILE *f, struct lyd_node_leaf *leaf)
81{
82 const char *ptr, *print_ptr;
83 int cur_id_len, print_id_len;
Michal Vaskof02e3742015-08-05 16:27:02 +020084 struct unres_data *nodes, unres;
Radek Krejcib8048692015-08-05 13:36:34 +020085 struct lys_module *prev_module = NULL, *cur_module;
Radek Krejci76512572015-08-04 09:47:08 +020086 struct lys_node *snode;
Michal Vaskoc82396e2015-07-17 15:31:25 +020087
Radek Krejcib8048692015-08-05 13:36:34 +020088 assert(((struct lys_node_leaf *)leaf->schema)->type.base == LY_TYPE_INST);
Michal Vaskoc82396e2015-07-17 15:31:25 +020089
90 fputc('\"', f);
91 print_ptr = ptr = leaf->value_str+1;
92
93 while (print_ptr[0]) {
94 fputc('/', f);
95
96 /* check namespaces */
97 ptr = strchr(ptr, '/');
98 if (ptr) {
99 cur_id_len = ptr - leaf->value_str;
100 } else {
101 cur_id_len = strlen(leaf->value_str);
102 }
103
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +0200104 memset(&unres, 0, sizeof unres);
105 unres.dnode = (struct lyd_node *)leaf;
106 resolve_instid(&unres, leaf->value_str, cur_id_len, &nodes);
Michal Vaskoc82396e2015-07-17 15:31:25 +0200107 assert(nodes && !nodes->next);
108
Radek Krejci76512572015-08-04 09:47:08 +0200109 snode = (struct lys_node *)nodes->dnode->schema;
Michal Vaskoc82396e2015-07-17 15:31:25 +0200110 free(nodes);
111
112 /* find current module */
113 if (snode->module->type) {
Radek Krejcib8048692015-08-05 13:36:34 +0200114 cur_module = ((struct lys_submodule *)snode->module)->belongsto;
Michal Vaskoc82396e2015-07-17 15:31:25 +0200115 } else {
116 cur_module = snode->module;
117 }
118
119 if (!prev_module || (cur_module != prev_module)) {
120 fprintf(f, "%s:", cur_module->ns);
121 prev_module = cur_module;
122 }
123
124 ptr = strchr(print_ptr+1, '/');
125 if (ptr) {
126 print_id_len = ptr - print_ptr;
127 } else {
128 print_id_len = strlen(print_ptr);
129 }
130
131 json_print_text_dquote(f, print_ptr, print_id_len);
132 print_ptr += print_id_len+1;
133 }
134
135 fprintf(f, "\"");
136}
137
138static void
Radek Krejci5a988152015-07-15 11:16:26 +0200139json_print_leaf(FILE *f, int level, struct lyd_node *node, int onlyvalue)
Radek Krejci94ca54b2015-07-08 15:48:47 +0200140{
Radek Krejcie4748472015-07-08 18:00:22 +0200141 struct lyd_node_leaf *leaf = (struct lyd_node_leaf *)node;
Radek Krejcib8048692015-08-05 13:36:34 +0200142 struct lys_node_leaf *sleaf = (struct lys_node_leaf *)node->schema;
Radek Krejci1574a8d2015-08-03 14:16:52 +0200143 struct lys_type *type;
Michal Vasko07471a52015-07-16 11:18:48 +0200144 LY_DATA_TYPE data_type;
Michal Vaskoc82396e2015-07-17 15:31:25 +0200145 const char *schema;
Radek Krejci7511f402015-07-10 09:56:30 +0200146 char dec[21];
147 int i, len;
Radek Krejci94ca54b2015-07-08 15:48:47 +0200148
Radek Krejci5a988152015-07-15 11:16:26 +0200149 if (!onlyvalue) {
150 if (!node->parent || nscmp(node, node->parent)) {
151 /* print "namespace" */
152 if (node->schema->module->type) {
153 /* submodule, get module */
Radek Krejcib8048692015-08-05 13:36:34 +0200154 schema = ((struct lys_submodule *)node->schema->module)->belongsto->name;
Radek Krejci5a988152015-07-15 11:16:26 +0200155 } else {
156 schema = node->schema->module->name;
157 }
158 fprintf(f, "%*s\"%s:%s\": ", LEVEL, INDENT, schema, node->schema->name);
Radek Krejci94ca54b2015-07-08 15:48:47 +0200159 } else {
Radek Krejci5a988152015-07-15 11:16:26 +0200160 fprintf(f, "%*s\"%s\": ", LEVEL, INDENT, node->schema->name);
Radek Krejci94ca54b2015-07-08 15:48:47 +0200161 }
Radek Krejci94ca54b2015-07-08 15:48:47 +0200162 }
Radek Krejcie4748472015-07-08 18:00:22 +0200163
Radek Krejcib8048692015-08-05 13:36:34 +0200164 data_type = ((struct lys_node_leaf *)leaf->schema)->type.base;
Michal Vasko07471a52015-07-16 11:18:48 +0200165 if (data_type == LY_TYPE_UNION) {
166 data_type = leaf->value_type;
167 }
168
169 switch (data_type) {
Radek Krejcie4748472015-07-08 18:00:22 +0200170 case LY_TYPE_BINARY:
171 case LY_TYPE_STRING:
Radek Krejci5a988152015-07-15 11:16:26 +0200172 fprintf(f, "\"%s\"", leaf->value.string ? leaf->value.string : "");
Radek Krejcie4748472015-07-08 18:00:22 +0200173 break;
Radek Krejci3e3affe2015-07-09 15:38:40 +0200174 case LY_TYPE_BITS:
Radek Krejci5a988152015-07-15 11:16:26 +0200175 fputc('"', f);
Radek Krejci3e3affe2015-07-09 15:38:40 +0200176
177 /* locate bits structure with the bits definitions to get the array size */
178 for (type = &sleaf->type; type->der->type.der; type = &type->der->type);
179
180 /* print set bits */
181 for (i = 0; i < type->info.bits.count; i++) {
182 if (leaf->value.bit[i]) {
183 fprintf(f, "%s%s", i ? " " : "", leaf->value.bit[i]->name);
184 }
185 }
Radek Krejci5a988152015-07-15 11:16:26 +0200186 fputc('"', f);
Radek Krejci3e3affe2015-07-09 15:38:40 +0200187 break;
Radek Krejcib7384642015-07-09 16:08:45 +0200188 case LY_TYPE_BOOL:
Michal Vasko9d7fb702015-07-17 14:00:22 +0200189 fprintf(f, "%s", leaf->value.bool ? "true" : "false");
Radek Krejcib7384642015-07-09 16:08:45 +0200190 break;
Radek Krejci7511f402015-07-10 09:56:30 +0200191 case LY_TYPE_DEC64:
192
193 /* locate dec structure with the fraction-digits definitions to get the value */
194 for (type = &sleaf->type; type->der->type.der; type = &type->der->type);
195
196 snprintf(dec, 21, "%" PRId64, leaf->value.dec64);
197 len = strlen(dec);
198 for (i = 0; dec[i]; ) {
199 fputc(dec[i++], f);
200 if (i + type->info.dec64.dig == len) {
201 fputc('.', f);
202 }
203 }
Radek Krejci7511f402015-07-10 09:56:30 +0200204
205 break;
Radek Krejcibce73742015-07-10 12:46:06 +0200206 case LY_TYPE_EMPTY:
Radek Krejci5a988152015-07-15 11:16:26 +0200207 fprintf(f, "[null]");
Radek Krejcibce73742015-07-10 12:46:06 +0200208 break;
Radek Krejci5b315a92015-07-10 13:18:45 +0200209 case LY_TYPE_ENUM:
Radek Krejci5a988152015-07-15 11:16:26 +0200210 fprintf(f, "\"%s\"", leaf->value.enm->name);
Radek Krejci5b315a92015-07-10 13:18:45 +0200211 break;
Radek Krejciac8aac62015-07-10 15:36:35 +0200212 case LY_TYPE_IDENT:
213 if (sleaf->module != leaf->value.ident->module) {
214 /* namespace identifier is needed */
Radek Krejci5a988152015-07-15 11:16:26 +0200215 fprintf(f, "\"%s:%s\"", leaf->value.ident->module->name, leaf->value.ident->name);
Radek Krejciac8aac62015-07-10 15:36:35 +0200216 } else {
217 /* no namespace is needed */
Radek Krejci5a988152015-07-15 11:16:26 +0200218 fprintf(f, "\"%s\"", leaf->value.ident->name);
Radek Krejciac8aac62015-07-10 15:36:35 +0200219 }
220 break;
Michal Vasko493bea72015-07-16 16:08:12 +0200221 case LY_TYPE_INST:
Michal Vaskoc82396e2015-07-17 15:31:25 +0200222 json_print_instid(f, leaf);
Michal Vasko493bea72015-07-16 16:08:12 +0200223 break;
Radek Krejci5a988152015-07-15 11:16:26 +0200224 case LY_TYPE_LEAFREF:
225 json_print_leaf(f, level, leaf->value.leafref, 1);
226 break;
Michal Vasko58110162015-07-15 15:50:16 +0200227 case LY_TYPE_INT8:
Michal Vasko9d7fb702015-07-17 14:00:22 +0200228 fprintf(f, "%d", leaf->value.int8);
Michal Vasko58110162015-07-15 15:50:16 +0200229 break;
230 case LY_TYPE_INT16:
Michal Vasko9d7fb702015-07-17 14:00:22 +0200231 fprintf(f, "%d", leaf->value.int16);
Michal Vasko58110162015-07-15 15:50:16 +0200232 break;
233 case LY_TYPE_INT32:
Michal Vasko9d7fb702015-07-17 14:00:22 +0200234 fprintf(f, "%d", leaf->value.int32);
Michal Vasko58110162015-07-15 15:50:16 +0200235 break;
236 case LY_TYPE_INT64:
237 fprintf(f, "\"%ld\"", leaf->value.int64);
238 break;
239 case LY_TYPE_UINT8:
Michal Vasko9d7fb702015-07-17 14:00:22 +0200240 fprintf(f, "%u", leaf->value.uint8);
Michal Vasko58110162015-07-15 15:50:16 +0200241 break;
242 case LY_TYPE_UINT16:
Michal Vasko9d7fb702015-07-17 14:00:22 +0200243 fprintf(f, "%u", leaf->value.uint16);
Michal Vasko58110162015-07-15 15:50:16 +0200244 break;
245 case LY_TYPE_UINT32:
Michal Vasko9d7fb702015-07-17 14:00:22 +0200246 fprintf(f, "%u", leaf->value.uint32);
Michal Vasko58110162015-07-15 15:50:16 +0200247 break;
248 case LY_TYPE_UINT64:
249 fprintf(f, "\"%lu\"", leaf->value.uint64);
250 break;
Radek Krejcie4748472015-07-08 18:00:22 +0200251 default:
Michal Vasko493bea72015-07-16 16:08:12 +0200252 /* error */
253 fprintf(f, "\"(!error!)\"");
Radek Krejcie4748472015-07-08 18:00:22 +0200254 }
255
Radek Krejci5a988152015-07-15 11:16:26 +0200256 if (!onlyvalue) {
Radek Krejci9566b092015-07-31 11:18:15 +0200257 fprintf(f, "%s\n", lyd_is_last(node) ? "" : ",");
Radek Krejci5a988152015-07-15 11:16:26 +0200258 }
Radek Krejci94ca54b2015-07-08 15:48:47 +0200259}
260
Michal Vaskoab8e4402015-07-17 12:54:28 +0200261static void
Michal Vasko98763c62015-07-17 13:47:00 +0200262json_print_container(FILE *f, int level, struct lyd_node *node)
263{
264 const char *schema;
265 struct lyd_node *child;
266
267 if (!node->parent || nscmp(node, node->parent)) {
268 /* print "namespace" */
269 if (node->schema->module->type) {
270 /* submodule, get module */
Radek Krejcib8048692015-08-05 13:36:34 +0200271 schema = ((struct lys_submodule *)node->schema->module)->belongsto->name;
Michal Vasko98763c62015-07-17 13:47:00 +0200272 } else {
273 schema = node->schema->module->name;
274 }
275 fprintf(f, "%*s\"%s:%s\": {\n", LEVEL, INDENT, schema, node->schema->name);
276 } else {
277 fprintf(f, "%*s\"%s\": {\n", LEVEL, INDENT, node->schema->name);
278 }
279 LY_TREE_FOR(node->child, child) {
280 json_print_node(f, level + 1, child);
281 }
Radek Krejci9566b092015-07-31 11:18:15 +0200282 fprintf(f, "%*s}%s\n", LEVEL, INDENT, lyd_is_last(node) ? "" : ",");
Michal Vasko98763c62015-07-17 13:47:00 +0200283}
284
285static void
286json_print_list_internal(FILE *f, int level, struct lyd_node_list *list)
287{
288 struct lyd_node *child;
289
290 fprintf(f, "%*s{\n", LEVEL, INDENT);
291
292 LY_TREE_FOR(list->child, child) {
293 json_print_node(f, level + 1, child);
294 }
295
296 fprintf(f, "%*s}%s\n", LEVEL, INDENT, (list->lnext ? "," : ""));
297}
298
299static void
300json_print_leaf_list(FILE *f, int level, struct lyd_node *node, int is_list)
301{
302 const char *schema;
303 struct lyd_node_list *list = (struct lyd_node_list *)node;
304 struct lyd_node_leaflist *llist = (struct lyd_node_leaflist *)node;
Michal Vasko98763c62015-07-17 13:47:00 +0200305
306 if ((is_list && list->lprev) || (!is_list && llist->lprev)) {
307 /* this list is already printed */
308 return;
309 }
310
311 if (!node->parent || nscmp(node, node->parent)) {
312 /* print "namespace" */
313 if (node->schema->module->type) {
314 /* submodule, get module */
Radek Krejcib8048692015-08-05 13:36:34 +0200315 schema = ((struct lys_submodule *)node->schema->module)->belongsto->name;
Michal Vasko98763c62015-07-17 13:47:00 +0200316 } else {
317 schema = node->schema->module->name;
318 }
319 fprintf(f, "%*s\"%s:%s\": [\n", LEVEL, INDENT, schema, node->schema->name);
320 } else {
321 fprintf(f, "%*s\"%s\": [\n", LEVEL, INDENT, node->schema->name);
322 }
323
324 if (!is_list) {
325 ++level;
326 }
327 while ((is_list && list) || (!is_list && llist)) {
328 if (is_list) {
329 json_print_list_internal(f, level + 1, list);
330 list = list->lnext;
331 } else {
332 fprintf(f, "%*s", LEVEL, INDENT);
333 json_print_leaf(f, level, (struct lyd_node *)llist, 1);
334 fprintf(f, "%s\n", (llist->lnext ? "," : ""));
335 llist = llist->lnext;
336 }
337 }
338 if (!is_list) {
339 --level;
340 }
341
Radek Krejci9566b092015-07-31 11:18:15 +0200342 fprintf(f, "%*s]%s\n", LEVEL, INDENT, lyd_is_last(node) ? "" : ",");
Michal Vasko98763c62015-07-17 13:47:00 +0200343}
344
345static void
Michal Vaskoab8e4402015-07-17 12:54:28 +0200346json_print_anyxml(FILE *f, int level, struct lyd_node *node)
347{
348 struct lyd_node_anyxml *axml = (struct lyd_node_anyxml *)node;
349
Radek Krejci9566b092015-07-31 11:18:15 +0200350 fprintf(f, "%*s\"%s\": [null]%s\n", LEVEL, INDENT, axml->value->name, lyd_is_last(node) ? "" : ",");
Michal Vaskoab8e4402015-07-17 12:54:28 +0200351}
352
Radek Krejci94ca54b2015-07-08 15:48:47 +0200353void
354json_print_node(FILE *f, int level, struct lyd_node *node)
355{
356 switch (node->schema->nodetype) {
Radek Krejci76512572015-08-04 09:47:08 +0200357 case LYS_CONTAINER:
Radek Krejci94ca54b2015-07-08 15:48:47 +0200358 json_print_container(f, level, node);
359 break;
Radek Krejci76512572015-08-04 09:47:08 +0200360 case LYS_LEAF:
Radek Krejci5a988152015-07-15 11:16:26 +0200361 json_print_leaf(f, level, node, 0);
Radek Krejci94ca54b2015-07-08 15:48:47 +0200362 break;
Radek Krejci76512572015-08-04 09:47:08 +0200363 case LYS_LEAFLIST:
Michal Vasko98763c62015-07-17 13:47:00 +0200364 json_print_leaf_list(f, level, node, 0);
365 break;
Radek Krejci76512572015-08-04 09:47:08 +0200366 case LYS_LIST:
Michal Vasko98763c62015-07-17 13:47:00 +0200367 json_print_leaf_list(f, level, node, 1);
Michal Vaskoab8e4402015-07-17 12:54:28 +0200368 break;
Radek Krejci76512572015-08-04 09:47:08 +0200369 case LYS_ANYXML:
Michal Vaskoab8e4402015-07-17 12:54:28 +0200370 json_print_anyxml(f, level, node);
371 break;
Radek Krejci94ca54b2015-07-08 15:48:47 +0200372 default:
Michal Vaskoab8e4402015-07-17 12:54:28 +0200373 assert(0);
Radek Krejci94ca54b2015-07-08 15:48:47 +0200374 break;
375 }
Radek Krejci94ca54b2015-07-08 15:48:47 +0200376}
377
Michal Vasko520d4732015-07-13 15:53:33 +0200378API int
Radek Krejci94ca54b2015-07-08 15:48:47 +0200379json_print_data(FILE *f, struct lyd_node *root)
380{
381 int level = 0;
382 struct lyd_node *node;
383
384 /* start */
385 fprintf(f, "{\n");
386
387 /* content */
388 LY_TREE_FOR(root, node) {
389 json_print_node(f, level + 1, node);
390 }
391
392 /* end */
393 fprintf(f, "}\n");
394
395 return EXIT_SUCCESS;
396}