blob: 23a6750c37b41f464e2c4e55c3c71561c279ea5c [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 Krejci0e67ac42018-07-25 15:46:37 +020033int
Radek Krejci382e7f92016-01-12 17:15:47 +010034json_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++) {
Jan Kundrátf5cbb962018-08-24 14:17:35 +020044 const unsigned char ascii = text[i];
45 if (ascii < 0x20) {
Radek Krejci382e7f92016-01-12 17:15:47 +010046 /* control character */
Jan Kundrátf5cbb962018-08-24 14:17:35 +020047 n += ly_print(out, "\\u%.4X", ascii);
Radek Krejci382e7f92016-01-12 17:15:47 +010048 } else {
Jan Kundrátf5cbb962018-08-24 14:17:35 +020049 switch (ascii) {
Radek Krejci382e7f92016-01-12 17:15:47 +010050 case '"':
51 n += ly_print(out, "\\\"");
52 break;
53 case '\\':
54 n += ly_print(out, "\\\\");
55 break;
56 default:
57 ly_write(out, &text[i], 1);
58 n++;
59 }
60 }
61 }
62 ly_write(out, "\"", 1);
63
64 return n + 2;
65}
66
Michal Vaskob3c31bd2017-07-17 10:01:48 +020067static int
Radek Krejci1eefeb32016-04-15 16:01:46 +020068json_print_attrs(struct lyout *out, int level, const struct lyd_node *node, const struct lys_module *wdmod)
Radek Krejcida61fb22015-10-30 11:10:03 +010069{
70 struct lyd_attr *attr;
Radek Krejcia571d942017-02-24 09:26:49 +010071 size_t len;
72 char *p;
Radek Krejcida61fb22015-10-30 11:10:03 +010073
Michal Vasko609d7082019-04-26 09:35:40 +020074 LY_PRINT_SET;
75
Radek Krejci1eefeb32016-04-15 16:01:46 +020076 if (wdmod) {
77 ly_print(out, "%*s\"%s:default\":\"true\"", LEVEL, INDENT, wdmod->name);
78 ly_print(out, "%s%s", node->attr ? "," : "", (level ? "\n" : ""));
79 }
Radek Krejcida61fb22015-10-30 11:10:03 +010080 for (attr = node->attr; attr; attr = attr->next) {
Radek Krejci532e5e92017-02-22 12:59:24 +010081 if (!attr->annotation) {
82 /* skip exception for the NETCONF's attribute since JSON is not defined for NETCONF */
83 continue;
84 }
Radek Krejcib1ef1872017-02-23 14:33:34 +010085 if (lys_main_module(attr->annotation->module) != lys_main_module(node->schema->module)) {
Radek Krejci532e5e92017-02-22 12:59:24 +010086 ly_print(out, "%*s\"%s:%s\":", LEVEL, INDENT, attr->annotation->module->name, attr->name);
Radek Krejcida61fb22015-10-30 11:10:03 +010087 } else {
Radek Krejci382e7f92016-01-12 17:15:47 +010088 ly_print(out, "%*s\"%s\":", LEVEL, INDENT, attr->name);
Radek Krejcida61fb22015-10-30 11:10:03 +010089 }
Radek Krejcia571d942017-02-24 09:26:49 +010090 /* leafref is not supported */
Michal Vasko70bf8e52018-03-26 11:32:33 +020091 switch (attr->value_type) {
Radek Krejcia571d942017-02-24 09:26:49 +010092 case LY_TYPE_BINARY:
93 case LY_TYPE_STRING:
94 case LY_TYPE_BITS:
95 case LY_TYPE_ENUM:
96 case LY_TYPE_INST:
97 case LY_TYPE_INT64:
98 case LY_TYPE_UINT64:
99 case LY_TYPE_DEC64:
Michal Vaskoa80d8302017-03-02 10:52:02 +0100100 json_print_string(out, attr->value_str);
Radek Krejcia571d942017-02-24 09:26:49 +0100101 break;
102
103 case LY_TYPE_INT8:
104 case LY_TYPE_INT16:
105 case LY_TYPE_INT32:
106 case LY_TYPE_UINT8:
107 case LY_TYPE_UINT16:
108 case LY_TYPE_UINT32:
109 case LY_TYPE_BOOL:
110 ly_print(out, "%s", attr->value_str[0] ? attr->value_str : "null");
111 break;
112
113 case LY_TYPE_IDENT:
114 p = strchr(attr->value_str, ':');
115 assert(p);
116 len = p - attr->value_str;
117 if (!strncmp(attr->value_str, attr->annotation->module->name, len)
118 && !attr->annotation->module->name[len]) {
119 /* do not print the prefix, it is the default prefix for this node */
120 json_print_string(out, ++p);
121 } else {
122 json_print_string(out, attr->value_str);
123 }
124 break;
125
126 case LY_TYPE_EMPTY:
127 ly_print(out, "[null]");
128 break;
129
130 default:
131 /* error */
Michal Vasko609d7082019-04-26 09:35:40 +0200132 LOGINT(node->schema->module->ctx);
Michal Vaskob3c31bd2017-07-17 10:01:48 +0200133 return EXIT_FAILURE;
Radek Krejcia571d942017-02-24 09:26:49 +0100134 }
135
Michal Vasko95068c42016-03-24 14:58:11 +0100136 ly_print(out, "%s%s", attr->next ? "," : "", (level ? "\n" : ""));
Radek Krejcida61fb22015-10-30 11:10:03 +0100137 }
Michal Vaskob3c31bd2017-07-17 10:01:48 +0200138
Michal Vasko609d7082019-04-26 09:35:40 +0200139 LY_PRINT_RET(node->schema->module->ctx);
Radek Krejcida61fb22015-10-30 11:10:03 +0100140}
141
Michal Vaskob3c31bd2017-07-17 10:01:48 +0200142static int
Radek Krejci46180b52016-08-31 16:01:32 +0200143json_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 +0200144{
Michal Vaskoe3886bb2017-01-02 11:33:28 +0100145 struct lyd_node_leaf_list *leaf = (struct lyd_node_leaf_list *)node, *iter;
Michal Vasko0bff3222017-01-05 10:55:31 +0100146 const struct lys_type *type;
Radek Krejci7a2a5622016-12-05 13:32:05 +0100147 const char *schema = NULL, *p, *mod_name;
Radek Krejci1eefeb32016-04-15 16:01:46 +0200148 const struct lys_module *wdmod = NULL;
Radek Krejci9b6aad22016-09-20 15:55:51 +0200149 LY_DATA_TYPE datatype;
Radek Krejci7a2a5622016-12-05 13:32:05 +0100150 size_t len;
Radek Krejci1eefeb32016-04-15 16:01:46 +0200151
Michal Vasko609d7082019-04-26 09:35:40 +0200152 LY_PRINT_SET;
153
Radek Krejci46180b52016-08-31 16:01:32 +0200154 if ((node->dflt && (options & (LYP_WD_ALL_TAG | LYP_WD_IMPL_TAG))) ||
155 (!node->dflt && (options & LYP_WD_ALL_TAG) && lyd_wd_default(leaf))) {
156 /* we have implicit OR explicit default node */
Radek Krejci1eefeb32016-04-15 16:01:46 +0200157 /* get with-defaults module */
Radek Krejcidfb00d62017-09-06 09:39:35 +0200158 wdmod = ly_ctx_get_module(node->schema->module->ctx, "ietf-netconf-with-defaults", NULL, 1);
Radek Krejci1eefeb32016-04-15 16:01:46 +0200159 }
Radek Krejci94ca54b2015-07-08 15:48:47 +0200160
Radek Krejci5a988152015-07-15 11:16:26 +0200161 if (!onlyvalue) {
Michal Vasko635bd452016-05-18 13:26:55 +0200162 if (toplevel || !node->parent || nscmp(node, node->parent)) {
Radek Krejci5a988152015-07-15 11:16:26 +0200163 /* print "namespace" */
Michal Vasko6c629ac2016-02-15 14:08:23 +0100164 schema = lys_node_module(node->schema)->name;
Michal Vasko95068c42016-03-24 14:58:11 +0100165 ly_print(out, "%*s\"%s:%s\":%s", LEVEL, INDENT, schema, node->schema->name, (level ? " " : ""));
Radek Krejci94ca54b2015-07-08 15:48:47 +0200166 } else {
Michal Vasko95068c42016-03-24 14:58:11 +0100167 ly_print(out, "%*s\"%s\":%s", LEVEL, INDENT, node->schema->name, (level ? " " : ""));
Radek Krejci94ca54b2015-07-08 15:48:47 +0200168 }
Radek Krejci94ca54b2015-07-08 15:48:47 +0200169 }
Radek Krejcie4748472015-07-08 18:00:22 +0200170
Michal Vasko70bf8e52018-03-26 11:32:33 +0200171 datatype = leaf->value_type;
Radek Krejci9b6aad22016-09-20 15:55:51 +0200172contentprint:
173 switch (datatype) {
Radek Krejcie4748472015-07-08 18:00:22 +0200174 case LY_TYPE_BINARY:
175 case LY_TYPE_STRING:
Radek Krejci3e3affe2015-07-09 15:38:40 +0200176 case LY_TYPE_BITS:
Radek Krejci5b315a92015-07-10 13:18:45 +0200177 case LY_TYPE_ENUM:
Radek Krejcic5090c32015-08-12 09:46:19 +0200178 case LY_TYPE_INST:
Radek Krejcic27114c2016-09-20 10:02:28 +0200179 case LY_TYPE_INT64:
180 case LY_TYPE_UINT64:
Michal Vasko3db69682018-03-27 16:11:31 +0200181 case LY_TYPE_UNION:
严军喜100794891758ff62016-10-25 10:14:47 +0800182 case LY_TYPE_DEC64:
Michal Vasko44913842016-04-13 14:20:41 +0200183 json_print_string(out, leaf->value_str);
Radek Krejciac8aac62015-07-10 15:36:35 +0200184 break;
Radek Krejcib1c12512015-08-11 11:22:04 +0200185
Radek Krejcib1c12512015-08-11 11:22:04 +0200186 case LY_TYPE_INT8:
187 case LY_TYPE_INT16:
188 case LY_TYPE_INT32:
Radek Krejcib1c12512015-08-11 11:22:04 +0200189 case LY_TYPE_UINT8:
190 case LY_TYPE_UINT16:
191 case LY_TYPE_UINT32:
严军喜100794891758ff62016-10-25 10:14:47 +0800192 case LY_TYPE_BOOL:
Michal Vasko44913842016-04-13 14:20:41 +0200193 ly_print(out, "%s", leaf->value_str[0] ? leaf->value_str : "null");
Radek Krejcib1c12512015-08-11 11:22:04 +0200194 break;
195
Radek Krejci7a2a5622016-12-05 13:32:05 +0100196 case LY_TYPE_IDENT:
197 p = strchr(leaf->value_str, ':');
198 assert(p);
199 len = p - leaf->value_str;
200 mod_name = leaf->schema->module->name;
201 if (!strncmp(leaf->value_str, mod_name, len) && !mod_name[len]) {
202 /* do not print the prefix, it is the default prefix for this node */
203 json_print_string(out, ++p);
204 } else {
205 json_print_string(out, leaf->value_str);
206 }
207 break;
208
Radek Krejci9b6aad22016-09-20 15:55:51 +0200209 case LY_TYPE_LEAFREF:
Michal Vaskoe3886bb2017-01-02 11:33:28 +0100210 iter = (struct lyd_node_leaf_list *)leaf->value.leafref;
211 while (iter && (iter->value_type == LY_TYPE_LEAFREF)) {
212 iter = (struct lyd_node_leaf_list *)iter->value.leafref;
213 }
214 if (!iter) {
Michal Vasko0bff3222017-01-05 10:55:31 +0100215 /* unresolved and invalid, but we can learn the correct type anyway */
216 type = lyd_leaf_type((struct lyd_node_leaf_list *)leaf);
217 if (!type) {
218 /* error */
Michal Vaskob3c31bd2017-07-17 10:01:48 +0200219 return EXIT_FAILURE;
Michal Vasko0bff3222017-01-05 10:55:31 +0100220 }
221 datatype = type->base;
Michal Vaskoe3886bb2017-01-02 11:33:28 +0100222 } else {
Michal Vasko70bf8e52018-03-26 11:32:33 +0200223 datatype = iter->value_type;
Radek Krejci9ad23f42016-10-31 15:46:52 +0100224 }
Michal Vasko0bff3222017-01-05 10:55:31 +0100225 goto contentprint;
Radek Krejci9b6aad22016-09-20 15:55:51 +0200226
Radek Krejcib1c12512015-08-11 11:22:04 +0200227 case LY_TYPE_EMPTY:
Radek Krejci76b07902015-10-09 09:11:25 +0200228 ly_print(out, "[null]");
Michal Vasko58110162015-07-15 15:50:16 +0200229 break;
Radek Krejcib1c12512015-08-11 11:22:04 +0200230
Radek Krejcie4748472015-07-08 18:00:22 +0200231 default:
Michal Vasko493bea72015-07-16 16:08:12 +0200232 /* error */
Michal Vasko609d7082019-04-26 09:35:40 +0200233 LOGINT(node->schema->module->ctx);
Michal Vaskob3c31bd2017-07-17 10:01:48 +0200234 return EXIT_FAILURE;
Radek Krejcie4748472015-07-08 18:00:22 +0200235 }
236
Radek Krejci382e7f92016-01-12 17:15:47 +0100237 /* print attributes as sibling leafs */
Radek Krejci1eefeb32016-04-15 16:01:46 +0200238 if (!onlyvalue && (node->attr || wdmod)) {
Radek Krejcida61fb22015-10-30 11:10:03 +0100239 if (schema) {
Michal Vasko95068c42016-03-24 14:58:11 +0100240 ly_print(out, ",%s%*s\"@%s:%s\":%s{%s", (level ? "\n" : ""), LEVEL, INDENT, schema, node->schema->name,
241 (level ? " " : ""), (level ? "\n" : ""));
Radek Krejcida61fb22015-10-30 11:10:03 +0100242 } else {
Michal Vasko95068c42016-03-24 14:58:11 +0100243 ly_print(out, ",%s%*s\"@%s\":%s{%s", (level ? "\n" : ""), LEVEL, INDENT, node->schema->name,
244 (level ? " " : ""), (level ? "\n" : ""));
Radek Krejcida61fb22015-10-30 11:10:03 +0100245 }
Michal Vaskob3c31bd2017-07-17 10:01:48 +0200246 if (json_print_attrs(out, (level ? level + 1 : level), node, wdmod)) {
247 return EXIT_FAILURE;
248 }
Radek Krejcida61fb22015-10-30 11:10:03 +0100249 ly_print(out, "%*s}", LEVEL, INDENT);
250 }
251
Michal Vasko609d7082019-04-26 09:35:40 +0200252 LY_PRINT_RET(node->schema->module->ctx);
Radek Krejci94ca54b2015-07-08 15:48:47 +0200253}
254
Michal Vaskob3c31bd2017-07-17 10:01:48 +0200255static int
Radek Krejci46180b52016-08-31 16:01:32 +0200256json_print_container(struct lyout *out, int level, const struct lyd_node *node, int toplevel, int options)
Michal Vasko98763c62015-07-17 13:47:00 +0200257{
258 const char *schema;
Michal Vasko98763c62015-07-17 13:47:00 +0200259
Michal Vasko609d7082019-04-26 09:35:40 +0200260 LY_PRINT_SET;
261
Michal Vasko635bd452016-05-18 13:26:55 +0200262 if (toplevel || !node->parent || nscmp(node, node->parent)) {
Michal Vasko98763c62015-07-17 13:47:00 +0200263 /* print "namespace" */
Michal Vasko6c629ac2016-02-15 14:08:23 +0100264 schema = lys_node_module(node->schema)->name;
Michal Vasko95068c42016-03-24 14:58:11 +0100265 ly_print(out, "%*s\"%s:%s\":%s{%s", LEVEL, INDENT, schema, node->schema->name, (level ? " " : ""), (level ? "\n" : ""));
Michal Vasko98763c62015-07-17 13:47:00 +0200266 } else {
Michal Vasko95068c42016-03-24 14:58:11 +0100267 ly_print(out, "%*s\"%s\":%s{%s", LEVEL, INDENT, node->schema->name, (level ? " " : ""), (level ? "\n" : ""));
Michal Vasko98763c62015-07-17 13:47:00 +0200268 }
Michal Vasko95068c42016-03-24 14:58:11 +0100269 if (level) {
270 level++;
271 }
Radek Krejcida61fb22015-10-30 11:10:03 +0100272 if (node->attr) {
Michal Vasko95068c42016-03-24 14:58:11 +0100273 ly_print(out, "%*s\"@\":%s{%s", LEVEL, INDENT, (level ? " " : ""), (level ? "\n" : ""));
Michal Vaskob3c31bd2017-07-17 10:01:48 +0200274 if (json_print_attrs(out, (level ? level + 1 : level), node, NULL)) {
275 return EXIT_FAILURE;
276 }
Michal Vasko95068c42016-03-24 14:58:11 +0100277 ly_print(out, "%*s}", LEVEL, INDENT);
278 if (node->child) {
279 ly_print(out, ",%s", (level ? "\n" : ""));
280 }
Radek Krejcida61fb22015-10-30 11:10:03 +0100281 }
Michal Vaskob3c31bd2017-07-17 10:01:48 +0200282 if (json_print_nodes(out, level, node->child, 1, 0, options)) {
283 return EXIT_FAILURE;
284 }
Michal Vasko95068c42016-03-24 14:58:11 +0100285 if (level) {
286 level--;
287 }
Radek Krejci76b07902015-10-09 09:11:25 +0200288 ly_print(out, "%*s}", LEVEL, INDENT);
Michal Vaskob3c31bd2017-07-17 10:01:48 +0200289
Michal Vasko609d7082019-04-26 09:35:40 +0200290 LY_PRINT_RET(node->schema->module->ctx);
Michal Vasko98763c62015-07-17 13:47:00 +0200291}
292
Michal Vaskob3c31bd2017-07-17 10:01:48 +0200293static int
Radek Krejci46180b52016-08-31 16:01:32 +0200294json_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 +0200295{
Radek Krejcida61fb22015-10-30 11:10:03 +0100296 const char *schema = NULL;
Michal Vasko1e62a092015-12-01 12:27:20 +0100297 const struct lyd_node *list = node;
Radek Krejcida61fb22015-10-30 11:10:03 +0100298 int flag_empty = 0, flag_attrs = 0;
Radek Krejci23238922015-10-27 17:13:34 +0100299
Michal Vasko609d7082019-04-26 09:35:40 +0200300 LY_PRINT_SET;
301
Radek Krejcie8775162016-09-14 13:08:58 +0200302 if (is_list && !list->child) {
Radek Krejci23238922015-10-27 17:13:34 +0100303 /* empty, e.g. in case of filter */
304 flag_empty = 1;
305 }
Michal Vasko98763c62015-07-17 13:47:00 +0200306
Michal Vasko635bd452016-05-18 13:26:55 +0200307 if (toplevel || !node->parent || nscmp(node, node->parent)) {
Michal Vasko98763c62015-07-17 13:47:00 +0200308 /* print "namespace" */
Michal Vasko6c629ac2016-02-15 14:08:23 +0100309 schema = lys_node_module(node->schema)->name;
Radek Krejci23238922015-10-27 17:13:34 +0100310 ly_print(out, "%*s\"%s:%s\":", LEVEL, INDENT, schema, node->schema->name);
Michal Vasko98763c62015-07-17 13:47:00 +0200311 } else {
Radek Krejci23238922015-10-27 17:13:34 +0100312 ly_print(out, "%*s\"%s\":", LEVEL, INDENT, node->schema->name);
Michal Vasko98763c62015-07-17 13:47:00 +0200313 }
314
Radek Krejci23238922015-10-27 17:13:34 +0100315 if (flag_empty) {
Michal Vasko95068c42016-03-24 14:58:11 +0100316 ly_print(out, "%snull", (level ? " " : ""));
Michal Vasko609d7082019-04-26 09:35:40 +0200317 goto finish;
Radek Krejci23238922015-10-27 17:13:34 +0100318 }
Michal Vasko95068c42016-03-24 14:58:11 +0100319 ly_print(out, "%s[%s", (level ? " " : ""), (level ? "\n" : ""));
Radek Krejci23238922015-10-27 17:13:34 +0100320
Michal Vasko95068c42016-03-24 14:58:11 +0100321 if (!is_list && level) {
Michal Vasko98763c62015-07-17 13:47:00 +0200322 ++level;
323 }
Radek Krejci27aaa732015-09-04 15:24:04 +0200324
325 while (list) {
Michal Vasko98763c62015-07-17 13:47:00 +0200326 if (is_list) {
Radek Krejci27aaa732015-09-04 15:24:04 +0200327 /* list print */
Michal Vasko95068c42016-03-24 14:58:11 +0100328 if (level) {
329 ++level;
330 }
331 ly_print(out, "%*s{%s", LEVEL, INDENT, (level ? "\n" : ""));
332 if (level) {
333 ++level;
334 }
Radek Krejcida61fb22015-10-30 11:10:03 +0100335 if (list->attr) {
Michal Vasko95068c42016-03-24 14:58:11 +0100336 ly_print(out, "%*s\"@\":%s{%s", LEVEL, INDENT, (level ? " " : ""), (level ? "\n" : ""));
Michal Vaskob3c31bd2017-07-17 10:01:48 +0200337 if (json_print_attrs(out, (level ? level + 1 : level), list, NULL)) {
338 return EXIT_FAILURE;
339 }
Michal Vaskof6aa8612017-03-02 10:52:44 +0100340 if (list->child) {
341 ly_print(out, "%*s},%s", LEVEL, INDENT, (level ? "\n" : ""));
342 } else {
343 ly_print(out, "%*s}", LEVEL, INDENT);
344 }
Radek Krejcida61fb22015-10-30 11:10:03 +0100345 }
Michal Vaskob3c31bd2017-07-17 10:01:48 +0200346 if (json_print_nodes(out, level, list->child, 1, 0, options)) {
347 return EXIT_FAILURE;
348 }
Michal Vasko95068c42016-03-24 14:58:11 +0100349 if (level) {
350 --level;
351 }
Radek Krejci76b07902015-10-09 09:11:25 +0200352 ly_print(out, "%*s}", LEVEL, INDENT);
Michal Vasko95068c42016-03-24 14:58:11 +0100353 if (level) {
354 --level;
355 }
Michal Vasko98763c62015-07-17 13:47:00 +0200356 } else {
Radek Krejci27aaa732015-09-04 15:24:04 +0200357 /* leaf-list print */
Radek Krejci76b07902015-10-09 09:11:25 +0200358 ly_print(out, "%*s", LEVEL, INDENT);
Michal Vaskob3c31bd2017-07-17 10:01:48 +0200359 if (json_print_leaf(out, level, list, 1, toplevel, options)) {
360 return EXIT_FAILURE;
361 }
Radek Krejcida61fb22015-10-30 11:10:03 +0100362 if (list->attr) {
363 flag_attrs = 1;
364 }
Radek Krejci27aaa732015-09-04 15:24:04 +0200365 }
Alexandre Snarskiice16bcf2018-09-12 12:10:07 +0300366 if (toplevel && !(options & LYP_WITHSIBLINGS)) {
367 /* if initially called without LYP_WITHSIBLINGS do not print other list entries */
368 break;
369 }
Radek Krejci27aaa732015-09-04 15:24:04 +0200370 for (list = list->next; list && list->schema != node->schema; list = list->next);
371 if (list) {
Michal Vasko95068c42016-03-24 14:58:11 +0100372 ly_print(out, ",%s", (level ? "\n" : ""));
Michal Vasko98763c62015-07-17 13:47:00 +0200373 }
374 }
Radek Krejci27aaa732015-09-04 15:24:04 +0200375
Michal Vasko95068c42016-03-24 14:58:11 +0100376 if (!is_list && level) {
Michal Vasko98763c62015-07-17 13:47:00 +0200377 --level;
378 }
379
Michal Vasko95068c42016-03-24 14:58:11 +0100380 ly_print(out, "%s%*s]", (level ? "\n" : ""), LEVEL, INDENT);
Radek Krejcida61fb22015-10-30 11:10:03 +0100381
382 /* attributes */
383 if (!is_list && flag_attrs) {
384 if (schema) {
Michal Vasko95068c42016-03-24 14:58:11 +0100385 ly_print(out, ",%s%*s\"@%s:%s\":%s[%s", (level ? "\n" : ""), LEVEL, INDENT, schema, node->schema->name,
386 (level ? " " : ""), (level ? "\n" : ""));
Radek Krejcida61fb22015-10-30 11:10:03 +0100387 } else {
Michal Vasko95068c42016-03-24 14:58:11 +0100388 ly_print(out, ",%s%*s\"@%s\":%s[%s", (level ? "\n" : ""), LEVEL, INDENT, node->schema->name,
389 (level ? " " : ""), (level ? "\n" : ""));
Radek Krejcida61fb22015-10-30 11:10:03 +0100390 }
Michal Vasko95068c42016-03-24 14:58:11 +0100391 if (level) {
392 level++;
393 }
Radek Krejcida61fb22015-10-30 11:10:03 +0100394 for (list = node; list; ) {
395 if (list->attr) {
Michal Vasko95068c42016-03-24 14:58:11 +0100396 ly_print(out, "%*s{%s", LEVEL, INDENT, (level ? " " : ""));
Michal Vaskob3c31bd2017-07-17 10:01:48 +0200397 if (json_print_attrs(out, 0, list, NULL)) {
398 return EXIT_FAILURE;
399 }
Radek Krejcida61fb22015-10-30 11:10:03 +0100400 ly_print(out, "%*s}", LEVEL, INDENT);
401 } else {
402 ly_print(out, "%*snull", LEVEL, INDENT);
403 }
404
405
406 for (list = list->next; list && list->schema != node->schema; list = list->next);
407 if (list) {
Michal Vasko95068c42016-03-24 14:58:11 +0100408 ly_print(out, ",%s", (level ? "\n" : ""));
Radek Krejcida61fb22015-10-30 11:10:03 +0100409 }
410 }
Michal Vasko95068c42016-03-24 14:58:11 +0100411 if (level) {
412 level--;
413 }
414 ly_print(out, "%s%*s]", (level ? "\n" : ""), LEVEL, INDENT);
Radek Krejcida61fb22015-10-30 11:10:03 +0100415 }
Michal Vaskob3c31bd2017-07-17 10:01:48 +0200416
Michal Vasko609d7082019-04-26 09:35:40 +0200417finish:
418 LY_PRINT_RET(node->schema->module->ctx);
Michal Vasko98763c62015-07-17 13:47:00 +0200419}
420
Michal Vaskob3c31bd2017-07-17 10:01:48 +0200421static int
Michal Vasko9696e4d2018-05-28 08:28:31 +0200422json_print_anydataxml(struct lyout *out, int level, const struct lyd_node *node, int toplevel, int options)
Radek Krejcia7177672016-11-17 14:53:03 +0900423{
424 struct lyd_node_anydata *any = (struct lyd_node_anydata *)node;
Michal Vasko9696e4d2018-05-28 08:28:31 +0200425 int is_object = 0;
Radek Krejcia7177672016-11-17 14:53:03 +0900426 char *buf;
427 const char *schema = NULL;
428
Michal Vasko609d7082019-04-26 09:35:40 +0200429 LY_PRINT_SET;
430
Radek Krejcia7177672016-11-17 14:53:03 +0900431 if (toplevel || !node->parent || nscmp(node, node->parent)) {
432 /* print "namespace" */
433 schema = lys_node_module(node->schema)->name;
Michal Vasko9696e4d2018-05-28 08:28:31 +0200434 ly_print(out, "%*s\"%s:%s\":", LEVEL, INDENT, schema, node->schema->name);
Radek Krejcia7177672016-11-17 14:53:03 +0900435 } else {
Michal Vasko9696e4d2018-05-28 08:28:31 +0200436 ly_print(out, "%*s\"%s\":", LEVEL, INDENT, node->schema->name);
Radek Krejcia7177672016-11-17 14:53:03 +0900437 }
438 if (level) {
439 level++;
440 }
441
442 switch (any->value_type) {
443 case LYD_ANYDATA_DATATREE:
Michal Vasko9696e4d2018-05-28 08:28:31 +0200444 is_object = 1;
445 ly_print(out, "%s{%s", (level ? " " : ""), (level ? "\n" : ""));
Radek Krejcidb2f58c2016-11-24 11:24:48 +0100446 /* do not print any default values nor empty containers */
Michal Vaskob3c31bd2017-07-17 10:01:48 +0200447 if (json_print_nodes(out, level, any->value.tree, 1, 0, LYP_WITHSIBLINGS | (options & ~LYP_NETCONF))) {
448 return EXIT_FAILURE;
449 }
Radek Krejcia7177672016-11-17 14:53:03 +0900450 break;
451 case LYD_ANYDATA_JSON:
Michal Vasko9696e4d2018-05-28 08:28:31 +0200452 if (level) {
453 ly_print(out, "\n");
454 }
Radek Krejcia7177672016-11-17 14:53:03 +0900455 if (any->value.str) {
Michal Vasko9696e4d2018-05-28 08:28:31 +0200456 ly_print(out, "%s", any->value.str);
457 }
Michal Vaskoe748db42018-08-17 10:30:32 +0200458 if (level && (!any->value.str || (any->value.str[strlen(any->value.str) - 1] != '\n'))) {
Michal Vasko9696e4d2018-05-28 08:28:31 +0200459 /* do not print 2 newlines */
460 ly_print(out, "\n");
Radek Krejcia7177672016-11-17 14:53:03 +0900461 }
462 break;
463 case LYD_ANYDATA_XML:
464 lyxml_print_mem(&buf, any->value.xml, (level ? LYXML_PRINT_FORMAT | LYXML_PRINT_NO_LAST_NEWLINE : 0)
465 | LYXML_PRINT_SIBLINGS);
Michal Vasko9696e4d2018-05-28 08:28:31 +0200466 if (level) {
467 ly_print(out, " ");
468 }
Radek Krejcia7177672016-11-17 14:53:03 +0900469 json_print_string(out, buf);
470 free(buf);
471 break;
472 case LYD_ANYDATA_CONSTSTRING:
473 case LYD_ANYDATA_SXML:
Michal Vasko9696e4d2018-05-28 08:28:31 +0200474 if (level) {
475 ly_print(out, " ");
476 }
Radek Krejcia7177672016-11-17 14:53:03 +0900477 if (any->value.str) {
478 json_print_string(out, any->value.str);
479 } else {
480 ly_print(out, "\"\"");
481 }
482 break;
Michal Vaskodcaf7222018-08-08 16:27:00 +0200483 case LYD_ANYDATA_STRING:
484 case LYD_ANYDATA_SXMLD:
485 case LYD_ANYDATA_JSOND:
486 case LYD_ANYDATA_LYBD:
487 case LYD_ANYDATA_LYB:
Radek Krejcia7177672016-11-17 14:53:03 +0900488 /* other formats are not supported */
Michal Vasko609d7082019-04-26 09:35:40 +0200489 LOGINT(node->schema->module->ctx);
490 return EXIT_FAILURE;
Radek Krejcida61fb22015-10-30 11:10:03 +0100491 }
492
493 /* print attributes as sibling leaf */
494 if (node->attr) {
Radek Krejcida61fb22015-10-30 11:10:03 +0100495 if (schema) {
Michal Vaskof6aa8612017-03-02 10:52:44 +0100496 ly_print(out, ",%s%*s\"@%s:%s\":%s{%s", (level ? "\n" : ""), LEVEL, INDENT, schema, node->schema->name,
497 (level ? " " : ""), (level ? "\n" : ""));
Radek Krejcida61fb22015-10-30 11:10:03 +0100498 } else {
Michal Vaskof6aa8612017-03-02 10:52:44 +0100499 ly_print(out, ",%s%*s\"@%s\":%s{%s", (level ? "\n" : ""), LEVEL, INDENT, node->schema->name,
500 (level ? " " : ""), (level ? "\n" : ""));
Radek Krejcida61fb22015-10-30 11:10:03 +0100501 }
Michal Vaskob3c31bd2017-07-17 10:01:48 +0200502 if (json_print_attrs(out, (level ? level + 1 : level), node, NULL)) {
503 return EXIT_FAILURE;
504 }
Radek Krejcida61fb22015-10-30 11:10:03 +0100505 ly_print(out, "%*s}", LEVEL, INDENT);
506 }
Radek Krejci4ae82942016-09-19 16:41:06 +0200507
Radek Krejci4ae82942016-09-19 16:41:06 +0200508 if (level) {
509 level--;
510 }
Michal Vasko9696e4d2018-05-28 08:28:31 +0200511 if (is_object) {
512 ly_print(out, "%*s}", LEVEL, INDENT);
513 }
Michal Vaskob3c31bd2017-07-17 10:01:48 +0200514
Michal Vasko609d7082019-04-26 09:35:40 +0200515 LY_PRINT_RET(node->schema->module->ctx);
Michal Vaskoab8e4402015-07-17 12:54:28 +0200516}
517
Michal Vaskob3c31bd2017-07-17 10:01:48 +0200518static int
Radek Krejci46180b52016-08-31 16:01:32 +0200519json_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 +0200520{
Michal Vasko609d7082019-04-26 09:35:40 +0200521 int comma_flag = 0;
Radek Krejci572f1222016-09-01 09:52:47 +0200522 const struct lyd_node *node, *iter;
Radek Krejci27aaa732015-09-04 15:24:04 +0200523
Michal Vasko609d7082019-04-26 09:35:40 +0200524 LY_PRINT_SET;
525
Radek Krejci27aaa732015-09-04 15:24:04 +0200526 LY_TREE_FOR(root, node) {
Michal Vaskob5bf9bb2020-06-01 16:43:40 +0200527 if (lyd_node_should_print(node, options)) {
528 /* wd says to print */
529 switch (node->schema->nodetype) {
530 case LYS_RPC:
531 case LYS_ACTION:
532 case LYS_NOTIF:
533 case LYS_CONTAINER:
Radek Krejcic90c6512018-02-14 15:21:19 +0100534 if (comma_flag) {
Radek Krejci27aaa732015-09-04 15:24:04 +0200535 /* print the previous comma */
Michal Vasko95068c42016-03-24 14:58:11 +0100536 ly_print(out, ",%s", (level ? "\n" : ""));
Radek Krejci27aaa732015-09-04 15:24:04 +0200537 }
Michal Vaskob5bf9bb2020-06-01 16:43:40 +0200538 if (json_print_container(out, level, node, toplevel, options)) {
Michal Vasko609d7082019-04-26 09:35:40 +0200539 return EXIT_FAILURE;
540 }
Michal Vaskob5bf9bb2020-06-01 16:43:40 +0200541 break;
542 case LYS_LEAF:
543 if (comma_flag) {
544 /* print the previous comma */
545 ly_print(out, ",%s", (level ? "\n" : ""));
546 }
547 if (json_print_leaf(out, level, node, 0, toplevel, options)) {
548 return EXIT_FAILURE;
549 }
550 break;
551 case LYS_LEAFLIST:
552 case LYS_LIST:
553 /* is it already printed? (root node is not) */
554 for (iter = node->prev; iter->next && node != root; iter = iter->prev) {
555 if (iter == node) {
556 continue;
557 }
558 if (iter->schema == node->schema) {
559 /* the list has alread some previous instance and therefore it is already printed */
560 break;
561 }
562 }
563 if (!iter->next || node == root) {
564 if (comma_flag) {
565 /* print the previous comma */
566 ly_print(out, ",%s", (level ? "\n" : ""));
567 }
568
569 /* print the list/leaflist */
570 if (json_print_leaf_list(out, level, node, node->schema->nodetype == LYS_LIST ? 1 : 0, toplevel, options)) {
571 return EXIT_FAILURE;
572 }
573 }
574 break;
575 case LYS_ANYXML:
576 case LYS_ANYDATA:
577 if (comma_flag) {
578 /* print the previous comma */
579 ly_print(out, ",%s", (level ? "\n" : ""));
580 }
581 if (json_print_anydataxml(out, level, node, toplevel, options)) {
582 return EXIT_FAILURE;
583 }
584 break;
585 default:
586 LOGINT(node->schema->module->ctx);
Michal Vasko609d7082019-04-26 09:35:40 +0200587 return EXIT_FAILURE;
588 }
Michal Vaskob5bf9bb2020-06-01 16:43:40 +0200589
590 comma_flag = 1;
Radek Krejci27aaa732015-09-04 15:24:04 +0200591 }
Radek Krejci5044be32016-01-18 17:05:51 +0100592
593 if (!withsiblings) {
594 break;
595 }
Radek Krejci94ca54b2015-07-08 15:48:47 +0200596 }
Radek Krejci4ae82942016-09-19 16:41:06 +0200597 if (root && level) {
Michal Vasko95068c42016-03-24 14:58:11 +0100598 ly_print(out, "\n");
599 }
Michal Vaskob3c31bd2017-07-17 10:01:48 +0200600
Michal Vasko609d7082019-04-26 09:35:40 +0200601 LY_PRINT_RET(root ? root->schema->module->ctx : NULL);
Radek Krejci94ca54b2015-07-08 15:48:47 +0200602}
603
Radek Krejcif3752b02015-10-02 15:31:34 +0200604int
Radek Krejci5044be32016-01-18 17:05:51 +0100605json_print_data(struct lyout *out, const struct lyd_node *root, int options)
Radek Krejci94ca54b2015-07-08 15:48:47 +0200606{
Michal Vaskoafa7a642016-10-18 15:11:38 +0200607 const struct lyd_node *node, *next;
608 int level = 0, action_input = 0;
Radek Krejci94ca54b2015-07-08 15:48:47 +0200609
Michal Vasko609d7082019-04-26 09:35:40 +0200610 LY_PRINT_SET;
611
Michal Vasko95068c42016-03-24 14:58:11 +0100612 if (options & LYP_FORMAT) {
613 ++level;
614 }
615
Michal Vaskoafa7a642016-10-18 15:11:38 +0200616 if (options & LYP_NETCONF) {
617 if (root->schema->nodetype != LYS_RPC) {
618 /* learn whether we are printing an action */
619 LY_TREE_DFS_BEGIN(root, next, node) {
620 if (node->schema->nodetype == LYS_ACTION) {
621 break;
622 }
623 LY_TREE_DFS_END(root, next, node);
624 }
625 } else {
626 node = root;
627 }
628
629 if (node && (node->schema->nodetype & (LYS_RPC | LYS_ACTION))) {
630 if (node->child && (node->child->schema->parent->nodetype == LYS_OUTPUT)) {
631 /* skip the container */
632 root = node->child;
633 } else if (node->schema->nodetype == LYS_ACTION) {
634 action_input = 1;
635 }
636 }
637 }
638
Radek Krejci94ca54b2015-07-08 15:48:47 +0200639 /* start */
Michal Vasko95068c42016-03-24 14:58:11 +0100640 ly_print(out, "{%s", (level ? "\n" : ""));
Radek Krejci94ca54b2015-07-08 15:48:47 +0200641
Michal Vaskoafa7a642016-10-18 15:11:38 +0200642 if (action_input) {
643 ly_print(out, "%*s\"yang:action\":%s{%s", LEVEL, INDENT, (level ? " " : ""), (level ? "\n" : ""));
644 if (level) {
645 ++level;
646 }
647 }
648
Radek Krejci94ca54b2015-07-08 15:48:47 +0200649 /* content */
Michal Vaskob3c31bd2017-07-17 10:01:48 +0200650 if (json_print_nodes(out, level, root, options & LYP_WITHSIBLINGS, 1, options)) {
651 return EXIT_FAILURE;
652 }
Radek Krejci94ca54b2015-07-08 15:48:47 +0200653
Michal Vaskoafa7a642016-10-18 15:11:38 +0200654 if (action_input) {
655 if (level) {
656 --level;
657 }
658 ly_print(out, "%*s}%s", LEVEL, INDENT, (level ? "\n" : ""));
659 }
660
Radek Krejci94ca54b2015-07-08 15:48:47 +0200661 /* end */
Michal Vasko95068c42016-03-24 14:58:11 +0100662 ly_print(out, "}%s", (level ? "\n" : ""));
Radek Krejci94ca54b2015-07-08 15:48:47 +0200663
Michal Vaskoafa7a642016-10-18 15:11:38 +0200664 ly_print_flush(out);
Michal Vasko609d7082019-04-26 09:35:40 +0200665 LY_PRINT_RET(NULL);
Radek Krejci94ca54b2015-07-08 15:48:47 +0200666}