blob: e45d44b0be31f8d823bf49f1827d6832e6639665 [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>
26
27#include "../common.h"
28#include "../tree.h"
29
30#define INDENT ""
31#define LEVEL (level*2)
32
33void json_print_node(FILE *f, int level, struct lyd_node *node);
34
35/* 0 - same, 1 - different */
36static int
37nscmp(struct lyd_node *node1, struct lyd_node *node2)
38{
39 struct ly_module *m1, *m2;
40
41 /* we have to cover submodules belonging to the same module */
42 if (node1->schema->module->type) {
43 m1 = ((struct ly_submodule *)node1->schema->module)->belongsto;
44 } else {
45 m1 = node1->schema->module;
46 }
47 if (node2->schema->module->type) {
48 m2 = ((struct ly_submodule *)node2->schema->module)->belongsto;
49 } else {
50 m2 = node2->schema->module;
51 }
52 if (m1 == m2) {
53 /* belongs to the same module */
54 return 0;
55 } else {
56 /* different modules */
57 return 1;
58 }
59}
60
61static void
62json_print_container(FILE *f, int level, struct lyd_node *node)
63{
64 const char *schema;
65 struct lyd_node *child;
66
67 if (!node->parent || nscmp(node, node->parent)) {
68 /* print "namespace" */
69 if (node->schema->module->type) {
70 /* submodule, get module */
71 schema = ((struct ly_submodule *)node->schema->module)->belongsto->name;
72 } else {
73 schema = node->schema->module->name;
74 }
75 fprintf(f, "%*s\"%s:%s\": {\n", LEVEL, INDENT, schema, node->schema->name);
76 } else {
77 fprintf(f, "%*s\"%s\": {\n", LEVEL, INDENT, node->schema->name);
78 }
79 LY_TREE_FOR(node->child, child) {
80 json_print_node(f, level + 1, child);
81 }
82 fprintf(f, "%*s}%s\n", LEVEL, INDENT, node->next ? "," : "");
83}
84
85static void
86json_print_list_internal(FILE *f, int level, struct lyd_node_list *list)
87{
88 struct lyd_node *child;
89
90 fprintf(f, "%*s{\n", LEVEL, INDENT);
91
Radek Krejci94ca54b2015-07-08 15:48:47 +020092 LY_TREE_FOR(list->child, child) {
93 json_print_node(f, level + 1, child);
94 }
95
96 fprintf(f, "%*s}%s\n", LEVEL, INDENT, list->lnext ? "," : "");
97}
98
99static void
100json_print_list(FILE *f, int level, struct lyd_node *node)
101{
102 const char *schema;
103 struct lyd_node_list *list = (struct lyd_node_list *)node;
104 struct lyd_node *iter;
105 char *delim = "";
106
107 if (list->lprev) {
108 /* this list is already printed */
109 return;
110 }
111
112 if (!node->parent || nscmp(node, node->parent)) {
113 /* print "namespace" */
114 if (node->schema->module->type) {
115 /* submodule, get module */
116 schema = ((struct ly_submodule *)node->schema->module)->belongsto->name;
117 } else {
118 schema = node->schema->module->name;
119 }
120 fprintf(f, "%*s\"%s:%s\": [\n", LEVEL, INDENT, schema, node->schema->name);
121 } else {
122 fprintf(f, "%*s\"%s\": [\n", LEVEL, INDENT, node->schema->name);
123 }
124
125 for(; list; list = list->lnext) {
126 json_print_list_internal(f, level + 1, list);
127 }
128 for (iter = node->next; iter; iter = iter->next) {
129 if (iter->schema != node->schema) {
130 delim = ",";
131 break;
132 }
133 }
134 fprintf(f, "%*s]%s\n", LEVEL, INDENT, delim);
135}
136
137static void
138json_print_leaf(FILE *f, int level, struct lyd_node *node)
139{
Radek Krejcie4748472015-07-08 18:00:22 +0200140 struct lyd_node_leaf *leaf = (struct lyd_node_leaf *)node;
Radek Krejci94ca54b2015-07-08 15:48:47 +0200141 const char *schema;
142
143 if (!node->parent || nscmp(node, node->parent)) {
144 /* print "namespace" */
145 if (node->schema->module->type) {
146 /* submodule, get module */
147 schema = ((struct ly_submodule *)node->schema->module)->belongsto->name;
148 } else {
149 schema = node->schema->module->name;
150 }
Radek Krejcie4748472015-07-08 18:00:22 +0200151 fprintf(f, "%*s\"%s:%s\": ", LEVEL, INDENT, schema, node->schema->name);
Radek Krejci94ca54b2015-07-08 15:48:47 +0200152 } else {
Radek Krejcie4748472015-07-08 18:00:22 +0200153 fprintf(f, "%*s\"%s\": ", LEVEL, INDENT, node->schema->name);
Radek Krejci94ca54b2015-07-08 15:48:47 +0200154 }
Radek Krejcie4748472015-07-08 18:00:22 +0200155
156 switch (((struct ly_mnode_leaf *)leaf->schema)->type.base) {
157 case LY_TYPE_BINARY:
158 case LY_TYPE_STRING:
159 fprintf(f, "\"%s\"%s\n", leaf->value.string, node->next ? "," : "");
160 break;
161 default:
162 /* TODO */
163 fprintf(f, "%s%s\n", "\"TBD\"", node->next ? "," : "");
164 }
165
Radek Krejci94ca54b2015-07-08 15:48:47 +0200166}
167
168void
169json_print_node(FILE *f, int level, struct lyd_node *node)
170{
171 switch (node->schema->nodetype) {
172 case LY_NODE_LIST:
173 json_print_list(f, level, node);
174 break;
175 case LY_NODE_CONTAINER:
176 json_print_container(f, level, node);
177 break;
178 case LY_NODE_LEAF:
179 json_print_leaf(f, level, node);
180 break;
181 default:
182 /* TODO: remove when all node types are covered */
183 break;
184 }
185
186}
187
188int
189json_print_data(FILE *f, struct lyd_node *root)
190{
191 int level = 0;
192 struct lyd_node *node;
193
194 /* start */
195 fprintf(f, "{\n");
196
197 /* content */
198 LY_TREE_FOR(root, node) {
199 json_print_node(f, level + 1, node);
200 }
201
202 /* end */
203 fprintf(f, "}\n");
204
205 return EXIT_SUCCESS;
206}