blob: 77b1d847bfc8dbbdb0023c660c9f9b582967ce1a [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
Radek Krejci998a0b82015-08-17 13:14:36 +020028#include "common.h"
Radek Krejci76b07902015-10-09 09:11:25 +020029#include "printer.h"
Michal Vasko2d162e12015-09-24 14:33:29 +020030#include "tree_data.h"
Radek Krejci998a0b82015-08-17 13:14:36 +020031#include "resolve.h"
32#include "tree_internal.h"
Radek Krejci94ca54b2015-07-08 15:48:47 +020033
34#define INDENT ""
35#define LEVEL (level*2)
36
Michal Vasko1e62a092015-12-01 12:27:20 +010037void json_print_nodes(struct lyout *out, int level, const struct lyd_node *root);
Radek Krejci94ca54b2015-07-08 15:48:47 +020038
Radek Krejci382e7f92016-01-12 17:15:47 +010039static int
40json_print_string(struct lyout *out, const char *text)
41{
42 unsigned int i, n;
43
44 if (!text) {
45 return 0;
46 }
47
48 ly_write(out, "\"", 1);
49 for (i = n = 0; text[i]; i++) {
50 if (text[i] < 0x20) {
51 /* control character */
52 n += ly_print(out, "\\u%.4X");
53 } else {
54 switch (text[i]) {
55 case '"':
56 n += ly_print(out, "\\\"");
57 break;
58 case '\\':
59 n += ly_print(out, "\\\\");
60 break;
61 default:
62 ly_write(out, &text[i], 1);
63 n++;
64 }
65 }
66 }
67 ly_write(out, "\"", 1);
68
69 return n + 2;
70}
71
Radek Krejci94ca54b2015-07-08 15:48:47 +020072static void
Michal Vasko1e62a092015-12-01 12:27:20 +010073json_print_attrs(struct lyout *out, int level, const struct lyd_node *node)
Radek Krejcida61fb22015-10-30 11:10:03 +010074{
75 struct lyd_attr *attr;
76
77 for (attr = node->attr; attr; attr = attr->next) {
78 if (attr->module != node->schema->module) {
Radek Krejci382e7f92016-01-12 17:15:47 +010079 ly_print(out, "%*s\"%s:%s\":", LEVEL, INDENT, attr->module->name, attr->name);
Radek Krejcida61fb22015-10-30 11:10:03 +010080 } else {
Radek Krejci382e7f92016-01-12 17:15:47 +010081 ly_print(out, "%*s\"%s\":", LEVEL, INDENT, attr->name);
Radek Krejcida61fb22015-10-30 11:10:03 +010082 }
Radek Krejci382e7f92016-01-12 17:15:47 +010083 json_print_string(out, attr->value ? attr->value : "");
84 ly_print(out, "%s", attr->next ? ",\n" : "\n");
Radek Krejcida61fb22015-10-30 11:10:03 +010085 }
86}
87
88static void
Michal Vasko1e62a092015-12-01 12:27:20 +010089json_print_leaf(struct lyout *out, int level, const struct lyd_node *node, int onlyvalue)
Radek Krejci94ca54b2015-07-08 15:48:47 +020090{
Michal Vasko4c183312015-09-25 10:41:47 +020091 struct lyd_node_leaf_list *leaf = (struct lyd_node_leaf_list *)node;
Radek Krejcida61fb22015-10-30 11:10:03 +010092 const char *schema = NULL;
Radek Krejci94ca54b2015-07-08 15:48:47 +020093
Radek Krejci5a988152015-07-15 11:16:26 +020094 if (!onlyvalue) {
95 if (!node->parent || nscmp(node, node->parent)) {
96 /* print "namespace" */
97 if (node->schema->module->type) {
98 /* submodule, get module */
Radek Krejcib8048692015-08-05 13:36:34 +020099 schema = ((struct lys_submodule *)node->schema->module)->belongsto->name;
Radek Krejci5a988152015-07-15 11:16:26 +0200100 } else {
101 schema = node->schema->module->name;
102 }
Radek Krejci76b07902015-10-09 09:11:25 +0200103 ly_print(out, "%*s\"%s:%s\": ", LEVEL, INDENT, schema, node->schema->name);
Radek Krejci94ca54b2015-07-08 15:48:47 +0200104 } else {
Radek Krejci76b07902015-10-09 09:11:25 +0200105 ly_print(out, "%*s\"%s\": ", LEVEL, INDENT, node->schema->name);
Radek Krejci94ca54b2015-07-08 15:48:47 +0200106 }
Radek Krejci94ca54b2015-07-08 15:48:47 +0200107 }
Radek Krejcie4748472015-07-08 18:00:22 +0200108
Radek Krejcida61fb22015-10-30 11:10:03 +0100109 switch (leaf->value_type & LY_DATA_TYPE_MASK) {
Radek Krejcie4748472015-07-08 18:00:22 +0200110 case LY_TYPE_BINARY:
111 case LY_TYPE_STRING:
Radek Krejci3e3affe2015-07-09 15:38:40 +0200112 case LY_TYPE_BITS:
Radek Krejci5b315a92015-07-10 13:18:45 +0200113 case LY_TYPE_ENUM:
Radek Krejciac8aac62015-07-10 15:36:35 +0200114 case LY_TYPE_IDENT:
Radek Krejcic5090c32015-08-12 09:46:19 +0200115 case LY_TYPE_INST:
Radek Krejci382e7f92016-01-12 17:15:47 +0100116 json_print_string(out, leaf->value_str ? leaf->value_str : "");
Radek Krejciac8aac62015-07-10 15:36:35 +0200117 break;
Radek Krejcib1c12512015-08-11 11:22:04 +0200118
119 case LY_TYPE_BOOL:
120 case LY_TYPE_DEC64:
121 case LY_TYPE_INT8:
122 case LY_TYPE_INT16:
123 case LY_TYPE_INT32:
124 case LY_TYPE_INT64:
125 case LY_TYPE_UINT8:
126 case LY_TYPE_UINT16:
127 case LY_TYPE_UINT32:
128 case LY_TYPE_UINT64:
Radek Krejci23238922015-10-27 17:13:34 +0100129 ly_print(out, "%s", leaf->value_str ? leaf->value_str : "null");
Radek Krejcib1c12512015-08-11 11:22:04 +0200130 break;
131
Radek Krejci5a988152015-07-15 11:16:26 +0200132 case LY_TYPE_LEAFREF:
Radek Krejci76b07902015-10-09 09:11:25 +0200133 json_print_leaf(out, level, leaf->value.leafref, 1);
Radek Krejci5a988152015-07-15 11:16:26 +0200134 break;
Radek Krejcib1c12512015-08-11 11:22:04 +0200135
136 case LY_TYPE_EMPTY:
Radek Krejci76b07902015-10-09 09:11:25 +0200137 ly_print(out, "[null]");
Michal Vasko58110162015-07-15 15:50:16 +0200138 break;
Radek Krejcib1c12512015-08-11 11:22:04 +0200139
Radek Krejcie4748472015-07-08 18:00:22 +0200140 default:
Michal Vasko493bea72015-07-16 16:08:12 +0200141 /* error */
Radek Krejci76b07902015-10-09 09:11:25 +0200142 ly_print(out, "\"(!error!)\"");
Radek Krejcie4748472015-07-08 18:00:22 +0200143 }
144
Radek Krejci382e7f92016-01-12 17:15:47 +0100145 /* print attributes as sibling leafs */
Radek Krejcida61fb22015-10-30 11:10:03 +0100146 if (!onlyvalue && node->attr) {
Radek Krejcida61fb22015-10-30 11:10:03 +0100147 if (schema) {
Radek Krejci88f29302015-10-30 15:42:33 +0100148 ly_print(out, ",\n%*s\"@%s:%s\": {\n", LEVEL, INDENT, schema, node->schema->name);
Radek Krejcida61fb22015-10-30 11:10:03 +0100149 } else {
Radek Krejci88f29302015-10-30 15:42:33 +0100150 ly_print(out, ",\n%*s\"@%s\": {\n", LEVEL, INDENT, node->schema->name);
Radek Krejcida61fb22015-10-30 11:10:03 +0100151 }
152 json_print_attrs(out, level + 1, node);
153 ly_print(out, "%*s}", LEVEL, INDENT);
154 }
155
Radek Krejcib1c12512015-08-11 11:22:04 +0200156 return;
Radek Krejci94ca54b2015-07-08 15:48:47 +0200157}
158
Michal Vaskoab8e4402015-07-17 12:54:28 +0200159static void
Michal Vasko1e62a092015-12-01 12:27:20 +0100160json_print_container(struct lyout *out, int level, const struct lyd_node *node)
Michal Vasko98763c62015-07-17 13:47:00 +0200161{
162 const char *schema;
Michal Vasko98763c62015-07-17 13:47:00 +0200163
164 if (!node->parent || nscmp(node, node->parent)) {
165 /* print "namespace" */
166 if (node->schema->module->type) {
167 /* submodule, get module */
Radek Krejcib8048692015-08-05 13:36:34 +0200168 schema = ((struct lys_submodule *)node->schema->module)->belongsto->name;
Michal Vasko98763c62015-07-17 13:47:00 +0200169 } else {
170 schema = node->schema->module->name;
171 }
Radek Krejci76b07902015-10-09 09:11:25 +0200172 ly_print(out, "%*s\"%s:%s\": {\n", LEVEL, INDENT, schema, node->schema->name);
Michal Vasko98763c62015-07-17 13:47:00 +0200173 } else {
Radek Krejci76b07902015-10-09 09:11:25 +0200174 ly_print(out, "%*s\"%s\": {\n", LEVEL, INDENT, node->schema->name);
Michal Vasko98763c62015-07-17 13:47:00 +0200175 }
Radek Krejcida61fb22015-10-30 11:10:03 +0100176 level++;
177 if (node->attr) {
178 ly_print(out, "%*s\"@\": {\n", LEVEL, INDENT);
179 json_print_attrs(out, level + 1, node);
180 ly_print(out, "%*s}%s", LEVEL, INDENT, node->child ? ",\n" : "");
181 }
182 json_print_nodes(out, level, node->child);
183 level--;
Radek Krejci76b07902015-10-09 09:11:25 +0200184 ly_print(out, "%*s}", LEVEL, INDENT);
Michal Vasko98763c62015-07-17 13:47:00 +0200185}
186
187static void
Michal Vasko1e62a092015-12-01 12:27:20 +0100188json_print_leaf_list(struct lyout *out, int level, const struct lyd_node *node, int is_list)
Michal Vasko98763c62015-07-17 13:47:00 +0200189{
Radek Krejcida61fb22015-10-30 11:10:03 +0100190 const char *schema = NULL;
Michal Vasko1e62a092015-12-01 12:27:20 +0100191 const struct lyd_node *list = node;
Radek Krejcida61fb22015-10-30 11:10:03 +0100192 int flag_empty = 0, flag_attrs = 0;
Radek Krejci23238922015-10-27 17:13:34 +0100193
194 if (!list->child) {
195 /* empty, e.g. in case of filter */
196 flag_empty = 1;
197 }
Michal Vasko98763c62015-07-17 13:47:00 +0200198
199 if (!node->parent || nscmp(node, node->parent)) {
200 /* print "namespace" */
201 if (node->schema->module->type) {
202 /* submodule, get module */
Radek Krejcib8048692015-08-05 13:36:34 +0200203 schema = ((struct lys_submodule *)node->schema->module)->belongsto->name;
Michal Vasko98763c62015-07-17 13:47:00 +0200204 } else {
205 schema = node->schema->module->name;
206 }
Radek Krejci23238922015-10-27 17:13:34 +0100207 ly_print(out, "%*s\"%s:%s\":", LEVEL, INDENT, schema, node->schema->name);
Michal Vasko98763c62015-07-17 13:47:00 +0200208 } else {
Radek Krejci23238922015-10-27 17:13:34 +0100209 ly_print(out, "%*s\"%s\":", LEVEL, INDENT, node->schema->name);
Michal Vasko98763c62015-07-17 13:47:00 +0200210 }
211
Radek Krejci23238922015-10-27 17:13:34 +0100212 if (flag_empty) {
213 ly_print(out, " null");
214 return;
215 }
216 ly_print(out, " [\n");
217
Michal Vasko98763c62015-07-17 13:47:00 +0200218 if (!is_list) {
219 ++level;
220 }
Radek Krejci27aaa732015-09-04 15:24:04 +0200221
222 while (list) {
Michal Vasko98763c62015-07-17 13:47:00 +0200223 if (is_list) {
Radek Krejci27aaa732015-09-04 15:24:04 +0200224 /* list print */
225 ++level;
Radek Krejci76b07902015-10-09 09:11:25 +0200226 ly_print(out, "%*s{\n", LEVEL, INDENT);
Radek Krejcida61fb22015-10-30 11:10:03 +0100227 ++level;
228 if (list->attr) {
229 ly_print(out, "%*s\"@\": {\n", LEVEL, INDENT);
230 json_print_attrs(out, level + 1, node);
231 ly_print(out, "%*s}%s", LEVEL, INDENT, list->child ? ",\n" : "");
232 }
233 json_print_nodes(out, level, list->child);
234 --level;
Radek Krejci76b07902015-10-09 09:11:25 +0200235 ly_print(out, "%*s}", LEVEL, INDENT);
Radek Krejci27aaa732015-09-04 15:24:04 +0200236 --level;
Michal Vasko98763c62015-07-17 13:47:00 +0200237 } else {
Radek Krejci27aaa732015-09-04 15:24:04 +0200238 /* leaf-list print */
Radek Krejci76b07902015-10-09 09:11:25 +0200239 ly_print(out, "%*s", LEVEL, INDENT);
240 json_print_leaf(out, level, list, 1);
Radek Krejcida61fb22015-10-30 11:10:03 +0100241 if (list->attr) {
242 flag_attrs = 1;
243 }
Radek Krejci27aaa732015-09-04 15:24:04 +0200244 }
245 for (list = list->next; list && list->schema != node->schema; list = list->next);
246 if (list) {
Radek Krejci76b07902015-10-09 09:11:25 +0200247 ly_print(out, ",\n");
Michal Vasko98763c62015-07-17 13:47:00 +0200248 }
249 }
Radek Krejci27aaa732015-09-04 15:24:04 +0200250
Michal Vasko98763c62015-07-17 13:47:00 +0200251 if (!is_list) {
252 --level;
253 }
254
Radek Krejci76b07902015-10-09 09:11:25 +0200255 ly_print(out, "\n%*s]", LEVEL, INDENT);
Radek Krejcida61fb22015-10-30 11:10:03 +0100256
257 /* attributes */
258 if (!is_list && flag_attrs) {
259 if (schema) {
Radek Krejci88f29302015-10-30 15:42:33 +0100260 ly_print(out, ",\n%*s\"@%s:%s\": [\n", LEVEL, INDENT, schema, node->schema->name);
Radek Krejcida61fb22015-10-30 11:10:03 +0100261 } else {
Radek Krejci88f29302015-10-30 15:42:33 +0100262 ly_print(out, ",\n%*s\"@%s\": [\n", LEVEL, INDENT, node->schema->name);
Radek Krejcida61fb22015-10-30 11:10:03 +0100263 }
264 level++;
265 for (list = node; list; ) {
266 if (list->attr) {
267 ly_print(out, "%*s{ ", LEVEL, INDENT);
268 json_print_attrs(out, 0, list);
269 ly_print(out, "%*s}", LEVEL, INDENT);
270 } else {
271 ly_print(out, "%*snull", LEVEL, INDENT);
272 }
273
274
275 for (list = list->next; list && list->schema != node->schema; list = list->next);
276 if (list) {
277 ly_print(out, ",\n");
278 }
279 }
280 level--;
281 ly_print(out, "\n%*s]", LEVEL, INDENT);
282 }
Michal Vasko98763c62015-07-17 13:47:00 +0200283}
284
285static void
Michal Vasko1e62a092015-12-01 12:27:20 +0100286json_print_anyxml(struct lyout *out, int level, const struct lyd_node *node)
Michal Vaskoab8e4402015-07-17 12:54:28 +0200287{
Radek Krejcida61fb22015-10-30 11:10:03 +0100288 const char *schema = NULL;
289
290 if (!node->parent || nscmp(node, node->parent)) {
291 /* print "namespace" */
292 if (node->schema->module->type) {
293 /* submodule, get module */
294 schema = ((struct lys_submodule *)node->schema->module)->belongsto->name;
295 } else {
296 schema = node->schema->module->name;
297 }
298 ly_print(out, "%*s\"%s:%s\": [null]", LEVEL, INDENT, schema, node->schema->name);
299 } else {
300 ly_print(out, "%*s\"%s\": [null]", LEVEL, INDENT, node->schema->name);
301 }
302
303 /* print attributes as sibling leaf */
304 if (node->attr) {
Radek Krejcida61fb22015-10-30 11:10:03 +0100305 if (schema) {
Radek Krejci88f29302015-10-30 15:42:33 +0100306 ly_print(out, ",\n%*s\"@%s:%s\": {\n", LEVEL, INDENT, schema, node->schema->name);
Radek Krejcida61fb22015-10-30 11:10:03 +0100307 } else {
Radek Krejci88f29302015-10-30 15:42:33 +0100308 ly_print(out, ",\n%*s\"@%s\": {\n", LEVEL, INDENT, node->schema->name);
Radek Krejcida61fb22015-10-30 11:10:03 +0100309 }
310 json_print_attrs(out, level + 1, node);
311 ly_print(out, "%*s}", LEVEL, INDENT);
312 }
Michal Vaskoab8e4402015-07-17 12:54:28 +0200313}
314
Radek Krejci94ca54b2015-07-08 15:48:47 +0200315void
Michal Vasko1e62a092015-12-01 12:27:20 +0100316json_print_nodes(struct lyout *out, int level, const struct lyd_node *root)
Radek Krejci94ca54b2015-07-08 15:48:47 +0200317{
Michal Vasko1e62a092015-12-01 12:27:20 +0100318 const struct lyd_node *node, *iter;
Radek Krejci27aaa732015-09-04 15:24:04 +0200319
320 LY_TREE_FOR(root, node) {
321 switch (node->schema->nodetype) {
Radek Krejcifb54be42015-10-02 15:21:16 +0200322 case LYS_RPC:
323 case LYS_NOTIF:
Radek Krejci27aaa732015-09-04 15:24:04 +0200324 case LYS_CONTAINER:
325 if (node->prev->next) {
326 /* print the previous comma */
Radek Krejci76b07902015-10-09 09:11:25 +0200327 ly_print(out, ",\n");
Radek Krejci27aaa732015-09-04 15:24:04 +0200328 }
Radek Krejci76b07902015-10-09 09:11:25 +0200329 json_print_container(out, level, node);
Radek Krejci27aaa732015-09-04 15:24:04 +0200330 break;
331 case LYS_LEAF:
332 if (node->prev->next) {
333 /* print the previous comma */
Radek Krejci76b07902015-10-09 09:11:25 +0200334 ly_print(out, ",\n");
Radek Krejci27aaa732015-09-04 15:24:04 +0200335 }
Radek Krejci76b07902015-10-09 09:11:25 +0200336 json_print_leaf(out, level, node, 0);
Radek Krejci27aaa732015-09-04 15:24:04 +0200337 break;
338 case LYS_LEAFLIST:
339 case LYS_LIST:
340 /* is it already printed? */
Radek Krejci9ce61512015-10-26 14:42:32 +0100341 for (iter = node->prev; iter->next; iter = iter->prev) {
Radek Krejci27aaa732015-09-04 15:24:04 +0200342 if (iter == node) {
343 continue;
344 }
345 if (iter->schema == node->schema) {
346 /* the list has alread some previous instance and therefore it is already printed */
347 break;
348 }
349 }
Michal Vasko6c563772015-10-15 10:49:30 +0200350 if (!iter->next) {
Radek Krejci27aaa732015-09-04 15:24:04 +0200351 if (node->prev->next) {
352 /* print the previous comma */
Radek Krejci76b07902015-10-09 09:11:25 +0200353 ly_print(out, ",\n");
Radek Krejci27aaa732015-09-04 15:24:04 +0200354 }
355
356 /* print the list/leaflist */
Radek Krejci76b07902015-10-09 09:11:25 +0200357 json_print_leaf_list(out, level, node, node->schema->nodetype == LYS_LIST ? 1 : 0);
Radek Krejci27aaa732015-09-04 15:24:04 +0200358 }
359 break;
360 case LYS_ANYXML:
361 if (node->prev->next) {
362 /* print the previous comma */
Radek Krejci76b07902015-10-09 09:11:25 +0200363 ly_print(out, ",\n");
Radek Krejci27aaa732015-09-04 15:24:04 +0200364 }
Radek Krejci76b07902015-10-09 09:11:25 +0200365 json_print_anyxml(out, level, node);
Radek Krejci27aaa732015-09-04 15:24:04 +0200366 break;
367 default:
368 LOGINT;
369 break;
370 }
Radek Krejci94ca54b2015-07-08 15:48:47 +0200371 }
Radek Krejci76b07902015-10-09 09:11:25 +0200372 ly_print(out, "\n");
Radek Krejci94ca54b2015-07-08 15:48:47 +0200373}
374
Radek Krejcif3752b02015-10-02 15:31:34 +0200375int
Michal Vasko1e62a092015-12-01 12:27:20 +0100376json_print_data(struct lyout *out, const struct lyd_node *root)
Radek Krejci94ca54b2015-07-08 15:48:47 +0200377{
378 int level = 0;
Radek Krejci94ca54b2015-07-08 15:48:47 +0200379
380 /* start */
Radek Krejci76b07902015-10-09 09:11:25 +0200381 ly_print(out, "{\n");
Radek Krejci94ca54b2015-07-08 15:48:47 +0200382
383 /* content */
Radek Krejci76b07902015-10-09 09:11:25 +0200384 json_print_nodes(out, level + 1, root);
Radek Krejci94ca54b2015-07-08 15:48:47 +0200385
386 /* end */
Radek Krejci76b07902015-10-09 09:11:25 +0200387 ly_print(out, "}\n");
Radek Krejci94ca54b2015-07-08 15:48:47 +0200388
389 return EXIT_SUCCESS;
390}