blob: 456c6a0dd4d521f103ec27589584679d8d5150a7 [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
11 *
12 * 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
Radek Krejci5044be32016-01-18 17:05:51 +010030static void json_print_nodes(struct lyout *out, int level, const struct lyd_node *root, int withsiblings);
Radek Krejci94ca54b2015-07-08 15:48:47 +020031
Radek Krejci382e7f92016-01-12 17:15:47 +010032static int
33json_print_string(struct lyout *out, const char *text)
34{
35 unsigned int i, n;
36
37 if (!text) {
38 return 0;
39 }
40
41 ly_write(out, "\"", 1);
42 for (i = n = 0; text[i]; i++) {
43 if (text[i] < 0x20) {
44 /* control character */
45 n += ly_print(out, "\\u%.4X");
46 } else {
47 switch (text[i]) {
48 case '"':
49 n += ly_print(out, "\\\"");
50 break;
51 case '\\':
52 n += ly_print(out, "\\\\");
53 break;
54 default:
55 ly_write(out, &text[i], 1);
56 n++;
57 }
58 }
59 }
60 ly_write(out, "\"", 1);
61
62 return n + 2;
63}
64
Radek Krejci94ca54b2015-07-08 15:48:47 +020065static void
Michal Vasko1e62a092015-12-01 12:27:20 +010066json_print_attrs(struct lyout *out, int level, const struct lyd_node *node)
Radek Krejcida61fb22015-10-30 11:10:03 +010067{
68 struct lyd_attr *attr;
69
70 for (attr = node->attr; attr; attr = attr->next) {
71 if (attr->module != node->schema->module) {
Radek Krejci382e7f92016-01-12 17:15:47 +010072 ly_print(out, "%*s\"%s:%s\":", LEVEL, INDENT, attr->module->name, attr->name);
Radek Krejcida61fb22015-10-30 11:10:03 +010073 } else {
Radek Krejci382e7f92016-01-12 17:15:47 +010074 ly_print(out, "%*s\"%s\":", LEVEL, INDENT, attr->name);
Radek Krejcida61fb22015-10-30 11:10:03 +010075 }
Radek Krejci382e7f92016-01-12 17:15:47 +010076 json_print_string(out, attr->value ? attr->value : "");
77 ly_print(out, "%s", attr->next ? ",\n" : "\n");
Radek Krejcida61fb22015-10-30 11:10:03 +010078 }
79}
80
81static void
Michal Vasko1e62a092015-12-01 12:27:20 +010082json_print_leaf(struct lyout *out, int level, const struct lyd_node *node, int onlyvalue)
Radek Krejci94ca54b2015-07-08 15:48:47 +020083{
Michal Vasko4c183312015-09-25 10:41:47 +020084 struct lyd_node_leaf_list *leaf = (struct lyd_node_leaf_list *)node;
Radek Krejcida61fb22015-10-30 11:10:03 +010085 const char *schema = NULL;
Radek Krejci94ca54b2015-07-08 15:48:47 +020086
Radek Krejci5a988152015-07-15 11:16:26 +020087 if (!onlyvalue) {
88 if (!node->parent || nscmp(node, node->parent)) {
89 /* print "namespace" */
Michal Vasko6c629ac2016-02-15 14:08:23 +010090 schema = lys_node_module(node->schema)->name;
Radek Krejci76b07902015-10-09 09:11:25 +020091 ly_print(out, "%*s\"%s:%s\": ", LEVEL, INDENT, schema, node->schema->name);
Radek Krejci94ca54b2015-07-08 15:48:47 +020092 } else {
Radek Krejci76b07902015-10-09 09:11:25 +020093 ly_print(out, "%*s\"%s\": ", LEVEL, INDENT, node->schema->name);
Radek Krejci94ca54b2015-07-08 15:48:47 +020094 }
Radek Krejci94ca54b2015-07-08 15:48:47 +020095 }
Radek Krejcie4748472015-07-08 18:00:22 +020096
Radek Krejcida61fb22015-10-30 11:10:03 +010097 switch (leaf->value_type & LY_DATA_TYPE_MASK) {
Radek Krejcie4748472015-07-08 18:00:22 +020098 case LY_TYPE_BINARY:
99 case LY_TYPE_STRING:
Radek Krejci3e3affe2015-07-09 15:38:40 +0200100 case LY_TYPE_BITS:
Radek Krejci5b315a92015-07-10 13:18:45 +0200101 case LY_TYPE_ENUM:
Radek Krejciac8aac62015-07-10 15:36:35 +0200102 case LY_TYPE_IDENT:
Radek Krejcic5090c32015-08-12 09:46:19 +0200103 case LY_TYPE_INST:
Radek Krejci382e7f92016-01-12 17:15:47 +0100104 json_print_string(out, leaf->value_str ? leaf->value_str : "");
Radek Krejciac8aac62015-07-10 15:36:35 +0200105 break;
Radek Krejcib1c12512015-08-11 11:22:04 +0200106
107 case LY_TYPE_BOOL:
108 case LY_TYPE_DEC64:
109 case LY_TYPE_INT8:
110 case LY_TYPE_INT16:
111 case LY_TYPE_INT32:
112 case LY_TYPE_INT64:
113 case LY_TYPE_UINT8:
114 case LY_TYPE_UINT16:
115 case LY_TYPE_UINT32:
116 case LY_TYPE_UINT64:
Radek Krejci23238922015-10-27 17:13:34 +0100117 ly_print(out, "%s", leaf->value_str ? leaf->value_str : "null");
Radek Krejcib1c12512015-08-11 11:22:04 +0200118 break;
119
Radek Krejci5a988152015-07-15 11:16:26 +0200120 case LY_TYPE_LEAFREF:
Radek Krejci5ce04a42016-01-21 14:54:24 +0100121 if (leaf->value.leafref) {
122 json_print_leaf(out, level, leaf->value.leafref, 1);
123 } else {
124 ly_print(out, "");
125 }
Radek Krejci5a988152015-07-15 11:16:26 +0200126 break;
Radek Krejcib1c12512015-08-11 11:22:04 +0200127
128 case LY_TYPE_EMPTY:
Radek Krejci76b07902015-10-09 09:11:25 +0200129 ly_print(out, "[null]");
Michal Vasko58110162015-07-15 15:50:16 +0200130 break;
Radek Krejcib1c12512015-08-11 11:22:04 +0200131
Radek Krejcie4748472015-07-08 18:00:22 +0200132 default:
Michal Vasko493bea72015-07-16 16:08:12 +0200133 /* error */
Radek Krejci76b07902015-10-09 09:11:25 +0200134 ly_print(out, "\"(!error!)\"");
Radek Krejcie4748472015-07-08 18:00:22 +0200135 }
136
Radek Krejci382e7f92016-01-12 17:15:47 +0100137 /* print attributes as sibling leafs */
Radek Krejcida61fb22015-10-30 11:10:03 +0100138 if (!onlyvalue && node->attr) {
Radek Krejcida61fb22015-10-30 11:10:03 +0100139 if (schema) {
Radek Krejci88f29302015-10-30 15:42:33 +0100140 ly_print(out, ",\n%*s\"@%s:%s\": {\n", LEVEL, INDENT, schema, node->schema->name);
Radek Krejcida61fb22015-10-30 11:10:03 +0100141 } else {
Radek Krejci88f29302015-10-30 15:42:33 +0100142 ly_print(out, ",\n%*s\"@%s\": {\n", LEVEL, INDENT, node->schema->name);
Radek Krejcida61fb22015-10-30 11:10:03 +0100143 }
144 json_print_attrs(out, level + 1, node);
145 ly_print(out, "%*s}", LEVEL, INDENT);
146 }
147
Radek Krejcib1c12512015-08-11 11:22:04 +0200148 return;
Radek Krejci94ca54b2015-07-08 15:48:47 +0200149}
150
Michal Vaskoab8e4402015-07-17 12:54:28 +0200151static void
Michal Vasko1e62a092015-12-01 12:27:20 +0100152json_print_container(struct lyout *out, int level, const struct lyd_node *node)
Michal Vasko98763c62015-07-17 13:47:00 +0200153{
154 const char *schema;
Michal Vasko98763c62015-07-17 13:47:00 +0200155
156 if (!node->parent || nscmp(node, node->parent)) {
157 /* print "namespace" */
Michal Vasko6c629ac2016-02-15 14:08:23 +0100158 schema = lys_node_module(node->schema)->name;
Radek Krejci76b07902015-10-09 09:11:25 +0200159 ly_print(out, "%*s\"%s:%s\": {\n", LEVEL, INDENT, schema, node->schema->name);
Michal Vasko98763c62015-07-17 13:47:00 +0200160 } else {
Radek Krejci76b07902015-10-09 09:11:25 +0200161 ly_print(out, "%*s\"%s\": {\n", LEVEL, INDENT, node->schema->name);
Michal Vasko98763c62015-07-17 13:47:00 +0200162 }
Radek Krejcida61fb22015-10-30 11:10:03 +0100163 level++;
164 if (node->attr) {
165 ly_print(out, "%*s\"@\": {\n", LEVEL, INDENT);
166 json_print_attrs(out, level + 1, node);
167 ly_print(out, "%*s}%s", LEVEL, INDENT, node->child ? ",\n" : "");
168 }
Radek Krejci5044be32016-01-18 17:05:51 +0100169 json_print_nodes(out, level, node->child, 1);
Radek Krejcida61fb22015-10-30 11:10:03 +0100170 level--;
Radek Krejci76b07902015-10-09 09:11:25 +0200171 ly_print(out, "%*s}", LEVEL, INDENT);
Michal Vasko98763c62015-07-17 13:47:00 +0200172}
173
174static void
Michal Vasko1e62a092015-12-01 12:27:20 +0100175json_print_leaf_list(struct lyout *out, int level, const struct lyd_node *node, int is_list)
Michal Vasko98763c62015-07-17 13:47:00 +0200176{
Radek Krejcida61fb22015-10-30 11:10:03 +0100177 const char *schema = NULL;
Michal Vasko1e62a092015-12-01 12:27:20 +0100178 const struct lyd_node *list = node;
Radek Krejcida61fb22015-10-30 11:10:03 +0100179 int flag_empty = 0, flag_attrs = 0;
Radek Krejci23238922015-10-27 17:13:34 +0100180
181 if (!list->child) {
182 /* empty, e.g. in case of filter */
183 flag_empty = 1;
184 }
Michal Vasko98763c62015-07-17 13:47:00 +0200185
186 if (!node->parent || nscmp(node, node->parent)) {
187 /* print "namespace" */
Michal Vasko6c629ac2016-02-15 14:08:23 +0100188 schema = lys_node_module(node->schema)->name;
Radek Krejci23238922015-10-27 17:13:34 +0100189 ly_print(out, "%*s\"%s:%s\":", LEVEL, INDENT, schema, node->schema->name);
Michal Vasko98763c62015-07-17 13:47:00 +0200190 } else {
Radek Krejci23238922015-10-27 17:13:34 +0100191 ly_print(out, "%*s\"%s\":", LEVEL, INDENT, node->schema->name);
Michal Vasko98763c62015-07-17 13:47:00 +0200192 }
193
Radek Krejci23238922015-10-27 17:13:34 +0100194 if (flag_empty) {
195 ly_print(out, " null");
196 return;
197 }
198 ly_print(out, " [\n");
199
Michal Vasko98763c62015-07-17 13:47:00 +0200200 if (!is_list) {
201 ++level;
202 }
Radek Krejci27aaa732015-09-04 15:24:04 +0200203
204 while (list) {
Michal Vasko98763c62015-07-17 13:47:00 +0200205 if (is_list) {
Radek Krejci27aaa732015-09-04 15:24:04 +0200206 /* list print */
207 ++level;
Radek Krejci76b07902015-10-09 09:11:25 +0200208 ly_print(out, "%*s{\n", LEVEL, INDENT);
Radek Krejcida61fb22015-10-30 11:10:03 +0100209 ++level;
210 if (list->attr) {
211 ly_print(out, "%*s\"@\": {\n", LEVEL, INDENT);
212 json_print_attrs(out, level + 1, node);
213 ly_print(out, "%*s}%s", LEVEL, INDENT, list->child ? ",\n" : "");
214 }
Radek Krejci5044be32016-01-18 17:05:51 +0100215 json_print_nodes(out, level, list->child, 1);
Radek Krejcida61fb22015-10-30 11:10:03 +0100216 --level;
Radek Krejci76b07902015-10-09 09:11:25 +0200217 ly_print(out, "%*s}", LEVEL, INDENT);
Radek Krejci27aaa732015-09-04 15:24:04 +0200218 --level;
Michal Vasko98763c62015-07-17 13:47:00 +0200219 } else {
Radek Krejci27aaa732015-09-04 15:24:04 +0200220 /* leaf-list print */
Radek Krejci76b07902015-10-09 09:11:25 +0200221 ly_print(out, "%*s", LEVEL, INDENT);
222 json_print_leaf(out, level, list, 1);
Radek Krejcida61fb22015-10-30 11:10:03 +0100223 if (list->attr) {
224 flag_attrs = 1;
225 }
Radek Krejci27aaa732015-09-04 15:24:04 +0200226 }
227 for (list = list->next; list && list->schema != node->schema; list = list->next);
228 if (list) {
Radek Krejci76b07902015-10-09 09:11:25 +0200229 ly_print(out, ",\n");
Michal Vasko98763c62015-07-17 13:47:00 +0200230 }
231 }
Radek Krejci27aaa732015-09-04 15:24:04 +0200232
Michal Vasko98763c62015-07-17 13:47:00 +0200233 if (!is_list) {
234 --level;
235 }
236
Radek Krejci76b07902015-10-09 09:11:25 +0200237 ly_print(out, "\n%*s]", LEVEL, INDENT);
Radek Krejcida61fb22015-10-30 11:10:03 +0100238
239 /* attributes */
240 if (!is_list && flag_attrs) {
241 if (schema) {
Radek Krejci88f29302015-10-30 15:42:33 +0100242 ly_print(out, ",\n%*s\"@%s:%s\": [\n", LEVEL, INDENT, schema, node->schema->name);
Radek Krejcida61fb22015-10-30 11:10:03 +0100243 } else {
Radek Krejci88f29302015-10-30 15:42:33 +0100244 ly_print(out, ",\n%*s\"@%s\": [\n", LEVEL, INDENT, node->schema->name);
Radek Krejcida61fb22015-10-30 11:10:03 +0100245 }
246 level++;
247 for (list = node; list; ) {
248 if (list->attr) {
249 ly_print(out, "%*s{ ", LEVEL, INDENT);
250 json_print_attrs(out, 0, list);
251 ly_print(out, "%*s}", LEVEL, INDENT);
252 } else {
253 ly_print(out, "%*snull", LEVEL, INDENT);
254 }
255
256
257 for (list = list->next; list && list->schema != node->schema; list = list->next);
258 if (list) {
259 ly_print(out, ",\n");
260 }
261 }
262 level--;
263 ly_print(out, "\n%*s]", LEVEL, INDENT);
264 }
Michal Vasko98763c62015-07-17 13:47:00 +0200265}
266
267static void
Michal Vasko1e62a092015-12-01 12:27:20 +0100268json_print_anyxml(struct lyout *out, int level, const struct lyd_node *node)
Michal Vaskoab8e4402015-07-17 12:54:28 +0200269{
Radek Krejcida61fb22015-10-30 11:10:03 +0100270 const char *schema = NULL;
271
272 if (!node->parent || nscmp(node, node->parent)) {
273 /* print "namespace" */
Michal Vasko6c629ac2016-02-15 14:08:23 +0100274 schema = lys_node_module(node->schema)->name;
Radek Krejcida61fb22015-10-30 11:10:03 +0100275 ly_print(out, "%*s\"%s:%s\": [null]", LEVEL, INDENT, schema, node->schema->name);
276 } else {
277 ly_print(out, "%*s\"%s\": [null]", LEVEL, INDENT, node->schema->name);
278 }
279
280 /* print attributes as sibling leaf */
281 if (node->attr) {
Radek Krejcida61fb22015-10-30 11:10:03 +0100282 if (schema) {
Radek Krejci88f29302015-10-30 15:42:33 +0100283 ly_print(out, ",\n%*s\"@%s:%s\": {\n", LEVEL, INDENT, schema, node->schema->name);
Radek Krejcida61fb22015-10-30 11:10:03 +0100284 } else {
Radek Krejci88f29302015-10-30 15:42:33 +0100285 ly_print(out, ",\n%*s\"@%s\": {\n", LEVEL, INDENT, node->schema->name);
Radek Krejcida61fb22015-10-30 11:10:03 +0100286 }
287 json_print_attrs(out, level + 1, node);
288 ly_print(out, "%*s}", LEVEL, INDENT);
289 }
Michal Vaskoab8e4402015-07-17 12:54:28 +0200290}
291
Radek Krejci5044be32016-01-18 17:05:51 +0100292static void
293json_print_nodes(struct lyout *out, int level, const struct lyd_node *root, int withsiblings)
Radek Krejci94ca54b2015-07-08 15:48:47 +0200294{
Michal Vasko1e62a092015-12-01 12:27:20 +0100295 const struct lyd_node *node, *iter;
Radek Krejci27aaa732015-09-04 15:24:04 +0200296
297 LY_TREE_FOR(root, node) {
298 switch (node->schema->nodetype) {
Radek Krejcifb54be42015-10-02 15:21:16 +0200299 case LYS_RPC:
300 case LYS_NOTIF:
Radek Krejci27aaa732015-09-04 15:24:04 +0200301 case LYS_CONTAINER:
302 if (node->prev->next) {
303 /* print the previous comma */
Radek Krejci76b07902015-10-09 09:11:25 +0200304 ly_print(out, ",\n");
Radek Krejci27aaa732015-09-04 15:24:04 +0200305 }
Radek Krejci76b07902015-10-09 09:11:25 +0200306 json_print_container(out, level, node);
Radek Krejci27aaa732015-09-04 15:24:04 +0200307 break;
308 case LYS_LEAF:
309 if (node->prev->next) {
310 /* print the previous comma */
Radek Krejci76b07902015-10-09 09:11:25 +0200311 ly_print(out, ",\n");
Radek Krejci27aaa732015-09-04 15:24:04 +0200312 }
Radek Krejci76b07902015-10-09 09:11:25 +0200313 json_print_leaf(out, level, node, 0);
Radek Krejci27aaa732015-09-04 15:24:04 +0200314 break;
315 case LYS_LEAFLIST:
316 case LYS_LIST:
317 /* is it already printed? */
Radek Krejci9ce61512015-10-26 14:42:32 +0100318 for (iter = node->prev; iter->next; iter = iter->prev) {
Radek Krejci27aaa732015-09-04 15:24:04 +0200319 if (iter == node) {
320 continue;
321 }
322 if (iter->schema == node->schema) {
323 /* the list has alread some previous instance and therefore it is already printed */
324 break;
325 }
326 }
Michal Vasko6c563772015-10-15 10:49:30 +0200327 if (!iter->next) {
Radek Krejci27aaa732015-09-04 15:24:04 +0200328 if (node->prev->next) {
329 /* print the previous comma */
Radek Krejci76b07902015-10-09 09:11:25 +0200330 ly_print(out, ",\n");
Radek Krejci27aaa732015-09-04 15:24:04 +0200331 }
332
333 /* print the list/leaflist */
Radek Krejci76b07902015-10-09 09:11:25 +0200334 json_print_leaf_list(out, level, node, node->schema->nodetype == LYS_LIST ? 1 : 0);
Radek Krejci27aaa732015-09-04 15:24:04 +0200335 }
336 break;
337 case LYS_ANYXML:
338 if (node->prev->next) {
339 /* print the previous comma */
Radek Krejci76b07902015-10-09 09:11:25 +0200340 ly_print(out, ",\n");
Radek Krejci27aaa732015-09-04 15:24:04 +0200341 }
Radek Krejci76b07902015-10-09 09:11:25 +0200342 json_print_anyxml(out, level, node);
Radek Krejci27aaa732015-09-04 15:24:04 +0200343 break;
344 default:
345 LOGINT;
346 break;
347 }
Radek Krejci5044be32016-01-18 17:05:51 +0100348
349 if (!withsiblings) {
350 break;
351 }
Radek Krejci94ca54b2015-07-08 15:48:47 +0200352 }
Radek Krejci76b07902015-10-09 09:11:25 +0200353 ly_print(out, "\n");
Radek Krejci94ca54b2015-07-08 15:48:47 +0200354}
355
Radek Krejcif3752b02015-10-02 15:31:34 +0200356int
Radek Krejci5044be32016-01-18 17:05:51 +0100357json_print_data(struct lyout *out, const struct lyd_node *root, int options)
Radek Krejci94ca54b2015-07-08 15:48:47 +0200358{
359 int level = 0;
Radek Krejci94ca54b2015-07-08 15:48:47 +0200360
361 /* start */
Radek Krejci76b07902015-10-09 09:11:25 +0200362 ly_print(out, "{\n");
Radek Krejci94ca54b2015-07-08 15:48:47 +0200363
364 /* content */
Radek Krejci5044be32016-01-18 17:05:51 +0100365 json_print_nodes(out, level + 1, root, options & LYP_WITHSIBLINGS);
Radek Krejci94ca54b2015-07-08 15:48:47 +0200366
367 /* end */
Radek Krejci76b07902015-10-09 09:11:25 +0200368 ly_print(out, "}\n");
Radek Krejci94ca54b2015-07-08 15:48:47 +0200369
370 return EXIT_SUCCESS;
371}