blob: a963d2570654c59e57269700b92670238df0c51c [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 Vaskoc82396e2015-07-17 15:31:25 +020031#include "../tree_internal.h"
Radek Krejci94ca54b2015-07-08 15:48:47 +020032
33#define INDENT ""
34#define LEVEL (level*2)
35
36void json_print_node(FILE *f, int level, struct lyd_node *node);
37
38/* 0 - same, 1 - different */
39static int
40nscmp(struct lyd_node *node1, struct lyd_node *node2)
41{
42 struct ly_module *m1, *m2;
43
44 /* we have to cover submodules belonging to the same module */
45 if (node1->schema->module->type) {
46 m1 = ((struct ly_submodule *)node1->schema->module)->belongsto;
47 } else {
48 m1 = node1->schema->module;
49 }
50 if (node2->schema->module->type) {
51 m2 = ((struct ly_submodule *)node2->schema->module)->belongsto;
52 } else {
53 m2 = node2->schema->module;
54 }
55 if (m1 == m2) {
56 /* belongs to the same module */
57 return 0;
58 } else {
59 /* different modules */
60 return 1;
61 }
62}
63
64static void
Michal Vaskoc82396e2015-07-17 15:31:25 +020065json_print_text_dquote(FILE *f, const char *str, int str_len)
66{
67 const char *ptr;
68
69 while ((ptr = strnchr(str, '\"', str_len))) {
70 fprintf(f, "%.*s\\\"", (int)(ptr-str), str);
71 str_len -= (ptr-str)+1;
72 str = ptr+1;
73 }
74
75 fprintf(f, "%.*s", str_len, str);
76}
77
78static void
79json_print_instid(FILE *f, struct lyd_node_leaf *leaf)
80{
81 const char *ptr, *print_ptr;
82 int cur_id_len, print_id_len;
83 struct leafref_instid *nodes;
84 struct ly_module *prev_module = NULL, *cur_module;
85 struct ly_mnode *snode;
86
87 assert(((struct ly_mnode_leaf *)leaf->schema)->type.base == LY_TYPE_INST);
88
89 fputc('\"', f);
90 print_ptr = ptr = leaf->value_str+1;
91
92 while (print_ptr[0]) {
93 fputc('/', f);
94
95 /* check namespaces */
96 ptr = strchr(ptr, '/');
97 if (ptr) {
98 cur_id_len = ptr - leaf->value_str;
99 } else {
100 cur_id_len = strlen(leaf->value_str);
101 }
102
103 nodes = resolve_instid((struct lyd_node *)leaf, leaf->value_str, cur_id_len);
104 assert(nodes && !nodes->next);
105
106 snode = (struct ly_mnode *)nodes->dnode->schema;
107 free(nodes);
108
109 /* find current module */
110 if (snode->module->type) {
111 cur_module = ((struct ly_submodule *)snode->module)->belongsto;
112 } else {
113 cur_module = snode->module;
114 }
115
116 if (!prev_module || (cur_module != prev_module)) {
117 fprintf(f, "%s:", cur_module->ns);
118 prev_module = cur_module;
119 }
120
121 ptr = strchr(print_ptr+1, '/');
122 if (ptr) {
123 print_id_len = ptr - print_ptr;
124 } else {
125 print_id_len = strlen(print_ptr);
126 }
127
128 json_print_text_dquote(f, print_ptr, print_id_len);
129 print_ptr += print_id_len+1;
130 }
131
132 fprintf(f, "\"");
133}
134
135static void
Radek Krejci5a988152015-07-15 11:16:26 +0200136json_print_leaf(FILE *f, int level, struct lyd_node *node, int onlyvalue)
Radek Krejci94ca54b2015-07-08 15:48:47 +0200137{
Radek Krejcie4748472015-07-08 18:00:22 +0200138 struct lyd_node_leaf *leaf = (struct lyd_node_leaf *)node;
Radek Krejci3e3affe2015-07-09 15:38:40 +0200139 struct ly_mnode_leaf *sleaf = (struct ly_mnode_leaf *)node->schema;
140 struct ly_type *type;
Michal Vasko07471a52015-07-16 11:18:48 +0200141 LY_DATA_TYPE data_type;
Michal Vaskoc82396e2015-07-17 15:31:25 +0200142 const char *schema;
Radek Krejci7511f402015-07-10 09:56:30 +0200143 char dec[21];
144 int i, len;
Radek Krejci94ca54b2015-07-08 15:48:47 +0200145
Radek Krejci5a988152015-07-15 11:16:26 +0200146 if (!onlyvalue) {
147 if (!node->parent || nscmp(node, node->parent)) {
148 /* print "namespace" */
149 if (node->schema->module->type) {
150 /* submodule, get module */
151 schema = ((struct ly_submodule *)node->schema->module)->belongsto->name;
152 } else {
153 schema = node->schema->module->name;
154 }
155 fprintf(f, "%*s\"%s:%s\": ", LEVEL, INDENT, schema, node->schema->name);
Radek Krejci94ca54b2015-07-08 15:48:47 +0200156 } else {
Radek Krejci5a988152015-07-15 11:16:26 +0200157 fprintf(f, "%*s\"%s\": ", LEVEL, INDENT, node->schema->name);
Radek Krejci94ca54b2015-07-08 15:48:47 +0200158 }
Radek Krejci94ca54b2015-07-08 15:48:47 +0200159 }
Radek Krejcie4748472015-07-08 18:00:22 +0200160
Michal Vasko07471a52015-07-16 11:18:48 +0200161 data_type = ((struct ly_mnode_leaf *)leaf->schema)->type.base;
162 if (data_type == LY_TYPE_UNION) {
163 data_type = leaf->value_type;
164 }
165
166 switch (data_type) {
Radek Krejcie4748472015-07-08 18:00:22 +0200167 case LY_TYPE_BINARY:
168 case LY_TYPE_STRING:
Radek Krejci5a988152015-07-15 11:16:26 +0200169 fprintf(f, "\"%s\"", leaf->value.string ? leaf->value.string : "");
Radek Krejcie4748472015-07-08 18:00:22 +0200170 break;
Radek Krejci3e3affe2015-07-09 15:38:40 +0200171 case LY_TYPE_BITS:
Radek Krejci5a988152015-07-15 11:16:26 +0200172 fputc('"', f);
Radek Krejci3e3affe2015-07-09 15:38:40 +0200173
174 /* locate bits structure with the bits definitions to get the array size */
175 for (type = &sleaf->type; type->der->type.der; type = &type->der->type);
176
177 /* print set bits */
178 for (i = 0; i < type->info.bits.count; i++) {
179 if (leaf->value.bit[i]) {
180 fprintf(f, "%s%s", i ? " " : "", leaf->value.bit[i]->name);
181 }
182 }
Radek Krejci5a988152015-07-15 11:16:26 +0200183 fputc('"', f);
Radek Krejci3e3affe2015-07-09 15:38:40 +0200184 break;
Radek Krejcib7384642015-07-09 16:08:45 +0200185 case LY_TYPE_BOOL:
Michal Vasko9d7fb702015-07-17 14:00:22 +0200186 fprintf(f, "%s", leaf->value.bool ? "true" : "false");
Radek Krejcib7384642015-07-09 16:08:45 +0200187 break;
Radek Krejci7511f402015-07-10 09:56:30 +0200188 case LY_TYPE_DEC64:
189
190 /* locate dec structure with the fraction-digits definitions to get the value */
191 for (type = &sleaf->type; type->der->type.der; type = &type->der->type);
192
193 snprintf(dec, 21, "%" PRId64, leaf->value.dec64);
194 len = strlen(dec);
195 for (i = 0; dec[i]; ) {
196 fputc(dec[i++], f);
197 if (i + type->info.dec64.dig == len) {
198 fputc('.', f);
199 }
200 }
Radek Krejci7511f402015-07-10 09:56:30 +0200201
202 break;
Radek Krejcibce73742015-07-10 12:46:06 +0200203 case LY_TYPE_EMPTY:
Radek Krejci5a988152015-07-15 11:16:26 +0200204 fprintf(f, "[null]");
Radek Krejcibce73742015-07-10 12:46:06 +0200205 break;
Radek Krejci5b315a92015-07-10 13:18:45 +0200206 case LY_TYPE_ENUM:
Radek Krejci5a988152015-07-15 11:16:26 +0200207 fprintf(f, "\"%s\"", leaf->value.enm->name);
Radek Krejci5b315a92015-07-10 13:18:45 +0200208 break;
Radek Krejciac8aac62015-07-10 15:36:35 +0200209 case LY_TYPE_IDENT:
210 if (sleaf->module != leaf->value.ident->module) {
211 /* namespace identifier is needed */
Radek Krejci5a988152015-07-15 11:16:26 +0200212 fprintf(f, "\"%s:%s\"", leaf->value.ident->module->name, leaf->value.ident->name);
Radek Krejciac8aac62015-07-10 15:36:35 +0200213 } else {
214 /* no namespace is needed */
Radek Krejci5a988152015-07-15 11:16:26 +0200215 fprintf(f, "\"%s\"", leaf->value.ident->name);
Radek Krejciac8aac62015-07-10 15:36:35 +0200216 }
217 break;
Michal Vasko493bea72015-07-16 16:08:12 +0200218 case LY_TYPE_INST:
Michal Vaskoc82396e2015-07-17 15:31:25 +0200219 json_print_instid(f, leaf);
Michal Vasko493bea72015-07-16 16:08:12 +0200220 break;
Radek Krejci5a988152015-07-15 11:16:26 +0200221 case LY_TYPE_LEAFREF:
222 json_print_leaf(f, level, leaf->value.leafref, 1);
223 break;
Michal Vasko58110162015-07-15 15:50:16 +0200224 case LY_TYPE_INT8:
Michal Vasko9d7fb702015-07-17 14:00:22 +0200225 fprintf(f, "%d", leaf->value.int8);
Michal Vasko58110162015-07-15 15:50:16 +0200226 break;
227 case LY_TYPE_INT16:
Michal Vasko9d7fb702015-07-17 14:00:22 +0200228 fprintf(f, "%d", leaf->value.int16);
Michal Vasko58110162015-07-15 15:50:16 +0200229 break;
230 case LY_TYPE_INT32:
Michal Vasko9d7fb702015-07-17 14:00:22 +0200231 fprintf(f, "%d", leaf->value.int32);
Michal Vasko58110162015-07-15 15:50:16 +0200232 break;
233 case LY_TYPE_INT64:
234 fprintf(f, "\"%ld\"", leaf->value.int64);
235 break;
236 case LY_TYPE_UINT8:
Michal Vasko9d7fb702015-07-17 14:00:22 +0200237 fprintf(f, "%u", leaf->value.uint8);
Michal Vasko58110162015-07-15 15:50:16 +0200238 break;
239 case LY_TYPE_UINT16:
Michal Vasko9d7fb702015-07-17 14:00:22 +0200240 fprintf(f, "%u", leaf->value.uint16);
Michal Vasko58110162015-07-15 15:50:16 +0200241 break;
242 case LY_TYPE_UINT32:
Michal Vasko9d7fb702015-07-17 14:00:22 +0200243 fprintf(f, "%u", leaf->value.uint32);
Michal Vasko58110162015-07-15 15:50:16 +0200244 break;
245 case LY_TYPE_UINT64:
246 fprintf(f, "\"%lu\"", leaf->value.uint64);
247 break;
Radek Krejcie4748472015-07-08 18:00:22 +0200248 default:
Michal Vasko493bea72015-07-16 16:08:12 +0200249 /* error */
250 fprintf(f, "\"(!error!)\"");
Radek Krejcie4748472015-07-08 18:00:22 +0200251 }
252
Radek Krejci5a988152015-07-15 11:16:26 +0200253 if (!onlyvalue) {
254 fprintf(f, "%s\n", node->next ? "," : "");
255 }
Radek Krejci94ca54b2015-07-08 15:48:47 +0200256}
257
Michal Vaskoab8e4402015-07-17 12:54:28 +0200258static void
Michal Vasko98763c62015-07-17 13:47:00 +0200259json_print_container(FILE *f, int level, struct lyd_node *node)
260{
261 const char *schema;
262 struct lyd_node *child;
263
264 if (!node->parent || nscmp(node, node->parent)) {
265 /* print "namespace" */
266 if (node->schema->module->type) {
267 /* submodule, get module */
268 schema = ((struct ly_submodule *)node->schema->module)->belongsto->name;
269 } else {
270 schema = node->schema->module->name;
271 }
272 fprintf(f, "%*s\"%s:%s\": {\n", LEVEL, INDENT, schema, node->schema->name);
273 } else {
274 fprintf(f, "%*s\"%s\": {\n", LEVEL, INDENT, node->schema->name);
275 }
276 LY_TREE_FOR(node->child, child) {
277 json_print_node(f, level + 1, child);
278 }
279 fprintf(f, "%*s}%s\n", LEVEL, INDENT, node->next ? "," : "");
280}
281
282static void
283json_print_list_internal(FILE *f, int level, struct lyd_node_list *list)
284{
285 struct lyd_node *child;
286
287 fprintf(f, "%*s{\n", LEVEL, INDENT);
288
289 LY_TREE_FOR(list->child, child) {
290 json_print_node(f, level + 1, child);
291 }
292
293 fprintf(f, "%*s}%s\n", LEVEL, INDENT, (list->lnext ? "," : ""));
294}
295
296static void
297json_print_leaf_list(FILE *f, int level, struct lyd_node *node, int is_list)
298{
299 const char *schema;
300 struct lyd_node_list *list = (struct lyd_node_list *)node;
301 struct lyd_node_leaflist *llist = (struct lyd_node_leaflist *)node;
302 struct lyd_node *iter;
303 char *delim = "";
304
305 if ((is_list && list->lprev) || (!is_list && llist->lprev)) {
306 /* this list is already printed */
307 return;
308 }
309
310 if (!node->parent || nscmp(node, node->parent)) {
311 /* print "namespace" */
312 if (node->schema->module->type) {
313 /* submodule, get module */
314 schema = ((struct ly_submodule *)node->schema->module)->belongsto->name;
315 } else {
316 schema = node->schema->module->name;
317 }
318 fprintf(f, "%*s\"%s:%s\": [\n", LEVEL, INDENT, schema, node->schema->name);
319 } else {
320 fprintf(f, "%*s\"%s\": [\n", LEVEL, INDENT, node->schema->name);
321 }
322
323 if (!is_list) {
324 ++level;
325 }
326 while ((is_list && list) || (!is_list && llist)) {
327 if (is_list) {
328 json_print_list_internal(f, level + 1, list);
329 list = list->lnext;
330 } else {
331 fprintf(f, "%*s", LEVEL, INDENT);
332 json_print_leaf(f, level, (struct lyd_node *)llist, 1);
333 fprintf(f, "%s\n", (llist->lnext ? "," : ""));
334 llist = llist->lnext;
335 }
336 }
337 if (!is_list) {
338 --level;
339 }
340
341 for (iter = node->next; iter; iter = iter->next) {
342 if (iter->schema != node->schema) {
343 delim = ",";
344 break;
345 }
346 }
347 fprintf(f, "%*s]%s\n", LEVEL, INDENT, delim);
348}
349
350static void
Michal Vaskoab8e4402015-07-17 12:54:28 +0200351json_print_anyxml(FILE *f, int level, struct lyd_node *node)
352{
353 struct lyd_node_anyxml *axml = (struct lyd_node_anyxml *)node;
354
355 fprintf(f, "%*s\"%s\": [null]%s\n", LEVEL, INDENT, axml->value->name, node->next ? "," : "");
356}
357
Radek Krejci94ca54b2015-07-08 15:48:47 +0200358void
359json_print_node(FILE *f, int level, struct lyd_node *node)
360{
361 switch (node->schema->nodetype) {
Radek Krejci94ca54b2015-07-08 15:48:47 +0200362 case LY_NODE_CONTAINER:
363 json_print_container(f, level, node);
364 break;
365 case LY_NODE_LEAF:
Radek Krejci5a988152015-07-15 11:16:26 +0200366 json_print_leaf(f, level, node, 0);
Radek Krejci94ca54b2015-07-08 15:48:47 +0200367 break;
Michal Vasko98763c62015-07-17 13:47:00 +0200368 case LY_NODE_LEAFLIST:
369 json_print_leaf_list(f, level, node, 0);
370 break;
Michal Vaskoab8e4402015-07-17 12:54:28 +0200371 case LY_NODE_LIST:
Michal Vasko98763c62015-07-17 13:47:00 +0200372 json_print_leaf_list(f, level, node, 1);
Michal Vaskoab8e4402015-07-17 12:54:28 +0200373 break;
374 case LY_NODE_ANYXML:
375 json_print_anyxml(f, level, node);
376 break;
Radek Krejci94ca54b2015-07-08 15:48:47 +0200377 default:
Michal Vaskoab8e4402015-07-17 12:54:28 +0200378 assert(0);
Radek Krejci94ca54b2015-07-08 15:48:47 +0200379 break;
380 }
Radek Krejci94ca54b2015-07-08 15:48:47 +0200381}
382
Michal Vasko520d4732015-07-13 15:53:33 +0200383API int
Radek Krejci94ca54b2015-07-08 15:48:47 +0200384json_print_data(FILE *f, struct lyd_node *root)
385{
386 int level = 0;
387 struct lyd_node *node;
388
389 /* start */
390 fprintf(f, "{\n");
391
392 /* content */
393 LY_TREE_FOR(root, node) {
394 json_print_node(f, level + 1, node);
395 }
396
397 /* end */
398 fprintf(f, "}\n");
399
400 return EXIT_SUCCESS;
401}