blob: 4b13918a72a6f06f6c90e3bbb932e72df585527f [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 *
Radek Krejci54f6fb32016-02-24 12:56:39 +01008 * This source code is licensed under BSD 3-Clause License (the "License").
9 * You may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
Michal Vasko8de098c2016-02-26 10:00:25 +010011 *
Radek Krejci54f6fb32016-02-24 12:56:39 +010012 * https://opensource.org/licenses/BSD-3-Clause
Radek Krejci94ca54b2015-07-08 15:48:47 +020013 */
14
15#include <stdlib.h>
16#include <stdio.h>
17#include <string.h>
18#include <assert.h>
Radek Krejci7511f402015-07-10 09:56:30 +020019#include <inttypes.h>
Radek Krejci94ca54b2015-07-08 15:48:47 +020020
Radek Krejci998a0b82015-08-17 13:14:36 +020021#include "common.h"
Radek Krejci76b07902015-10-09 09:11:25 +020022#include "printer.h"
Michal Vasko2d162e12015-09-24 14:33:29 +020023#include "tree_data.h"
Radek Krejci998a0b82015-08-17 13:14:36 +020024#include "resolve.h"
25#include "tree_internal.h"
Radek Krejci94ca54b2015-07-08 15:48:47 +020026
27#define INDENT ""
28#define LEVEL (level*2)
29
Michal Vaskob3c31bd2017-07-17 10:01:48 +020030static int json_print_nodes(struct lyout *out, int level, const struct lyd_node *root, int withsiblings, int toplevel,
31 int options);
Radek Krejci94ca54b2015-07-08 15:48:47 +020032
Radek Krejci382e7f92016-01-12 17:15:47 +010033static int
34json_print_string(struct lyout *out, const char *text)
35{
36 unsigned int i, n;
37
38 if (!text) {
39 return 0;
40 }
41
42 ly_write(out, "\"", 1);
43 for (i = n = 0; text[i]; i++) {
zyinter200856c0f132016-11-17 10:59:23 +080044 if (text[i] >= 0 && text[i] < 0x20) {
Radek Krejci382e7f92016-01-12 17:15:47 +010045 /* control character */
46 n += ly_print(out, "\\u%.4X");
47 } else {
48 switch (text[i]) {
49 case '"':
50 n += ly_print(out, "\\\"");
51 break;
52 case '\\':
53 n += ly_print(out, "\\\\");
54 break;
55 default:
56 ly_write(out, &text[i], 1);
57 n++;
58 }
59 }
60 }
61 ly_write(out, "\"", 1);
62
63 return n + 2;
64}
65
Michal Vaskob3c31bd2017-07-17 10:01:48 +020066static int
Radek Krejci1eefeb32016-04-15 16:01:46 +020067json_print_attrs(struct lyout *out, int level, const struct lyd_node *node, const struct lys_module *wdmod)
Radek Krejcida61fb22015-10-30 11:10:03 +010068{
69 struct lyd_attr *attr;
Radek Krejcia571d942017-02-24 09:26:49 +010070 size_t len;
71 char *p;
Radek Krejcida61fb22015-10-30 11:10:03 +010072
Radek Krejci1eefeb32016-04-15 16:01:46 +020073 if (wdmod) {
74 ly_print(out, "%*s\"%s:default\":\"true\"", LEVEL, INDENT, wdmod->name);
75 ly_print(out, "%s%s", node->attr ? "," : "", (level ? "\n" : ""));
76 }
Radek Krejcida61fb22015-10-30 11:10:03 +010077 for (attr = node->attr; attr; attr = attr->next) {
Radek Krejci532e5e92017-02-22 12:59:24 +010078 if (!attr->annotation) {
79 /* skip exception for the NETCONF's attribute since JSON is not defined for NETCONF */
80 continue;
81 }
Radek Krejcib1ef1872017-02-23 14:33:34 +010082 if (lys_main_module(attr->annotation->module) != lys_main_module(node->schema->module)) {
Radek Krejci532e5e92017-02-22 12:59:24 +010083 ly_print(out, "%*s\"%s:%s\":", LEVEL, INDENT, attr->annotation->module->name, attr->name);
Radek Krejcida61fb22015-10-30 11:10:03 +010084 } else {
Radek Krejci382e7f92016-01-12 17:15:47 +010085 ly_print(out, "%*s\"%s\":", LEVEL, INDENT, attr->name);
Radek Krejcida61fb22015-10-30 11:10:03 +010086 }
Radek Krejcia571d942017-02-24 09:26:49 +010087 /* leafref is not supported */
Michal Vasko70bf8e52018-03-26 11:32:33 +020088 switch (attr->value_type) {
Radek Krejcia571d942017-02-24 09:26:49 +010089 case LY_TYPE_BINARY:
90 case LY_TYPE_STRING:
91 case LY_TYPE_BITS:
92 case LY_TYPE_ENUM:
93 case LY_TYPE_INST:
94 case LY_TYPE_INT64:
95 case LY_TYPE_UINT64:
96 case LY_TYPE_DEC64:
Michal Vaskoa80d8302017-03-02 10:52:02 +010097 json_print_string(out, attr->value_str);
Radek Krejcia571d942017-02-24 09:26:49 +010098 break;
99
100 case LY_TYPE_INT8:
101 case LY_TYPE_INT16:
102 case LY_TYPE_INT32:
103 case LY_TYPE_UINT8:
104 case LY_TYPE_UINT16:
105 case LY_TYPE_UINT32:
106 case LY_TYPE_BOOL:
107 ly_print(out, "%s", attr->value_str[0] ? attr->value_str : "null");
108 break;
109
110 case LY_TYPE_IDENT:
111 p = strchr(attr->value_str, ':');
112 assert(p);
113 len = p - attr->value_str;
114 if (!strncmp(attr->value_str, attr->annotation->module->name, len)
115 && !attr->annotation->module->name[len]) {
116 /* do not print the prefix, it is the default prefix for this node */
117 json_print_string(out, ++p);
118 } else {
119 json_print_string(out, attr->value_str);
120 }
121 break;
122
123 case LY_TYPE_EMPTY:
124 ly_print(out, "[null]");
125 break;
126
127 default:
128 /* error */
129 ly_print(out, "\"(!error!)\"");
Michal Vaskob3c31bd2017-07-17 10:01:48 +0200130 return EXIT_FAILURE;
Radek Krejcia571d942017-02-24 09:26:49 +0100131 }
132
Michal Vasko95068c42016-03-24 14:58:11 +0100133 ly_print(out, "%s%s", attr->next ? "," : "", (level ? "\n" : ""));
Radek Krejcida61fb22015-10-30 11:10:03 +0100134 }
Michal Vaskob3c31bd2017-07-17 10:01:48 +0200135
136 return EXIT_SUCCESS;
Radek Krejcida61fb22015-10-30 11:10:03 +0100137}
138
Michal Vaskob3c31bd2017-07-17 10:01:48 +0200139static int
Radek Krejci46180b52016-08-31 16:01:32 +0200140json_print_leaf(struct lyout *out, int level, const struct lyd_node *node, int onlyvalue, int toplevel, int options)
Radek Krejci94ca54b2015-07-08 15:48:47 +0200141{
Michal Vaskoe3886bb2017-01-02 11:33:28 +0100142 struct lyd_node_leaf_list *leaf = (struct lyd_node_leaf_list *)node, *iter;
Michal Vasko0bff3222017-01-05 10:55:31 +0100143 const struct lys_type *type;
Radek Krejci7a2a5622016-12-05 13:32:05 +0100144 const char *schema = NULL, *p, *mod_name;
Radek Krejci1eefeb32016-04-15 16:01:46 +0200145 const struct lys_module *wdmod = NULL;
Radek Krejci9b6aad22016-09-20 15:55:51 +0200146 LY_DATA_TYPE datatype;
Radek Krejci7a2a5622016-12-05 13:32:05 +0100147 size_t len;
Radek Krejci1eefeb32016-04-15 16:01:46 +0200148
Radek Krejci46180b52016-08-31 16:01:32 +0200149 if ((node->dflt && (options & (LYP_WD_ALL_TAG | LYP_WD_IMPL_TAG))) ||
150 (!node->dflt && (options & LYP_WD_ALL_TAG) && lyd_wd_default(leaf))) {
151 /* we have implicit OR explicit default node */
Radek Krejci1eefeb32016-04-15 16:01:46 +0200152 /* get with-defaults module */
Radek Krejcidfb00d62017-09-06 09:39:35 +0200153 wdmod = ly_ctx_get_module(node->schema->module->ctx, "ietf-netconf-with-defaults", NULL, 1);
Radek Krejci1eefeb32016-04-15 16:01:46 +0200154 }
Radek Krejci94ca54b2015-07-08 15:48:47 +0200155
Radek Krejci5a988152015-07-15 11:16:26 +0200156 if (!onlyvalue) {
Michal Vasko635bd452016-05-18 13:26:55 +0200157 if (toplevel || !node->parent || nscmp(node, node->parent)) {
Radek Krejci5a988152015-07-15 11:16:26 +0200158 /* print "namespace" */
Michal Vasko6c629ac2016-02-15 14:08:23 +0100159 schema = lys_node_module(node->schema)->name;
Michal Vasko95068c42016-03-24 14:58:11 +0100160 ly_print(out, "%*s\"%s:%s\":%s", LEVEL, INDENT, schema, node->schema->name, (level ? " " : ""));
Radek Krejci94ca54b2015-07-08 15:48:47 +0200161 } else {
Michal Vasko95068c42016-03-24 14:58:11 +0100162 ly_print(out, "%*s\"%s\":%s", LEVEL, INDENT, node->schema->name, (level ? " " : ""));
Radek Krejci94ca54b2015-07-08 15:48:47 +0200163 }
Radek Krejci94ca54b2015-07-08 15:48:47 +0200164 }
Radek Krejcie4748472015-07-08 18:00:22 +0200165
Michal Vasko70bf8e52018-03-26 11:32:33 +0200166 datatype = leaf->value_type;
Radek Krejci9b6aad22016-09-20 15:55:51 +0200167contentprint:
168 switch (datatype) {
Radek Krejcie4748472015-07-08 18:00:22 +0200169 case LY_TYPE_BINARY:
170 case LY_TYPE_STRING:
Radek Krejci3e3affe2015-07-09 15:38:40 +0200171 case LY_TYPE_BITS:
Radek Krejci5b315a92015-07-10 13:18:45 +0200172 case LY_TYPE_ENUM:
Radek Krejcic5090c32015-08-12 09:46:19 +0200173 case LY_TYPE_INST:
Radek Krejcic27114c2016-09-20 10:02:28 +0200174 case LY_TYPE_INT64:
175 case LY_TYPE_UINT64:
严军喜100794891758ff62016-10-25 10:14:47 +0800176 case LY_TYPE_DEC64:
Michal Vasko44913842016-04-13 14:20:41 +0200177 json_print_string(out, leaf->value_str);
Radek Krejciac8aac62015-07-10 15:36:35 +0200178 break;
Radek Krejcib1c12512015-08-11 11:22:04 +0200179
Radek Krejcib1c12512015-08-11 11:22:04 +0200180 case LY_TYPE_INT8:
181 case LY_TYPE_INT16:
182 case LY_TYPE_INT32:
Radek Krejcib1c12512015-08-11 11:22:04 +0200183 case LY_TYPE_UINT8:
184 case LY_TYPE_UINT16:
185 case LY_TYPE_UINT32:
严军喜100794891758ff62016-10-25 10:14:47 +0800186 case LY_TYPE_BOOL:
Michal Vasko44913842016-04-13 14:20:41 +0200187 ly_print(out, "%s", leaf->value_str[0] ? leaf->value_str : "null");
Radek Krejcib1c12512015-08-11 11:22:04 +0200188 break;
189
Radek Krejci7a2a5622016-12-05 13:32:05 +0100190 case LY_TYPE_IDENT:
191 p = strchr(leaf->value_str, ':');
192 assert(p);
193 len = p - leaf->value_str;
194 mod_name = leaf->schema->module->name;
195 if (!strncmp(leaf->value_str, mod_name, len) && !mod_name[len]) {
196 /* do not print the prefix, it is the default prefix for this node */
197 json_print_string(out, ++p);
198 } else {
199 json_print_string(out, leaf->value_str);
200 }
201 break;
202
Radek Krejci9b6aad22016-09-20 15:55:51 +0200203 case LY_TYPE_LEAFREF:
Michal Vaskoe3886bb2017-01-02 11:33:28 +0100204 iter = (struct lyd_node_leaf_list *)leaf->value.leafref;
205 while (iter && (iter->value_type == LY_TYPE_LEAFREF)) {
206 iter = (struct lyd_node_leaf_list *)iter->value.leafref;
207 }
208 if (!iter) {
Michal Vasko0bff3222017-01-05 10:55:31 +0100209 /* unresolved and invalid, but we can learn the correct type anyway */
210 type = lyd_leaf_type((struct lyd_node_leaf_list *)leaf);
211 if (!type) {
212 /* error */
213 ly_print(out, "\"(!error!)\"");
Michal Vaskob3c31bd2017-07-17 10:01:48 +0200214 return EXIT_FAILURE;
Michal Vasko0bff3222017-01-05 10:55:31 +0100215 }
216 datatype = type->base;
Michal Vaskoe3886bb2017-01-02 11:33:28 +0100217 } else {
Michal Vasko70bf8e52018-03-26 11:32:33 +0200218 datatype = iter->value_type;
Radek Krejci9ad23f42016-10-31 15:46:52 +0100219 }
Michal Vasko0bff3222017-01-05 10:55:31 +0100220 goto contentprint;
Radek Krejci9b6aad22016-09-20 15:55:51 +0200221
Radek Krejcib1c12512015-08-11 11:22:04 +0200222 case LY_TYPE_EMPTY:
Radek Krejci76b07902015-10-09 09:11:25 +0200223 ly_print(out, "[null]");
Michal Vasko58110162015-07-15 15:50:16 +0200224 break;
Radek Krejcib1c12512015-08-11 11:22:04 +0200225
Radek Krejcie4748472015-07-08 18:00:22 +0200226 default:
Michal Vasko493bea72015-07-16 16:08:12 +0200227 /* error */
Radek Krejci76b07902015-10-09 09:11:25 +0200228 ly_print(out, "\"(!error!)\"");
Michal Vaskob3c31bd2017-07-17 10:01:48 +0200229 return EXIT_FAILURE;
Radek Krejcie4748472015-07-08 18:00:22 +0200230 }
231
Radek Krejci382e7f92016-01-12 17:15:47 +0100232 /* print attributes as sibling leafs */
Radek Krejci1eefeb32016-04-15 16:01:46 +0200233 if (!onlyvalue && (node->attr || wdmod)) {
Radek Krejcida61fb22015-10-30 11:10:03 +0100234 if (schema) {
Michal Vasko95068c42016-03-24 14:58:11 +0100235 ly_print(out, ",%s%*s\"@%s:%s\":%s{%s", (level ? "\n" : ""), LEVEL, INDENT, schema, node->schema->name,
236 (level ? " " : ""), (level ? "\n" : ""));
Radek Krejcida61fb22015-10-30 11:10:03 +0100237 } else {
Michal Vasko95068c42016-03-24 14:58:11 +0100238 ly_print(out, ",%s%*s\"@%s\":%s{%s", (level ? "\n" : ""), LEVEL, INDENT, node->schema->name,
239 (level ? " " : ""), (level ? "\n" : ""));
Radek Krejcida61fb22015-10-30 11:10:03 +0100240 }
Michal Vaskob3c31bd2017-07-17 10:01:48 +0200241 if (json_print_attrs(out, (level ? level + 1 : level), node, wdmod)) {
242 return EXIT_FAILURE;
243 }
Radek Krejcida61fb22015-10-30 11:10:03 +0100244 ly_print(out, "%*s}", LEVEL, INDENT);
245 }
246
Michal Vaskob3c31bd2017-07-17 10:01:48 +0200247 return EXIT_SUCCESS;
Radek Krejci94ca54b2015-07-08 15:48:47 +0200248}
249
Michal Vaskob3c31bd2017-07-17 10:01:48 +0200250static int
Radek Krejci46180b52016-08-31 16:01:32 +0200251json_print_container(struct lyout *out, int level, const struct lyd_node *node, int toplevel, int options)
Michal Vasko98763c62015-07-17 13:47:00 +0200252{
253 const char *schema;
Michal Vasko98763c62015-07-17 13:47:00 +0200254
Michal Vasko635bd452016-05-18 13:26:55 +0200255 if (toplevel || !node->parent || nscmp(node, node->parent)) {
Michal Vasko98763c62015-07-17 13:47:00 +0200256 /* print "namespace" */
Michal Vasko6c629ac2016-02-15 14:08:23 +0100257 schema = lys_node_module(node->schema)->name;
Michal Vasko95068c42016-03-24 14:58:11 +0100258 ly_print(out, "%*s\"%s:%s\":%s{%s", LEVEL, INDENT, schema, node->schema->name, (level ? " " : ""), (level ? "\n" : ""));
Michal Vasko98763c62015-07-17 13:47:00 +0200259 } else {
Michal Vasko95068c42016-03-24 14:58:11 +0100260 ly_print(out, "%*s\"%s\":%s{%s", LEVEL, INDENT, node->schema->name, (level ? " " : ""), (level ? "\n" : ""));
Michal Vasko98763c62015-07-17 13:47:00 +0200261 }
Michal Vasko95068c42016-03-24 14:58:11 +0100262 if (level) {
263 level++;
264 }
Radek Krejcida61fb22015-10-30 11:10:03 +0100265 if (node->attr) {
Michal Vasko95068c42016-03-24 14:58:11 +0100266 ly_print(out, "%*s\"@\":%s{%s", LEVEL, INDENT, (level ? " " : ""), (level ? "\n" : ""));
Michal Vaskob3c31bd2017-07-17 10:01:48 +0200267 if (json_print_attrs(out, (level ? level + 1 : level), node, NULL)) {
268 return EXIT_FAILURE;
269 }
Michal Vasko95068c42016-03-24 14:58:11 +0100270 ly_print(out, "%*s}", LEVEL, INDENT);
271 if (node->child) {
272 ly_print(out, ",%s", (level ? "\n" : ""));
273 }
Radek Krejcida61fb22015-10-30 11:10:03 +0100274 }
Michal Vaskob3c31bd2017-07-17 10:01:48 +0200275 if (json_print_nodes(out, level, node->child, 1, 0, options)) {
276 return EXIT_FAILURE;
277 }
Michal Vasko95068c42016-03-24 14:58:11 +0100278 if (level) {
279 level--;
280 }
Radek Krejci76b07902015-10-09 09:11:25 +0200281 ly_print(out, "%*s}", LEVEL, INDENT);
Michal Vaskob3c31bd2017-07-17 10:01:48 +0200282
283 return EXIT_SUCCESS;
Michal Vasko98763c62015-07-17 13:47:00 +0200284}
285
Michal Vaskob3c31bd2017-07-17 10:01:48 +0200286static int
Radek Krejci46180b52016-08-31 16:01:32 +0200287json_print_leaf_list(struct lyout *out, int level, const struct lyd_node *node, int is_list, int toplevel, int options)
Michal Vasko98763c62015-07-17 13:47:00 +0200288{
Radek Krejcida61fb22015-10-30 11:10:03 +0100289 const char *schema = NULL;
Michal Vasko1e62a092015-12-01 12:27:20 +0100290 const struct lyd_node *list = node;
Radek Krejcida61fb22015-10-30 11:10:03 +0100291 int flag_empty = 0, flag_attrs = 0;
Radek Krejci23238922015-10-27 17:13:34 +0100292
Radek Krejcie8775162016-09-14 13:08:58 +0200293 if (is_list && !list->child) {
Radek Krejci23238922015-10-27 17:13:34 +0100294 /* empty, e.g. in case of filter */
295 flag_empty = 1;
296 }
Michal Vasko98763c62015-07-17 13:47:00 +0200297
Michal Vasko635bd452016-05-18 13:26:55 +0200298 if (toplevel || !node->parent || nscmp(node, node->parent)) {
Michal Vasko98763c62015-07-17 13:47:00 +0200299 /* print "namespace" */
Michal Vasko6c629ac2016-02-15 14:08:23 +0100300 schema = lys_node_module(node->schema)->name;
Radek Krejci23238922015-10-27 17:13:34 +0100301 ly_print(out, "%*s\"%s:%s\":", LEVEL, INDENT, schema, node->schema->name);
Michal Vasko98763c62015-07-17 13:47:00 +0200302 } else {
Radek Krejci23238922015-10-27 17:13:34 +0100303 ly_print(out, "%*s\"%s\":", LEVEL, INDENT, node->schema->name);
Michal Vasko98763c62015-07-17 13:47:00 +0200304 }
305
Radek Krejci23238922015-10-27 17:13:34 +0100306 if (flag_empty) {
Michal Vasko95068c42016-03-24 14:58:11 +0100307 ly_print(out, "%snull", (level ? " " : ""));
Michal Vaskob3c31bd2017-07-17 10:01:48 +0200308 return EXIT_SUCCESS;
Radek Krejci23238922015-10-27 17:13:34 +0100309 }
Michal Vasko95068c42016-03-24 14:58:11 +0100310 ly_print(out, "%s[%s", (level ? " " : ""), (level ? "\n" : ""));
Radek Krejci23238922015-10-27 17:13:34 +0100311
Michal Vasko95068c42016-03-24 14:58:11 +0100312 if (!is_list && level) {
Michal Vasko98763c62015-07-17 13:47:00 +0200313 ++level;
314 }
Radek Krejci27aaa732015-09-04 15:24:04 +0200315
316 while (list) {
Michal Vasko98763c62015-07-17 13:47:00 +0200317 if (is_list) {
Radek Krejci27aaa732015-09-04 15:24:04 +0200318 /* list print */
Michal Vasko95068c42016-03-24 14:58:11 +0100319 if (level) {
320 ++level;
321 }
322 ly_print(out, "%*s{%s", LEVEL, INDENT, (level ? "\n" : ""));
323 if (level) {
324 ++level;
325 }
Radek Krejcida61fb22015-10-30 11:10:03 +0100326 if (list->attr) {
Michal Vasko95068c42016-03-24 14:58:11 +0100327 ly_print(out, "%*s\"@\":%s{%s", LEVEL, INDENT, (level ? " " : ""), (level ? "\n" : ""));
Michal Vaskob3c31bd2017-07-17 10:01:48 +0200328 if (json_print_attrs(out, (level ? level + 1 : level), list, NULL)) {
329 return EXIT_FAILURE;
330 }
Michal Vaskof6aa8612017-03-02 10:52:44 +0100331 if (list->child) {
332 ly_print(out, "%*s},%s", LEVEL, INDENT, (level ? "\n" : ""));
333 } else {
334 ly_print(out, "%*s}", LEVEL, INDENT);
335 }
Radek Krejcida61fb22015-10-30 11:10:03 +0100336 }
Michal Vaskob3c31bd2017-07-17 10:01:48 +0200337 if (json_print_nodes(out, level, list->child, 1, 0, options)) {
338 return EXIT_FAILURE;
339 }
Michal Vasko95068c42016-03-24 14:58:11 +0100340 if (level) {
341 --level;
342 }
Radek Krejci76b07902015-10-09 09:11:25 +0200343 ly_print(out, "%*s}", LEVEL, INDENT);
Michal Vasko95068c42016-03-24 14:58:11 +0100344 if (level) {
345 --level;
346 }
Michal Vasko98763c62015-07-17 13:47:00 +0200347 } else {
Radek Krejci27aaa732015-09-04 15:24:04 +0200348 /* leaf-list print */
Radek Krejci76b07902015-10-09 09:11:25 +0200349 ly_print(out, "%*s", LEVEL, INDENT);
Michal Vaskob3c31bd2017-07-17 10:01:48 +0200350 if (json_print_leaf(out, level, list, 1, toplevel, options)) {
351 return EXIT_FAILURE;
352 }
Radek Krejcida61fb22015-10-30 11:10:03 +0100353 if (list->attr) {
354 flag_attrs = 1;
355 }
Radek Krejci27aaa732015-09-04 15:24:04 +0200356 }
357 for (list = list->next; list && list->schema != node->schema; list = list->next);
358 if (list) {
Michal Vasko95068c42016-03-24 14:58:11 +0100359 ly_print(out, ",%s", (level ? "\n" : ""));
Michal Vasko98763c62015-07-17 13:47:00 +0200360 }
361 }
Radek Krejci27aaa732015-09-04 15:24:04 +0200362
Michal Vasko95068c42016-03-24 14:58:11 +0100363 if (!is_list && level) {
Michal Vasko98763c62015-07-17 13:47:00 +0200364 --level;
365 }
366
Michal Vasko95068c42016-03-24 14:58:11 +0100367 ly_print(out, "%s%*s]", (level ? "\n" : ""), LEVEL, INDENT);
Radek Krejcida61fb22015-10-30 11:10:03 +0100368
369 /* attributes */
370 if (!is_list && flag_attrs) {
371 if (schema) {
Michal Vasko95068c42016-03-24 14:58:11 +0100372 ly_print(out, ",%s%*s\"@%s:%s\":%s[%s", (level ? "\n" : ""), LEVEL, INDENT, schema, node->schema->name,
373 (level ? " " : ""), (level ? "\n" : ""));
Radek Krejcida61fb22015-10-30 11:10:03 +0100374 } else {
Michal Vasko95068c42016-03-24 14:58:11 +0100375 ly_print(out, ",%s%*s\"@%s\":%s[%s", (level ? "\n" : ""), LEVEL, INDENT, node->schema->name,
376 (level ? " " : ""), (level ? "\n" : ""));
Radek Krejcida61fb22015-10-30 11:10:03 +0100377 }
Michal Vasko95068c42016-03-24 14:58:11 +0100378 if (level) {
379 level++;
380 }
Radek Krejcida61fb22015-10-30 11:10:03 +0100381 for (list = node; list; ) {
382 if (list->attr) {
Michal Vasko95068c42016-03-24 14:58:11 +0100383 ly_print(out, "%*s{%s", LEVEL, INDENT, (level ? " " : ""));
Michal Vaskob3c31bd2017-07-17 10:01:48 +0200384 if (json_print_attrs(out, 0, list, NULL)) {
385 return EXIT_FAILURE;
386 }
Radek Krejcida61fb22015-10-30 11:10:03 +0100387 ly_print(out, "%*s}", LEVEL, INDENT);
388 } else {
389 ly_print(out, "%*snull", LEVEL, INDENT);
390 }
391
392
393 for (list = list->next; list && list->schema != node->schema; list = list->next);
394 if (list) {
Michal Vasko95068c42016-03-24 14:58:11 +0100395 ly_print(out, ",%s", (level ? "\n" : ""));
Radek Krejcida61fb22015-10-30 11:10:03 +0100396 }
397 }
Michal Vasko95068c42016-03-24 14:58:11 +0100398 if (level) {
399 level--;
400 }
401 ly_print(out, "%s%*s]", (level ? "\n" : ""), LEVEL, INDENT);
Radek Krejcida61fb22015-10-30 11:10:03 +0100402 }
Michal Vaskob3c31bd2017-07-17 10:01:48 +0200403
404 return EXIT_SUCCESS;
Michal Vasko98763c62015-07-17 13:47:00 +0200405}
406
Michal Vaskob3c31bd2017-07-17 10:01:48 +0200407static int
Radek Krejcia7177672016-11-17 14:53:03 +0900408json_print_anyxml(struct lyout *out, int level, const struct lyd_node *node, int toplevel, int options)
409{
410 struct lyd_node_anydata *any = (struct lyd_node_anydata *)node;
411 int isobject = 0;
412 char *buf;
413 const char *schema = NULL;
414
415 if (toplevel || !node->parent || nscmp(node, node->parent)) {
416 /* print "namespace" */
417 schema = lys_node_module(node->schema)->name;
418 ly_print(out, "%*s\"%s:%s\":%s", LEVEL, INDENT, schema, node->schema->name, (level ? " " : ""));
419 } else {
420 ly_print(out, "%*s\"%s\":%s", LEVEL, INDENT, node->schema->name, (level ? " " : ""));
421 }
422 if (level) {
423 level++;
424 }
425
426 switch (any->value_type) {
427 case LYD_ANYDATA_DATATREE:
428 isobject = 1;
429 ly_print(out, level ? "{\n" : "{");
Radek Krejcidb2f58c2016-11-24 11:24:48 +0100430 /* do not print any default values nor empty containers */
Michal Vaskob3c31bd2017-07-17 10:01:48 +0200431 if (json_print_nodes(out, level, any->value.tree, 1, 0, LYP_WITHSIBLINGS | (options & ~LYP_NETCONF))) {
432 return EXIT_FAILURE;
433 }
Radek Krejcia7177672016-11-17 14:53:03 +0900434 break;
435 case LYD_ANYDATA_JSON:
436 isobject = 1;
437 ly_print(out, level ? "{\n" : "{");
438 if (any->value.str) {
439 ly_print(out, "%*s%s%s", LEVEL, INDENT, any->value.str, level ? "\n" : "");
440 }
441 break;
442 case LYD_ANYDATA_XML:
443 lyxml_print_mem(&buf, any->value.xml, (level ? LYXML_PRINT_FORMAT | LYXML_PRINT_NO_LAST_NEWLINE : 0)
444 | LYXML_PRINT_SIBLINGS);
445 json_print_string(out, buf);
446 free(buf);
447 break;
448 case LYD_ANYDATA_CONSTSTRING:
449 case LYD_ANYDATA_SXML:
450 if (any->value.str) {
451 json_print_string(out, any->value.str);
452 } else {
453 ly_print(out, "\"\"");
454 }
455 break;
456 default:
457 /* other formats are not supported */
Michal Vasko53b7da02018-02-13 15:28:42 +0100458 LOGWRN(node->schema->module->ctx, "Unable to print anydata content (type %d) as JSON.", any->value_type);
Radek Krejcia7177672016-11-17 14:53:03 +0900459 break;
460 }
461
462 if (level) {
463 level--;
464 }
465 if (isobject) {
466 ly_print(out, "%*s}", LEVEL, INDENT);
467 }
Michal Vaskob3c31bd2017-07-17 10:01:48 +0200468
469 return EXIT_SUCCESS;
Radek Krejcia7177672016-11-17 14:53:03 +0900470}
471
Michal Vaskob3c31bd2017-07-17 10:01:48 +0200472static int
Radek Krejci46180b52016-08-31 16:01:32 +0200473json_print_anydata(struct lyout *out, int level, const struct lyd_node *node, int toplevel, int options)
Michal Vaskoab8e4402015-07-17 12:54:28 +0200474{
Radek Krejcida61fb22015-10-30 11:10:03 +0100475 const char *schema = NULL;
Radek Krejcibf2abff2016-08-23 15:51:52 +0200476 struct lyd_node_anydata *any = (struct lyd_node_anydata *)node;
Radek Krejcida61fb22015-10-30 11:10:03 +0100477
Michal Vasko635bd452016-05-18 13:26:55 +0200478 if (toplevel || !node->parent || nscmp(node, node->parent)) {
Radek Krejcida61fb22015-10-30 11:10:03 +0100479 /* print "namespace" */
Michal Vasko6c629ac2016-02-15 14:08:23 +0100480 schema = lys_node_module(node->schema)->name;
Radek Krejci4ae82942016-09-19 16:41:06 +0200481 ly_print(out, "%*s\"%s:%s\":%s{%s", LEVEL, INDENT, schema, node->schema->name, (level ? " " : ""), (level ? "\n" : ""));
Radek Krejcida61fb22015-10-30 11:10:03 +0100482 } else {
Radek Krejci4ae82942016-09-19 16:41:06 +0200483 ly_print(out, "%*s\"%s\":%s{%s", LEVEL, INDENT, node->schema->name, (level ? " " : ""), (level ? "\n" : ""));
484 }
485 if (level) {
486 level++;
Radek Krejci9a5daea2016-03-02 16:49:40 +0100487 }
488
Radek Krejci4ae82942016-09-19 16:41:06 +0200489 switch (any->value_type) {
490 case LYD_ANYDATA_DATATREE:
Radek Krejcidb2f58c2016-11-24 11:24:48 +0100491 /* do not print any default values nor empty containers */
Michal Vaskob3c31bd2017-07-17 10:01:48 +0200492 if (json_print_nodes(out, level, any->value.tree, 1, 0, LYP_WITHSIBLINGS | (options & LYP_FORMAT))) {
493 return EXIT_FAILURE;
494 }
Radek Krejci4ae82942016-09-19 16:41:06 +0200495 break;
496 case LYD_ANYDATA_JSON:
497 if (any->value.str) {
Michal Vaskof6aa8612017-03-02 10:52:44 +0100498 ly_print(out, "%*s%s%s", LEVEL, INDENT, any->value.str, (level ? "\n" : ""));
Radek Krejci9a5daea2016-03-02 16:49:40 +0100499 }
Radek Krejci4ae82942016-09-19 16:41:06 +0200500 break;
501 default:
502 /* other formats are not supported */
Michal Vasko53b7da02018-02-13 15:28:42 +0100503 LOGWRN(node->schema->module->ctx, "Unable to print anydata content (type %d) as JSON.", any->value_type);
Radek Krejci4ae82942016-09-19 16:41:06 +0200504 break;
Radek Krejcida61fb22015-10-30 11:10:03 +0100505 }
506
507 /* print attributes as sibling leaf */
508 if (node->attr) {
Radek Krejcida61fb22015-10-30 11:10:03 +0100509 if (schema) {
Michal Vaskof6aa8612017-03-02 10:52:44 +0100510 ly_print(out, ",%s%*s\"@%s:%s\":%s{%s", (level ? "\n" : ""), LEVEL, INDENT, schema, node->schema->name,
511 (level ? " " : ""), (level ? "\n" : ""));
Radek Krejcida61fb22015-10-30 11:10:03 +0100512 } else {
Michal Vaskof6aa8612017-03-02 10:52:44 +0100513 ly_print(out, ",%s%*s\"@%s\":%s{%s", (level ? "\n" : ""), LEVEL, INDENT, node->schema->name,
514 (level ? " " : ""), (level ? "\n" : ""));
Radek Krejcida61fb22015-10-30 11:10:03 +0100515 }
Michal Vaskob3c31bd2017-07-17 10:01:48 +0200516 if (json_print_attrs(out, (level ? level + 1 : level), node, NULL)) {
517 return EXIT_FAILURE;
518 }
Radek Krejcida61fb22015-10-30 11:10:03 +0100519 ly_print(out, "%*s}", LEVEL, INDENT);
520 }
Radek Krejci4ae82942016-09-19 16:41:06 +0200521
Radek Krejci4ae82942016-09-19 16:41:06 +0200522 if (level) {
523 level--;
524 }
525 ly_print(out, "%*s}", LEVEL, INDENT);
Michal Vaskob3c31bd2017-07-17 10:01:48 +0200526
527 return EXIT_SUCCESS;
Michal Vaskoab8e4402015-07-17 12:54:28 +0200528}
529
Michal Vaskob3c31bd2017-07-17 10:01:48 +0200530static int
Radek Krejci46180b52016-08-31 16:01:32 +0200531json_print_nodes(struct lyout *out, int level, const struct lyd_node *root, int withsiblings, int toplevel, int options)
Radek Krejci94ca54b2015-07-08 15:48:47 +0200532{
Radek Krejcic90c6512018-02-14 15:21:19 +0100533 int ret = EXIT_SUCCESS,comma_flag = 0;
Radek Krejci572f1222016-09-01 09:52:47 +0200534 const struct lyd_node *node, *iter;
Radek Krejci27aaa732015-09-04 15:24:04 +0200535
536 LY_TREE_FOR(root, node) {
Radek Krejci572f1222016-09-01 09:52:47 +0200537 if (!lyd_wd_toprint(node, options)) {
Michal Vaskob3c31bd2017-07-17 10:01:48 +0200538 /* wd says do not print */
Radek Krejci572f1222016-09-01 09:52:47 +0200539 continue;
Radek Krejci46180b52016-08-31 16:01:32 +0200540 }
541
Radek Krejci27aaa732015-09-04 15:24:04 +0200542 switch (node->schema->nodetype) {
Radek Krejcifb54be42015-10-02 15:21:16 +0200543 case LYS_RPC:
Michal Vaskoafa7a642016-10-18 15:11:38 +0200544 case LYS_ACTION:
Radek Krejcifb54be42015-10-02 15:21:16 +0200545 case LYS_NOTIF:
Radek Krejci27aaa732015-09-04 15:24:04 +0200546 case LYS_CONTAINER:
Radek Krejcic90c6512018-02-14 15:21:19 +0100547 if (comma_flag) {
Radek Krejci27aaa732015-09-04 15:24:04 +0200548 /* print the previous comma */
Michal Vasko95068c42016-03-24 14:58:11 +0100549 ly_print(out, ",%s", (level ? "\n" : ""));
Radek Krejci27aaa732015-09-04 15:24:04 +0200550 }
Michal Vaskob3c31bd2017-07-17 10:01:48 +0200551 ret = json_print_container(out, level, node, toplevel, options);
Radek Krejci27aaa732015-09-04 15:24:04 +0200552 break;
553 case LYS_LEAF:
Radek Krejcic90c6512018-02-14 15:21:19 +0100554 if (comma_flag) {
Radek Krejci27aaa732015-09-04 15:24:04 +0200555 /* print the previous comma */
Michal Vasko95068c42016-03-24 14:58:11 +0100556 ly_print(out, ",%s", (level ? "\n" : ""));
Radek Krejci27aaa732015-09-04 15:24:04 +0200557 }
Michal Vaskob3c31bd2017-07-17 10:01:48 +0200558 ret = json_print_leaf(out, level, node, 0, toplevel, options);
Radek Krejci27aaa732015-09-04 15:24:04 +0200559 break;
560 case LYS_LEAFLIST:
561 case LYS_LIST:
562 /* is it already printed? */
Radek Krejci9ce61512015-10-26 14:42:32 +0100563 for (iter = node->prev; iter->next; iter = iter->prev) {
Radek Krejci27aaa732015-09-04 15:24:04 +0200564 if (iter == node) {
565 continue;
566 }
567 if (iter->schema == node->schema) {
568 /* the list has alread some previous instance and therefore it is already printed */
569 break;
570 }
571 }
Michal Vasko6c563772015-10-15 10:49:30 +0200572 if (!iter->next) {
Radek Krejcic90c6512018-02-14 15:21:19 +0100573 if (comma_flag) {
Radek Krejci27aaa732015-09-04 15:24:04 +0200574 /* print the previous comma */
Michal Vasko95068c42016-03-24 14:58:11 +0100575 ly_print(out, ",%s", (level ? "\n" : ""));
Radek Krejci27aaa732015-09-04 15:24:04 +0200576 }
577
578 /* print the list/leaflist */
Michal Vaskob3c31bd2017-07-17 10:01:48 +0200579 ret = json_print_leaf_list(out, level, node, node->schema->nodetype == LYS_LIST ? 1 : 0, toplevel, options);
Radek Krejci27aaa732015-09-04 15:24:04 +0200580 }
581 break;
582 case LYS_ANYXML:
Radek Krejcic90c6512018-02-14 15:21:19 +0100583 if (comma_flag) {
Radek Krejcia7177672016-11-17 14:53:03 +0900584 /* print the previous comma */
585 ly_print(out, ",%s", (level ? "\n" : ""));
586 }
Michal Vaskob3c31bd2017-07-17 10:01:48 +0200587 ret = json_print_anyxml(out, level, node, toplevel, options);
Radek Krejcia7177672016-11-17 14:53:03 +0900588 break;
Radek Krejcibf2abff2016-08-23 15:51:52 +0200589 case LYS_ANYDATA:
Radek Krejcic90c6512018-02-14 15:21:19 +0100590 if (comma_flag) {
Radek Krejci27aaa732015-09-04 15:24:04 +0200591 /* print the previous comma */
Michal Vasko95068c42016-03-24 14:58:11 +0100592 ly_print(out, ",%s", (level ? "\n" : ""));
Radek Krejci27aaa732015-09-04 15:24:04 +0200593 }
Michal Vaskob3c31bd2017-07-17 10:01:48 +0200594 ret = json_print_anydata(out, level, node, toplevel, options);
Radek Krejci27aaa732015-09-04 15:24:04 +0200595 break;
596 default:
Michal Vasko53b7da02018-02-13 15:28:42 +0100597 LOGINT(node->schema->module->ctx);
Michal Vaskob3c31bd2017-07-17 10:01:48 +0200598 ret = EXIT_FAILURE;
Radek Krejci27aaa732015-09-04 15:24:04 +0200599 break;
600 }
Radek Krejci5044be32016-01-18 17:05:51 +0100601
602 if (!withsiblings) {
603 break;
604 }
Radek Krejcic90c6512018-02-14 15:21:19 +0100605 comma_flag = 1;
Radek Krejci94ca54b2015-07-08 15:48:47 +0200606 }
Radek Krejci4ae82942016-09-19 16:41:06 +0200607 if (root && level) {
Michal Vasko95068c42016-03-24 14:58:11 +0100608 ly_print(out, "\n");
609 }
Michal Vaskob3c31bd2017-07-17 10:01:48 +0200610
611 return ret;
Radek Krejci94ca54b2015-07-08 15:48:47 +0200612}
613
Radek Krejcif3752b02015-10-02 15:31:34 +0200614int
Radek Krejci5044be32016-01-18 17:05:51 +0100615json_print_data(struct lyout *out, const struct lyd_node *root, int options)
Radek Krejci94ca54b2015-07-08 15:48:47 +0200616{
Michal Vaskoafa7a642016-10-18 15:11:38 +0200617 const struct lyd_node *node, *next;
618 int level = 0, action_input = 0;
Radek Krejci94ca54b2015-07-08 15:48:47 +0200619
Michal Vasko95068c42016-03-24 14:58:11 +0100620 if (options & LYP_FORMAT) {
621 ++level;
622 }
623
Michal Vaskoafa7a642016-10-18 15:11:38 +0200624 if (options & LYP_NETCONF) {
625 if (root->schema->nodetype != LYS_RPC) {
626 /* learn whether we are printing an action */
627 LY_TREE_DFS_BEGIN(root, next, node) {
628 if (node->schema->nodetype == LYS_ACTION) {
629 break;
630 }
631 LY_TREE_DFS_END(root, next, node);
632 }
633 } else {
634 node = root;
635 }
636
637 if (node && (node->schema->nodetype & (LYS_RPC | LYS_ACTION))) {
638 if (node->child && (node->child->schema->parent->nodetype == LYS_OUTPUT)) {
639 /* skip the container */
640 root = node->child;
641 } else if (node->schema->nodetype == LYS_ACTION) {
642 action_input = 1;
643 }
644 }
645 }
646
Radek Krejci94ca54b2015-07-08 15:48:47 +0200647 /* start */
Michal Vasko95068c42016-03-24 14:58:11 +0100648 ly_print(out, "{%s", (level ? "\n" : ""));
Radek Krejci94ca54b2015-07-08 15:48:47 +0200649
Michal Vaskoafa7a642016-10-18 15:11:38 +0200650 if (action_input) {
651 ly_print(out, "%*s\"yang:action\":%s{%s", LEVEL, INDENT, (level ? " " : ""), (level ? "\n" : ""));
652 if (level) {
653 ++level;
654 }
655 }
656
Radek Krejci94ca54b2015-07-08 15:48:47 +0200657 /* content */
Michal Vaskob3c31bd2017-07-17 10:01:48 +0200658 if (json_print_nodes(out, level, root, options & LYP_WITHSIBLINGS, 1, options)) {
659 return EXIT_FAILURE;
660 }
Radek Krejci94ca54b2015-07-08 15:48:47 +0200661
Michal Vaskoafa7a642016-10-18 15:11:38 +0200662 if (action_input) {
663 if (level) {
664 --level;
665 }
666 ly_print(out, "%*s}%s", LEVEL, INDENT, (level ? "\n" : ""));
667 }
668
Radek Krejci94ca54b2015-07-08 15:48:47 +0200669 /* end */
Michal Vasko95068c42016-03-24 14:58:11 +0100670 ly_print(out, "}%s", (level ? "\n" : ""));
Radek Krejci94ca54b2015-07-08 15:48:47 +0200671
Michal Vaskoafa7a642016-10-18 15:11:38 +0200672 ly_print_flush(out);
Radek Krejci94ca54b2015-07-08 15:48:47 +0200673 return EXIT_SUCCESS;
674}