blob: f60e9abb1d0ddede421254776b86cf594725478c [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
Radek Krejci998a0b82015-08-17 13:14:36 +020028#include "common.h"
29#include "xml.h"
Michal Vasko2d162e12015-09-24 14:33:29 +020030#include "tree_data.h"
Radek Krejci998a0b82015-08-17 13:14:36 +020031#include "resolve.h"
32#include "tree_internal.h"
Radek Krejci94ca54b2015-07-08 15:48:47 +020033
34#define INDENT ""
35#define LEVEL (level*2)
36
Radek Krejci27aaa732015-09-04 15:24:04 +020037void json_print_nodes(FILE *f, int level, struct lyd_node *root);
Radek Krejci94ca54b2015-07-08 15:48:47 +020038
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
Radek Krejci5a988152015-07-15 11:16:26 +020066json_print_leaf(FILE *f, int level, struct lyd_node *node, int onlyvalue)
Radek Krejci94ca54b2015-07-08 15:48:47 +020067{
Michal Vasko4c183312015-09-25 10:41:47 +020068 struct lyd_node_leaf_list *leaf = (struct lyd_node_leaf_list *)node;
Michal Vasko07471a52015-07-16 11:18:48 +020069 LY_DATA_TYPE data_type;
Michal Vaskoc82396e2015-07-17 15:31:25 +020070 const char *schema;
Radek Krejci94ca54b2015-07-08 15:48:47 +020071
Radek Krejci5a988152015-07-15 11:16:26 +020072 if (!onlyvalue) {
73 if (!node->parent || nscmp(node, node->parent)) {
74 /* print "namespace" */
75 if (node->schema->module->type) {
76 /* submodule, get module */
Radek Krejcib8048692015-08-05 13:36:34 +020077 schema = ((struct lys_submodule *)node->schema->module)->belongsto->name;
Radek Krejci5a988152015-07-15 11:16:26 +020078 } else {
79 schema = node->schema->module->name;
80 }
81 fprintf(f, "%*s\"%s:%s\": ", LEVEL, INDENT, schema, node->schema->name);
Radek Krejci94ca54b2015-07-08 15:48:47 +020082 } else {
Radek Krejci5a988152015-07-15 11:16:26 +020083 fprintf(f, "%*s\"%s\": ", LEVEL, INDENT, node->schema->name);
Radek Krejci94ca54b2015-07-08 15:48:47 +020084 }
Radek Krejci94ca54b2015-07-08 15:48:47 +020085 }
Radek Krejcie4748472015-07-08 18:00:22 +020086
Radek Krejci25b9fd32015-08-10 15:06:07 +020087 data_type = leaf->value_type;
Michal Vasko07471a52015-07-16 11:18:48 +020088
Radek Krejcib1c12512015-08-11 11:22:04 +020089 switch (data_type & LY_DATA_TYPE_MASK) {
Radek Krejcie4748472015-07-08 18:00:22 +020090 case LY_TYPE_BINARY:
91 case LY_TYPE_STRING:
Radek Krejci3e3affe2015-07-09 15:38:40 +020092 case LY_TYPE_BITS:
Radek Krejci5b315a92015-07-10 13:18:45 +020093 case LY_TYPE_ENUM:
Radek Krejciac8aac62015-07-10 15:36:35 +020094 case LY_TYPE_IDENT:
Radek Krejcic5090c32015-08-12 09:46:19 +020095 case LY_TYPE_INST:
Radek Krejcib1c12512015-08-11 11:22:04 +020096 fprintf(f, "\"%s\"", leaf->value_str ? leaf->value_str : "");
Radek Krejciac8aac62015-07-10 15:36:35 +020097 break;
Radek Krejcib1c12512015-08-11 11:22:04 +020098
99 case LY_TYPE_BOOL:
100 case LY_TYPE_DEC64:
101 case LY_TYPE_INT8:
102 case LY_TYPE_INT16:
103 case LY_TYPE_INT32:
104 case LY_TYPE_INT64:
105 case LY_TYPE_UINT8:
106 case LY_TYPE_UINT16:
107 case LY_TYPE_UINT32:
108 case LY_TYPE_UINT64:
109 fprintf(f, "%s", leaf->value_str ? leaf->value_str : "");
110 break;
111
Radek Krejci5a988152015-07-15 11:16:26 +0200112 case LY_TYPE_LEAFREF:
113 json_print_leaf(f, level, leaf->value.leafref, 1);
114 break;
Radek Krejcib1c12512015-08-11 11:22:04 +0200115
116 case LY_TYPE_EMPTY:
117 fprintf(f, "[null]");
Michal Vasko58110162015-07-15 15:50:16 +0200118 break;
Radek Krejcib1c12512015-08-11 11:22:04 +0200119
Radek Krejcie4748472015-07-08 18:00:22 +0200120 default:
Michal Vasko493bea72015-07-16 16:08:12 +0200121 /* error */
122 fprintf(f, "\"(!error!)\"");
Radek Krejcie4748472015-07-08 18:00:22 +0200123 }
124
Radek Krejcib1c12512015-08-11 11:22:04 +0200125 return;
Radek Krejci94ca54b2015-07-08 15:48:47 +0200126}
127
Michal Vaskoab8e4402015-07-17 12:54:28 +0200128static void
Michal Vasko98763c62015-07-17 13:47:00 +0200129json_print_container(FILE *f, int level, struct lyd_node *node)
130{
131 const char *schema;
Michal Vasko98763c62015-07-17 13:47:00 +0200132
133 if (!node->parent || nscmp(node, node->parent)) {
134 /* print "namespace" */
135 if (node->schema->module->type) {
136 /* submodule, get module */
Radek Krejcib8048692015-08-05 13:36:34 +0200137 schema = ((struct lys_submodule *)node->schema->module)->belongsto->name;
Michal Vasko98763c62015-07-17 13:47:00 +0200138 } else {
139 schema = node->schema->module->name;
140 }
141 fprintf(f, "%*s\"%s:%s\": {\n", LEVEL, INDENT, schema, node->schema->name);
142 } else {
143 fprintf(f, "%*s\"%s\": {\n", LEVEL, INDENT, node->schema->name);
144 }
Radek Krejci27aaa732015-09-04 15:24:04 +0200145 json_print_nodes(f, level + 1, node->child);
146 fprintf(f, "%*s}", LEVEL, INDENT);
Michal Vasko98763c62015-07-17 13:47:00 +0200147}
148
149static void
150json_print_leaf_list(FILE *f, int level, struct lyd_node *node, int is_list)
151{
152 const char *schema;
Radek Krejci27aaa732015-09-04 15:24:04 +0200153 struct lyd_node *list = node;
Michal Vasko98763c62015-07-17 13:47:00 +0200154
155 if (!node->parent || nscmp(node, node->parent)) {
156 /* print "namespace" */
157 if (node->schema->module->type) {
158 /* submodule, get module */
Radek Krejcib8048692015-08-05 13:36:34 +0200159 schema = ((struct lys_submodule *)node->schema->module)->belongsto->name;
Michal Vasko98763c62015-07-17 13:47:00 +0200160 } else {
161 schema = node->schema->module->name;
162 }
163 fprintf(f, "%*s\"%s:%s\": [\n", LEVEL, INDENT, schema, node->schema->name);
164 } else {
165 fprintf(f, "%*s\"%s\": [\n", LEVEL, INDENT, node->schema->name);
166 }
167
168 if (!is_list) {
169 ++level;
170 }
Radek Krejci27aaa732015-09-04 15:24:04 +0200171
172 while (list) {
Michal Vasko98763c62015-07-17 13:47:00 +0200173 if (is_list) {
Radek Krejci27aaa732015-09-04 15:24:04 +0200174 /* list print */
175 ++level;
176 fprintf(f, "%*s{\n", LEVEL, INDENT);
177 json_print_nodes(f, level + 1, list->child);
178 fprintf(f, "%*s}", LEVEL, INDENT);
179 --level;
Michal Vasko98763c62015-07-17 13:47:00 +0200180 } else {
Radek Krejci27aaa732015-09-04 15:24:04 +0200181 /* leaf-list print */
Michal Vasko98763c62015-07-17 13:47:00 +0200182 fprintf(f, "%*s", LEVEL, INDENT);
Radek Krejci27aaa732015-09-04 15:24:04 +0200183 json_print_leaf(f, level, list, 1);
184 }
185 for (list = list->next; list && list->schema != node->schema; list = list->next);
186 if (list) {
187 fprintf(f, ",\n");
Michal Vasko98763c62015-07-17 13:47:00 +0200188 }
189 }
Radek Krejci27aaa732015-09-04 15:24:04 +0200190
Michal Vasko98763c62015-07-17 13:47:00 +0200191 if (!is_list) {
192 --level;
193 }
194
Radek Krejci27aaa732015-09-04 15:24:04 +0200195 fprintf(f, "\n%*s]", LEVEL, INDENT);
Michal Vasko98763c62015-07-17 13:47:00 +0200196}
197
198static void
Michal Vaskoab8e4402015-07-17 12:54:28 +0200199json_print_anyxml(FILE *f, int level, struct lyd_node *node)
200{
Radek Krejci27aaa732015-09-04 15:24:04 +0200201 fprintf(f, "%*s\"%s\": [null]", LEVEL, INDENT, node->schema->name);
Michal Vaskoab8e4402015-07-17 12:54:28 +0200202}
203
Radek Krejci94ca54b2015-07-08 15:48:47 +0200204void
Radek Krejci27aaa732015-09-04 15:24:04 +0200205json_print_nodes(FILE *f, int level, struct lyd_node *root)
Radek Krejci94ca54b2015-07-08 15:48:47 +0200206{
Radek Krejci27aaa732015-09-04 15:24:04 +0200207 struct lyd_node *node, *iter;
208
209 LY_TREE_FOR(root, node) {
210 switch (node->schema->nodetype) {
Radek Krejcifb54be42015-10-02 15:21:16 +0200211 case LYS_RPC:
212 case LYS_NOTIF:
Radek Krejci27aaa732015-09-04 15:24:04 +0200213 case LYS_CONTAINER:
214 if (node->prev->next) {
215 /* print the previous comma */
216 fprintf(f, ",\n");
217 }
218 json_print_container(f, level, node);
219 break;
220 case LYS_LEAF:
221 if (node->prev->next) {
222 /* print the previous comma */
223 fprintf(f, ",\n");
224 }
225 json_print_leaf(f, level, node, 0);
226 break;
227 case LYS_LEAFLIST:
228 case LYS_LIST:
229 /* is it already printed? */
230 for (iter = node; iter->prev->next; iter = iter->prev) {
231 if (iter == node) {
232 continue;
233 }
234 if (iter->schema == node->schema) {
235 /* the list has alread some previous instance and therefore it is already printed */
236 break;
237 }
238 }
239 if (!iter->prev->next) {
240 if (node->prev->next) {
241 /* print the previous comma */
242 fprintf(f, ",\n");
243 }
244
245 /* print the list/leaflist */
246 json_print_leaf_list(f, level, node, node->schema->nodetype == LYS_LIST ? 1 : 0);
247 }
248 break;
249 case LYS_ANYXML:
250 if (node->prev->next) {
251 /* print the previous comma */
252 fprintf(f, ",\n");
253 }
254 json_print_anyxml(f, level, node);
255 break;
256 default:
257 LOGINT;
258 break;
259 }
Radek Krejci94ca54b2015-07-08 15:48:47 +0200260 }
Radek Krejci27aaa732015-09-04 15:24:04 +0200261 fprintf(f, "\n");
Radek Krejci94ca54b2015-07-08 15:48:47 +0200262}
263
Radek Krejcif3752b02015-10-02 15:31:34 +0200264int
Radek Krejci94ca54b2015-07-08 15:48:47 +0200265json_print_data(FILE *f, struct lyd_node *root)
266{
267 int level = 0;
Radek Krejci94ca54b2015-07-08 15:48:47 +0200268
269 /* start */
270 fprintf(f, "{\n");
271
272 /* content */
Radek Krejci27aaa732015-09-04 15:24:04 +0200273 json_print_nodes(f, level + 1, root);
Radek Krejci94ca54b2015-07-08 15:48:47 +0200274
275 /* end */
276 fprintf(f, "}\n");
277
278 return EXIT_SUCCESS;
279}