blob: b10c9ebd37ce94370e2be3d38dedfd9ffe68c88f [file] [log] [blame]
Radek Krejci94ca54b2015-07-08 15:48:47 +02001/**
2 * @file printer/json.c
3 * @author Radek Krejci <rkrejci@cesnet.cz>
4 * @brief JSON printer for libyang data structure
5 *
6 * Copyright (c) 2015 CESNET, z.s.p.o.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
16 * distribution.
17 * 3. Neither the name of the Company nor the names of its contributors
18 * may be used to endorse or promote products derived from this
19 * software without specific prior written permission.
20 */
21
22#include <stdlib.h>
23#include <stdio.h>
24#include <string.h>
25#include <assert.h>
Radek Krejci7511f402015-07-10 09:56:30 +020026#include <inttypes.h>
Radek Krejci94ca54b2015-07-08 15:48:47 +020027
28#include "../common.h"
Michal Vaskoab8e4402015-07-17 12:54:28 +020029#include "../xml.h"
Radek Krejci94ca54b2015-07-08 15:48:47 +020030#include "../tree.h"
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +020031#include "../resolve.h"
Michal Vaskoc82396e2015-07-17 15:31:25 +020032#include "../tree_internal.h"
Radek Krejci94ca54b2015-07-08 15:48:47 +020033
34#define INDENT ""
35#define LEVEL (level*2)
36
37void json_print_node(FILE *f, int level, struct lyd_node *node);
38
39/* 0 - same, 1 - different */
40static int
41nscmp(struct lyd_node *node1, struct lyd_node *node2)
42{
Radek Krejcib8048692015-08-05 13:36:34 +020043 struct lys_module *m1, *m2;
Radek Krejci94ca54b2015-07-08 15:48:47 +020044
45 /* we have to cover submodules belonging to the same module */
46 if (node1->schema->module->type) {
Radek Krejcib8048692015-08-05 13:36:34 +020047 m1 = ((struct lys_submodule *)node1->schema->module)->belongsto;
Radek Krejci94ca54b2015-07-08 15:48:47 +020048 } else {
49 m1 = node1->schema->module;
50 }
51 if (node2->schema->module->type) {
Radek Krejcib8048692015-08-05 13:36:34 +020052 m2 = ((struct lys_submodule *)node2->schema->module)->belongsto;
Radek Krejci94ca54b2015-07-08 15:48:47 +020053 } else {
54 m2 = node2->schema->module;
55 }
56 if (m1 == m2) {
57 /* belongs to the same module */
58 return 0;
59 } else {
60 /* different modules */
61 return 1;
62 }
63}
64
65static void
Michal Vaskoc82396e2015-07-17 15:31:25 +020066json_print_text_dquote(FILE *f, const char *str, int str_len)
67{
68 const char *ptr;
69
70 while ((ptr = strnchr(str, '\"', str_len))) {
71 fprintf(f, "%.*s\\\"", (int)(ptr-str), str);
72 str_len -= (ptr-str)+1;
73 str = ptr+1;
74 }
75
76 fprintf(f, "%.*s", str_len, str);
77}
78
79static void
80json_print_instid(FILE *f, struct lyd_node_leaf *leaf)
81{
82 const char *ptr, *print_ptr;
83 int cur_id_len, print_id_len;
Michal Vaskof02e3742015-08-05 16:27:02 +020084 struct unres_data *nodes, unres;
Radek Krejcib8048692015-08-05 13:36:34 +020085 struct lys_module *prev_module = NULL, *cur_module;
Radek Krejci76512572015-08-04 09:47:08 +020086 struct lys_node *snode;
Michal Vaskoc82396e2015-07-17 15:31:25 +020087
Radek Krejcib8048692015-08-05 13:36:34 +020088 assert(((struct lys_node_leaf *)leaf->schema)->type.base == LY_TYPE_INST);
Michal Vaskoc82396e2015-07-17 15:31:25 +020089
90 fputc('\"', f);
91 print_ptr = ptr = leaf->value_str+1;
92
93 while (print_ptr[0]) {
94 fputc('/', f);
95
96 /* check namespaces */
97 ptr = strchr(ptr, '/');
98 if (ptr) {
99 cur_id_len = ptr - leaf->value_str;
100 } else {
101 cur_id_len = strlen(leaf->value_str);
102 }
103
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +0200104 memset(&unres, 0, sizeof unres);
105 unres.dnode = (struct lyd_node *)leaf;
106 resolve_instid(&unres, leaf->value_str, cur_id_len, &nodes);
Michal Vaskoc82396e2015-07-17 15:31:25 +0200107 assert(nodes && !nodes->next);
108
Radek Krejci76512572015-08-04 09:47:08 +0200109 snode = (struct lys_node *)nodes->dnode->schema;
Michal Vaskoc82396e2015-07-17 15:31:25 +0200110 free(nodes);
111
112 /* find current module */
113 if (snode->module->type) {
Radek Krejcib8048692015-08-05 13:36:34 +0200114 cur_module = ((struct lys_submodule *)snode->module)->belongsto;
Michal Vaskoc82396e2015-07-17 15:31:25 +0200115 } else {
116 cur_module = snode->module;
117 }
118
119 if (!prev_module || (cur_module != prev_module)) {
120 fprintf(f, "%s:", cur_module->ns);
121 prev_module = cur_module;
122 }
123
124 ptr = strchr(print_ptr+1, '/');
125 if (ptr) {
126 print_id_len = ptr - print_ptr;
127 } else {
128 print_id_len = strlen(print_ptr);
129 }
130
131 json_print_text_dquote(f, print_ptr, print_id_len);
132 print_ptr += print_id_len+1;
133 }
134
135 fprintf(f, "\"");
136}
137
138static void
Radek Krejci5a988152015-07-15 11:16:26 +0200139json_print_leaf(FILE *f, int level, struct lyd_node *node, int onlyvalue)
Radek Krejci94ca54b2015-07-08 15:48:47 +0200140{
Radek Krejcie4748472015-07-08 18:00:22 +0200141 struct lyd_node_leaf *leaf = (struct lyd_node_leaf *)node;
Michal Vasko07471a52015-07-16 11:18:48 +0200142 LY_DATA_TYPE data_type;
Michal Vaskoc82396e2015-07-17 15:31:25 +0200143 const char *schema;
Radek Krejci94ca54b2015-07-08 15:48:47 +0200144
Radek Krejci5a988152015-07-15 11:16:26 +0200145 if (!onlyvalue) {
146 if (!node->parent || nscmp(node, node->parent)) {
147 /* print "namespace" */
148 if (node->schema->module->type) {
149 /* submodule, get module */
Radek Krejcib8048692015-08-05 13:36:34 +0200150 schema = ((struct lys_submodule *)node->schema->module)->belongsto->name;
Radek Krejci5a988152015-07-15 11:16:26 +0200151 } else {
152 schema = node->schema->module->name;
153 }
154 fprintf(f, "%*s\"%s:%s\": ", LEVEL, INDENT, schema, node->schema->name);
Radek Krejci94ca54b2015-07-08 15:48:47 +0200155 } else {
Radek Krejci5a988152015-07-15 11:16:26 +0200156 fprintf(f, "%*s\"%s\": ", LEVEL, INDENT, node->schema->name);
Radek Krejci94ca54b2015-07-08 15:48:47 +0200157 }
Radek Krejci94ca54b2015-07-08 15:48:47 +0200158 }
Radek Krejcie4748472015-07-08 18:00:22 +0200159
Radek Krejci25b9fd32015-08-10 15:06:07 +0200160 data_type = leaf->value_type;
Michal Vasko07471a52015-07-16 11:18:48 +0200161
Radek Krejcib1c12512015-08-11 11:22:04 +0200162 switch (data_type & LY_DATA_TYPE_MASK) {
Radek Krejcie4748472015-07-08 18:00:22 +0200163 case LY_TYPE_BINARY:
164 case LY_TYPE_STRING:
Radek Krejci3e3affe2015-07-09 15:38:40 +0200165 case LY_TYPE_BITS:
Radek Krejci5b315a92015-07-10 13:18:45 +0200166 case LY_TYPE_ENUM:
Radek Krejciac8aac62015-07-10 15:36:35 +0200167 case LY_TYPE_IDENT:
Radek Krejcib1c12512015-08-11 11:22:04 +0200168 fprintf(f, "\"%s\"", leaf->value_str ? leaf->value_str : "");
Radek Krejciac8aac62015-07-10 15:36:35 +0200169 break;
Radek Krejcib1c12512015-08-11 11:22:04 +0200170
171 case LY_TYPE_BOOL:
172 case LY_TYPE_DEC64:
173 case LY_TYPE_INT8:
174 case LY_TYPE_INT16:
175 case LY_TYPE_INT32:
176 case LY_TYPE_INT64:
177 case LY_TYPE_UINT8:
178 case LY_TYPE_UINT16:
179 case LY_TYPE_UINT32:
180 case LY_TYPE_UINT64:
181 fprintf(f, "%s", leaf->value_str ? leaf->value_str : "");
182 break;
183
Michal Vasko493bea72015-07-16 16:08:12 +0200184 case LY_TYPE_INST:
Michal Vaskoc82396e2015-07-17 15:31:25 +0200185 json_print_instid(f, leaf);
Michal Vasko493bea72015-07-16 16:08:12 +0200186 break;
Radek Krejcib1c12512015-08-11 11:22:04 +0200187
Radek Krejci5a988152015-07-15 11:16:26 +0200188 case LY_TYPE_LEAFREF:
189 json_print_leaf(f, level, leaf->value.leafref, 1);
190 break;
Radek Krejcib1c12512015-08-11 11:22:04 +0200191
192 case LY_TYPE_EMPTY:
193 fprintf(f, "[null]");
Michal Vasko58110162015-07-15 15:50:16 +0200194 break;
Radek Krejcib1c12512015-08-11 11:22:04 +0200195
Radek Krejcie4748472015-07-08 18:00:22 +0200196 default:
Michal Vasko493bea72015-07-16 16:08:12 +0200197 /* error */
198 fprintf(f, "\"(!error!)\"");
Radek Krejcie4748472015-07-08 18:00:22 +0200199 }
200
Radek Krejci5a988152015-07-15 11:16:26 +0200201 if (!onlyvalue) {
Radek Krejci9566b092015-07-31 11:18:15 +0200202 fprintf(f, "%s\n", lyd_is_last(node) ? "" : ",");
Radek Krejci5a988152015-07-15 11:16:26 +0200203 }
Radek Krejcib1c12512015-08-11 11:22:04 +0200204 return;
Radek Krejci94ca54b2015-07-08 15:48:47 +0200205}
206
Michal Vaskoab8e4402015-07-17 12:54:28 +0200207static void
Michal Vasko98763c62015-07-17 13:47:00 +0200208json_print_container(FILE *f, int level, struct lyd_node *node)
209{
210 const char *schema;
211 struct lyd_node *child;
212
213 if (!node->parent || nscmp(node, node->parent)) {
214 /* print "namespace" */
215 if (node->schema->module->type) {
216 /* submodule, get module */
Radek Krejcib8048692015-08-05 13:36:34 +0200217 schema = ((struct lys_submodule *)node->schema->module)->belongsto->name;
Michal Vasko98763c62015-07-17 13:47:00 +0200218 } else {
219 schema = node->schema->module->name;
220 }
221 fprintf(f, "%*s\"%s:%s\": {\n", LEVEL, INDENT, schema, node->schema->name);
222 } else {
223 fprintf(f, "%*s\"%s\": {\n", LEVEL, INDENT, node->schema->name);
224 }
225 LY_TREE_FOR(node->child, child) {
226 json_print_node(f, level + 1, child);
227 }
Radek Krejci9566b092015-07-31 11:18:15 +0200228 fprintf(f, "%*s}%s\n", LEVEL, INDENT, lyd_is_last(node) ? "" : ",");
Michal Vasko98763c62015-07-17 13:47:00 +0200229}
230
231static void
232json_print_list_internal(FILE *f, int level, struct lyd_node_list *list)
233{
234 struct lyd_node *child;
235
236 fprintf(f, "%*s{\n", LEVEL, INDENT);
237
238 LY_TREE_FOR(list->child, child) {
239 json_print_node(f, level + 1, child);
240 }
241
242 fprintf(f, "%*s}%s\n", LEVEL, INDENT, (list->lnext ? "," : ""));
243}
244
245static void
246json_print_leaf_list(FILE *f, int level, struct lyd_node *node, int is_list)
247{
248 const char *schema;
249 struct lyd_node_list *list = (struct lyd_node_list *)node;
250 struct lyd_node_leaflist *llist = (struct lyd_node_leaflist *)node;
Michal Vasko98763c62015-07-17 13:47:00 +0200251
252 if ((is_list && list->lprev) || (!is_list && llist->lprev)) {
253 /* this list is already printed */
254 return;
255 }
256
257 if (!node->parent || nscmp(node, node->parent)) {
258 /* print "namespace" */
259 if (node->schema->module->type) {
260 /* submodule, get module */
Radek Krejcib8048692015-08-05 13:36:34 +0200261 schema = ((struct lys_submodule *)node->schema->module)->belongsto->name;
Michal Vasko98763c62015-07-17 13:47:00 +0200262 } else {
263 schema = node->schema->module->name;
264 }
265 fprintf(f, "%*s\"%s:%s\": [\n", LEVEL, INDENT, schema, node->schema->name);
266 } else {
267 fprintf(f, "%*s\"%s\": [\n", LEVEL, INDENT, node->schema->name);
268 }
269
270 if (!is_list) {
271 ++level;
272 }
273 while ((is_list && list) || (!is_list && llist)) {
274 if (is_list) {
275 json_print_list_internal(f, level + 1, list);
276 list = list->lnext;
277 } else {
278 fprintf(f, "%*s", LEVEL, INDENT);
279 json_print_leaf(f, level, (struct lyd_node *)llist, 1);
280 fprintf(f, "%s\n", (llist->lnext ? "," : ""));
281 llist = llist->lnext;
282 }
283 }
284 if (!is_list) {
285 --level;
286 }
287
Radek Krejci9566b092015-07-31 11:18:15 +0200288 fprintf(f, "%*s]%s\n", LEVEL, INDENT, lyd_is_last(node) ? "" : ",");
Michal Vasko98763c62015-07-17 13:47:00 +0200289}
290
291static void
Michal Vaskoab8e4402015-07-17 12:54:28 +0200292json_print_anyxml(FILE *f, int level, struct lyd_node *node)
293{
294 struct lyd_node_anyxml *axml = (struct lyd_node_anyxml *)node;
295
Radek Krejci9566b092015-07-31 11:18:15 +0200296 fprintf(f, "%*s\"%s\": [null]%s\n", LEVEL, INDENT, axml->value->name, lyd_is_last(node) ? "" : ",");
Michal Vaskoab8e4402015-07-17 12:54:28 +0200297}
298
Radek Krejci94ca54b2015-07-08 15:48:47 +0200299void
300json_print_node(FILE *f, int level, struct lyd_node *node)
301{
302 switch (node->schema->nodetype) {
Radek Krejci76512572015-08-04 09:47:08 +0200303 case LYS_CONTAINER:
Radek Krejci94ca54b2015-07-08 15:48:47 +0200304 json_print_container(f, level, node);
305 break;
Radek Krejci76512572015-08-04 09:47:08 +0200306 case LYS_LEAF:
Radek Krejci5a988152015-07-15 11:16:26 +0200307 json_print_leaf(f, level, node, 0);
Radek Krejci94ca54b2015-07-08 15:48:47 +0200308 break;
Radek Krejci76512572015-08-04 09:47:08 +0200309 case LYS_LEAFLIST:
Michal Vasko98763c62015-07-17 13:47:00 +0200310 json_print_leaf_list(f, level, node, 0);
311 break;
Radek Krejci76512572015-08-04 09:47:08 +0200312 case LYS_LIST:
Michal Vasko98763c62015-07-17 13:47:00 +0200313 json_print_leaf_list(f, level, node, 1);
Michal Vaskoab8e4402015-07-17 12:54:28 +0200314 break;
Radek Krejci76512572015-08-04 09:47:08 +0200315 case LYS_ANYXML:
Michal Vaskoab8e4402015-07-17 12:54:28 +0200316 json_print_anyxml(f, level, node);
317 break;
Radek Krejci94ca54b2015-07-08 15:48:47 +0200318 default:
Michal Vasko0c888fd2015-08-11 15:54:08 +0200319 LOGINT;
Radek Krejci94ca54b2015-07-08 15:48:47 +0200320 break;
321 }
Radek Krejci94ca54b2015-07-08 15:48:47 +0200322}
323
Michal Vasko520d4732015-07-13 15:53:33 +0200324API int
Radek Krejci94ca54b2015-07-08 15:48:47 +0200325json_print_data(FILE *f, struct lyd_node *root)
326{
327 int level = 0;
328 struct lyd_node *node;
329
330 /* start */
331 fprintf(f, "{\n");
332
333 /* content */
334 LY_TREE_FOR(root, node) {
335 json_print_node(f, level + 1, node);
336 }
337
338 /* end */
339 fprintf(f, "}\n");
340
341 return EXIT_SUCCESS;
342}