blob: 125c2fcf375d81da2d580b80fb996f20f1a4c74f [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"
31
32#define INDENT ""
33#define LEVEL (level*2)
34
35void json_print_node(FILE *f, int level, struct lyd_node *node);
36
37/* 0 - same, 1 - different */
38static int
39nscmp(struct lyd_node *node1, struct lyd_node *node2)
40{
41 struct ly_module *m1, *m2;
42
43 /* we have to cover submodules belonging to the same module */
44 if (node1->schema->module->type) {
45 m1 = ((struct ly_submodule *)node1->schema->module)->belongsto;
46 } else {
47 m1 = node1->schema->module;
48 }
49 if (node2->schema->module->type) {
50 m2 = ((struct ly_submodule *)node2->schema->module)->belongsto;
51 } else {
52 m2 = node2->schema->module;
53 }
54 if (m1 == m2) {
55 /* belongs to the same module */
56 return 0;
57 } else {
58 /* different modules */
59 return 1;
60 }
61}
62
63static void
64json_print_container(FILE *f, int level, struct lyd_node *node)
65{
66 const char *schema;
67 struct lyd_node *child;
68
69 if (!node->parent || nscmp(node, node->parent)) {
70 /* print "namespace" */
71 if (node->schema->module->type) {
72 /* submodule, get module */
73 schema = ((struct ly_submodule *)node->schema->module)->belongsto->name;
74 } else {
75 schema = node->schema->module->name;
76 }
77 fprintf(f, "%*s\"%s:%s\": {\n", LEVEL, INDENT, schema, node->schema->name);
78 } else {
79 fprintf(f, "%*s\"%s\": {\n", LEVEL, INDENT, node->schema->name);
80 }
81 LY_TREE_FOR(node->child, child) {
82 json_print_node(f, level + 1, child);
83 }
84 fprintf(f, "%*s}%s\n", LEVEL, INDENT, node->next ? "," : "");
85}
86
87static void
88json_print_list_internal(FILE *f, int level, struct lyd_node_list *list)
89{
90 struct lyd_node *child;
91
92 fprintf(f, "%*s{\n", LEVEL, INDENT);
93
Radek Krejci94ca54b2015-07-08 15:48:47 +020094 LY_TREE_FOR(list->child, child) {
95 json_print_node(f, level + 1, child);
96 }
97
98 fprintf(f, "%*s}%s\n", LEVEL, INDENT, list->lnext ? "," : "");
99}
100
101static void
102json_print_list(FILE *f, int level, struct lyd_node *node)
103{
104 const char *schema;
105 struct lyd_node_list *list = (struct lyd_node_list *)node;
106 struct lyd_node *iter;
107 char *delim = "";
108
109 if (list->lprev) {
110 /* this list is already printed */
111 return;
112 }
113
114 if (!node->parent || nscmp(node, node->parent)) {
115 /* print "namespace" */
116 if (node->schema->module->type) {
117 /* submodule, get module */
118 schema = ((struct ly_submodule *)node->schema->module)->belongsto->name;
119 } else {
120 schema = node->schema->module->name;
121 }
122 fprintf(f, "%*s\"%s:%s\": [\n", LEVEL, INDENT, schema, node->schema->name);
123 } else {
124 fprintf(f, "%*s\"%s\": [\n", LEVEL, INDENT, node->schema->name);
125 }
126
127 for(; list; list = list->lnext) {
128 json_print_list_internal(f, level + 1, list);
129 }
130 for (iter = node->next; iter; iter = iter->next) {
131 if (iter->schema != node->schema) {
132 delim = ",";
133 break;
134 }
135 }
136 fprintf(f, "%*s]%s\n", LEVEL, INDENT, delim);
137}
138
139static void
Radek Krejci5a988152015-07-15 11:16:26 +0200140json_print_leaf(FILE *f, int level, struct lyd_node *node, int onlyvalue)
Radek Krejci94ca54b2015-07-08 15:48:47 +0200141{
Radek Krejcie4748472015-07-08 18:00:22 +0200142 struct lyd_node_leaf *leaf = (struct lyd_node_leaf *)node;
Radek Krejci3e3affe2015-07-09 15:38:40 +0200143 struct ly_mnode_leaf *sleaf = (struct ly_mnode_leaf *)node->schema;
144 struct ly_type *type;
Michal Vasko07471a52015-07-16 11:18:48 +0200145 LY_DATA_TYPE data_type;
Michal Vasko8c9b7a72015-07-17 09:58:46 +0200146 const char *schema, *ptr, *ptr2;
Radek Krejci7511f402015-07-10 09:56:30 +0200147 char dec[21];
148 int i, len;
Radek Krejci94ca54b2015-07-08 15:48:47 +0200149
Radek Krejci5a988152015-07-15 11:16:26 +0200150 if (!onlyvalue) {
151 if (!node->parent || nscmp(node, node->parent)) {
152 /* print "namespace" */
153 if (node->schema->module->type) {
154 /* submodule, get module */
155 schema = ((struct ly_submodule *)node->schema->module)->belongsto->name;
156 } else {
157 schema = node->schema->module->name;
158 }
159 fprintf(f, "%*s\"%s:%s\": ", LEVEL, INDENT, schema, node->schema->name);
Radek Krejci94ca54b2015-07-08 15:48:47 +0200160 } else {
Radek Krejci5a988152015-07-15 11:16:26 +0200161 fprintf(f, "%*s\"%s\": ", LEVEL, INDENT, node->schema->name);
Radek Krejci94ca54b2015-07-08 15:48:47 +0200162 }
Radek Krejci94ca54b2015-07-08 15:48:47 +0200163 }
Radek Krejcie4748472015-07-08 18:00:22 +0200164
Michal Vasko07471a52015-07-16 11:18:48 +0200165 data_type = ((struct ly_mnode_leaf *)leaf->schema)->type.base;
166 if (data_type == LY_TYPE_UNION) {
167 data_type = leaf->value_type;
168 }
169
170 switch (data_type) {
Radek Krejcie4748472015-07-08 18:00:22 +0200171 case LY_TYPE_BINARY:
172 case LY_TYPE_STRING:
Radek Krejci5a988152015-07-15 11:16:26 +0200173 fprintf(f, "\"%s\"", leaf->value.string ? leaf->value.string : "");
Radek Krejcie4748472015-07-08 18:00:22 +0200174 break;
Radek Krejci3e3affe2015-07-09 15:38:40 +0200175 case LY_TYPE_BITS:
Radek Krejci5a988152015-07-15 11:16:26 +0200176 fputc('"', f);
Radek Krejci3e3affe2015-07-09 15:38:40 +0200177
178 /* locate bits structure with the bits definitions to get the array size */
179 for (type = &sleaf->type; type->der->type.der; type = &type->der->type);
180
181 /* print set bits */
182 for (i = 0; i < type->info.bits.count; i++) {
183 if (leaf->value.bit[i]) {
184 fprintf(f, "%s%s", i ? " " : "", leaf->value.bit[i]->name);
185 }
186 }
Radek Krejci5a988152015-07-15 11:16:26 +0200187 fputc('"', f);
Radek Krejci3e3affe2015-07-09 15:38:40 +0200188 break;
Radek Krejcib7384642015-07-09 16:08:45 +0200189 case LY_TYPE_BOOL:
Radek Krejci5a988152015-07-15 11:16:26 +0200190 fprintf(f, "\"%s\"", leaf->value.bool ? "true" : "false");
Radek Krejcib7384642015-07-09 16:08:45 +0200191 break;
Radek Krejci7511f402015-07-10 09:56:30 +0200192 case LY_TYPE_DEC64:
193
194 /* locate dec structure with the fraction-digits definitions to get the value */
195 for (type = &sleaf->type; type->der->type.der; type = &type->der->type);
196
197 snprintf(dec, 21, "%" PRId64, leaf->value.dec64);
198 len = strlen(dec);
199 for (i = 0; dec[i]; ) {
200 fputc(dec[i++], f);
201 if (i + type->info.dec64.dig == len) {
202 fputc('.', f);
203 }
204 }
Radek Krejci7511f402015-07-10 09:56:30 +0200205
206 break;
Radek Krejcibce73742015-07-10 12:46:06 +0200207 case LY_TYPE_EMPTY:
Radek Krejci5a988152015-07-15 11:16:26 +0200208 fprintf(f, "[null]");
Radek Krejcibce73742015-07-10 12:46:06 +0200209 break;
Radek Krejci5b315a92015-07-10 13:18:45 +0200210 case LY_TYPE_ENUM:
Radek Krejci5a988152015-07-15 11:16:26 +0200211 fprintf(f, "\"%s\"", leaf->value.enm->name);
Radek Krejci5b315a92015-07-10 13:18:45 +0200212 break;
Radek Krejciac8aac62015-07-10 15:36:35 +0200213 case LY_TYPE_IDENT:
214 if (sleaf->module != leaf->value.ident->module) {
215 /* namespace identifier is needed */
Radek Krejci5a988152015-07-15 11:16:26 +0200216 fprintf(f, "\"%s:%s\"", leaf->value.ident->module->name, leaf->value.ident->name);
Radek Krejciac8aac62015-07-10 15:36:35 +0200217 } else {
218 /* no namespace is needed */
Radek Krejci5a988152015-07-15 11:16:26 +0200219 fprintf(f, "\"%s\"", leaf->value.ident->name);
Radek Krejciac8aac62015-07-10 15:36:35 +0200220 }
221 break;
Michal Vasko493bea72015-07-16 16:08:12 +0200222 case LY_TYPE_INST:
Michal Vasko8c9b7a72015-07-17 09:58:46 +0200223 fprintf(f, "\"");
224
225 ptr = NULL;
226 ptr2 = leaf->value_str;
227 while ((ptr = strchr(ptr2, '\"'))) {
228 fprintf(f, "%.*s\\\"", (int)(ptr-ptr2), ptr2);
229 ptr2 = ptr+1;
230 }
231
232 fprintf(f, "%s\"", ptr2);
Michal Vasko493bea72015-07-16 16:08:12 +0200233 break;
Radek Krejci5a988152015-07-15 11:16:26 +0200234 case LY_TYPE_LEAFREF:
235 json_print_leaf(f, level, leaf->value.leafref, 1);
236 break;
Michal Vasko58110162015-07-15 15:50:16 +0200237 case LY_TYPE_INT8:
238 fprintf(f, "\"%d\"", leaf->value.int8);
239 break;
240 case LY_TYPE_INT16:
241 fprintf(f, "\"%d\"", leaf->value.int16);
242 break;
243 case LY_TYPE_INT32:
244 fprintf(f, "\"%d\"", leaf->value.int32);
245 break;
246 case LY_TYPE_INT64:
247 fprintf(f, "\"%ld\"", leaf->value.int64);
248 break;
249 case LY_TYPE_UINT8:
250 fprintf(f, "\"%u\"", leaf->value.uint8);
251 break;
252 case LY_TYPE_UINT16:
253 fprintf(f, "\"%u\"", leaf->value.uint16);
254 break;
255 case LY_TYPE_UINT32:
256 fprintf(f, "\"%u\"", leaf->value.uint32);
257 break;
258 case LY_TYPE_UINT64:
259 fprintf(f, "\"%lu\"", leaf->value.uint64);
260 break;
Radek Krejcie4748472015-07-08 18:00:22 +0200261 default:
Michal Vasko493bea72015-07-16 16:08:12 +0200262 /* error */
263 fprintf(f, "\"(!error!)\"");
Radek Krejcie4748472015-07-08 18:00:22 +0200264 }
265
Radek Krejci5a988152015-07-15 11:16:26 +0200266 if (!onlyvalue) {
267 fprintf(f, "%s\n", node->next ? "," : "");
268 }
Radek Krejci94ca54b2015-07-08 15:48:47 +0200269}
270
Michal Vaskoab8e4402015-07-17 12:54:28 +0200271static void
272json_print_anyxml(FILE *f, int level, struct lyd_node *node)
273{
274 struct lyd_node_anyxml *axml = (struct lyd_node_anyxml *)node;
275
276 fprintf(f, "%*s\"%s\": [null]%s\n", LEVEL, INDENT, axml->value->name, node->next ? "," : "");
277}
278
Radek Krejci94ca54b2015-07-08 15:48:47 +0200279void
280json_print_node(FILE *f, int level, struct lyd_node *node)
281{
282 switch (node->schema->nodetype) {
Radek Krejci94ca54b2015-07-08 15:48:47 +0200283 case LY_NODE_CONTAINER:
284 json_print_container(f, level, node);
285 break;
Radek Krejci5a988152015-07-15 11:16:26 +0200286 case LY_NODE_LEAFLIST:
Radek Krejci94ca54b2015-07-08 15:48:47 +0200287 case LY_NODE_LEAF:
Radek Krejci5a988152015-07-15 11:16:26 +0200288 json_print_leaf(f, level, node, 0);
Radek Krejci94ca54b2015-07-08 15:48:47 +0200289 break;
Michal Vaskoab8e4402015-07-17 12:54:28 +0200290 case LY_NODE_LIST:
291 json_print_list(f, level, node);
292 break;
293 case LY_NODE_ANYXML:
294 json_print_anyxml(f, level, node);
295 break;
Radek Krejci94ca54b2015-07-08 15:48:47 +0200296 default:
Michal Vaskoab8e4402015-07-17 12:54:28 +0200297 assert(0);
Radek Krejci94ca54b2015-07-08 15:48:47 +0200298 break;
299 }
Radek Krejci94ca54b2015-07-08 15:48:47 +0200300}
301
Michal Vasko520d4732015-07-13 15:53:33 +0200302API int
Radek Krejci94ca54b2015-07-08 15:48:47 +0200303json_print_data(FILE *f, struct lyd_node *root)
304{
305 int level = 0;
306 struct lyd_node *node;
307
308 /* start */
309 fprintf(f, "{\n");
310
311 /* content */
312 LY_TREE_FOR(root, node) {
313 json_print_node(f, level + 1, node);
314 }
315
316 /* end */
317 fprintf(f, "}\n");
318
319 return EXIT_SUCCESS;
320}