|
Packit |
8fb591 |
/**
|
|
Packit |
8fb591 |
* @file printer/json.c
|
|
Packit |
8fb591 |
* @author Radek Krejci <rkrejci@cesnet.cz>
|
|
Packit |
8fb591 |
* @brief JSON printer for libyang data structure
|
|
Packit |
8fb591 |
*
|
|
Packit |
8fb591 |
* Copyright (c) 2015 CESNET, z.s.p.o.
|
|
Packit |
8fb591 |
*
|
|
Packit |
8fb591 |
* This source code is licensed under BSD 3-Clause License (the "License").
|
|
Packit |
8fb591 |
* You may not use this file except in compliance with the License.
|
|
Packit |
8fb591 |
* You may obtain a copy of the License at
|
|
Packit |
8fb591 |
*
|
|
Packit |
8fb591 |
* https://opensource.org/licenses/BSD-3-Clause
|
|
Packit |
8fb591 |
*/
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
#include <stdlib.h>
|
|
Packit |
8fb591 |
#include <stdio.h>
|
|
Packit |
8fb591 |
#include <string.h>
|
|
Packit |
8fb591 |
#include <assert.h>
|
|
Packit |
8fb591 |
#include <inttypes.h>
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
#include "common.h"
|
|
Packit |
8fb591 |
#include "printer.h"
|
|
Packit |
8fb591 |
#include "tree_data.h"
|
|
Packit |
8fb591 |
#include "resolve.h"
|
|
Packit |
8fb591 |
#include "tree_internal.h"
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
#define INDENT ""
|
|
Packit |
8fb591 |
#define LEVEL (level*2)
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
static int json_print_nodes(struct lyout *out, int level, const struct lyd_node *root, int withsiblings, int toplevel,
|
|
Packit |
8fb591 |
int options);
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
int
|
|
Packit |
8fb591 |
json_print_string(struct lyout *out, const char *text)
|
|
Packit |
8fb591 |
{
|
|
Packit |
8fb591 |
unsigned int i, n;
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
if (!text) {
|
|
Packit |
8fb591 |
return 0;
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
ly_write(out, "\"", 1);
|
|
Packit |
8fb591 |
for (i = n = 0; text[i]; i++) {
|
|
Packit |
8fb591 |
const unsigned char ascii = text[i];
|
|
Packit |
8fb591 |
if (ascii < 0x20) {
|
|
Packit |
8fb591 |
/* control character */
|
|
Packit |
8fb591 |
n += ly_print(out, "\\u%.4X", ascii);
|
|
Packit |
8fb591 |
} else {
|
|
Packit |
8fb591 |
switch (ascii) {
|
|
Packit |
8fb591 |
case '"':
|
|
Packit |
8fb591 |
n += ly_print(out, "\\\"");
|
|
Packit |
8fb591 |
break;
|
|
Packit |
8fb591 |
case '\\':
|
|
Packit |
8fb591 |
n += ly_print(out, "\\\\");
|
|
Packit |
8fb591 |
break;
|
|
Packit |
8fb591 |
default:
|
|
Packit |
8fb591 |
ly_write(out, &text[i], 1);
|
|
Packit |
8fb591 |
n++;
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
ly_write(out, "\"", 1);
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
return n + 2;
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
static int
|
|
Packit |
8fb591 |
json_print_attrs(struct lyout *out, int level, const struct lyd_node *node, const struct lys_module *wdmod)
|
|
Packit |
8fb591 |
{
|
|
Packit |
8fb591 |
struct lyd_attr *attr;
|
|
Packit |
8fb591 |
size_t len;
|
|
Packit |
8fb591 |
char *p;
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
if (wdmod) {
|
|
Packit |
8fb591 |
ly_print(out, "%*s\"%s:default\":\"true\"", LEVEL, INDENT, wdmod->name);
|
|
Packit |
8fb591 |
ly_print(out, "%s%s", node->attr ? "," : "", (level ? "\n" : ""));
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
for (attr = node->attr; attr; attr = attr->next) {
|
|
Packit |
8fb591 |
if (!attr->annotation) {
|
|
Packit |
8fb591 |
/* skip exception for the NETCONF's attribute since JSON is not defined for NETCONF */
|
|
Packit |
8fb591 |
continue;
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
if (lys_main_module(attr->annotation->module) != lys_main_module(node->schema->module)) {
|
|
Packit |
8fb591 |
ly_print(out, "%*s\"%s:%s\":", LEVEL, INDENT, attr->annotation->module->name, attr->name);
|
|
Packit |
8fb591 |
} else {
|
|
Packit |
8fb591 |
ly_print(out, "%*s\"%s\":", LEVEL, INDENT, attr->name);
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
/* leafref is not supported */
|
|
Packit |
8fb591 |
switch (attr->value_type) {
|
|
Packit |
8fb591 |
case LY_TYPE_BINARY:
|
|
Packit |
8fb591 |
case LY_TYPE_STRING:
|
|
Packit |
8fb591 |
case LY_TYPE_BITS:
|
|
Packit |
8fb591 |
case LY_TYPE_ENUM:
|
|
Packit |
8fb591 |
case LY_TYPE_INST:
|
|
Packit |
8fb591 |
case LY_TYPE_INT64:
|
|
Packit |
8fb591 |
case LY_TYPE_UINT64:
|
|
Packit |
8fb591 |
case LY_TYPE_DEC64:
|
|
Packit |
8fb591 |
json_print_string(out, attr->value_str);
|
|
Packit |
8fb591 |
break;
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
case LY_TYPE_INT8:
|
|
Packit |
8fb591 |
case LY_TYPE_INT16:
|
|
Packit |
8fb591 |
case LY_TYPE_INT32:
|
|
Packit |
8fb591 |
case LY_TYPE_UINT8:
|
|
Packit |
8fb591 |
case LY_TYPE_UINT16:
|
|
Packit |
8fb591 |
case LY_TYPE_UINT32:
|
|
Packit |
8fb591 |
case LY_TYPE_BOOL:
|
|
Packit |
8fb591 |
ly_print(out, "%s", attr->value_str[0] ? attr->value_str : "null");
|
|
Packit |
8fb591 |
break;
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
case LY_TYPE_IDENT:
|
|
Packit |
8fb591 |
p = strchr(attr->value_str, ':');
|
|
Packit |
8fb591 |
assert(p);
|
|
Packit |
8fb591 |
len = p - attr->value_str;
|
|
Packit |
8fb591 |
if (!strncmp(attr->value_str, attr->annotation->module->name, len)
|
|
Packit |
8fb591 |
&& !attr->annotation->module->name[len]) {
|
|
Packit |
8fb591 |
/* do not print the prefix, it is the default prefix for this node */
|
|
Packit |
8fb591 |
json_print_string(out, ++p);
|
|
Packit |
8fb591 |
} else {
|
|
Packit |
8fb591 |
json_print_string(out, attr->value_str);
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
break;
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
case LY_TYPE_EMPTY:
|
|
Packit |
8fb591 |
ly_print(out, "[null]");
|
|
Packit |
8fb591 |
break;
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
default:
|
|
Packit |
8fb591 |
/* error */
|
|
Packit |
8fb591 |
ly_print(out, "\"(!error!)\"");
|
|
Packit |
8fb591 |
return EXIT_FAILURE;
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
ly_print(out, "%s%s", attr->next ? "," : "", (level ? "\n" : ""));
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
return EXIT_SUCCESS;
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
static int
|
|
Packit |
8fb591 |
json_print_leaf(struct lyout *out, int level, const struct lyd_node *node, int onlyvalue, int toplevel, int options)
|
|
Packit |
8fb591 |
{
|
|
Packit |
8fb591 |
struct lyd_node_leaf_list *leaf = (struct lyd_node_leaf_list *)node, *iter;
|
|
Packit |
8fb591 |
const struct lys_type *type;
|
|
Packit |
8fb591 |
const char *schema = NULL, *p, *mod_name;
|
|
Packit |
8fb591 |
const struct lys_module *wdmod = NULL;
|
|
Packit |
8fb591 |
LY_DATA_TYPE datatype;
|
|
Packit |
8fb591 |
size_t len;
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
if ((node->dflt && (options & (LYP_WD_ALL_TAG | LYP_WD_IMPL_TAG))) ||
|
|
Packit |
8fb591 |
(!node->dflt && (options & LYP_WD_ALL_TAG) && lyd_wd_default(leaf))) {
|
|
Packit |
8fb591 |
/* we have implicit OR explicit default node */
|
|
Packit |
8fb591 |
/* get with-defaults module */
|
|
Packit |
8fb591 |
wdmod = ly_ctx_get_module(node->schema->module->ctx, "ietf-netconf-with-defaults", NULL, 1);
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
if (!onlyvalue) {
|
|
Packit |
8fb591 |
if (toplevel || !node->parent || nscmp(node, node->parent)) {
|
|
Packit |
8fb591 |
/* print "namespace" */
|
|
Packit |
8fb591 |
schema = lys_node_module(node->schema)->name;
|
|
Packit |
8fb591 |
ly_print(out, "%*s\"%s:%s\":%s", LEVEL, INDENT, schema, node->schema->name, (level ? " " : ""));
|
|
Packit |
8fb591 |
} else {
|
|
Packit |
8fb591 |
ly_print(out, "%*s\"%s\":%s", LEVEL, INDENT, node->schema->name, (level ? " " : ""));
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
datatype = leaf->value_type;
|
|
Packit |
8fb591 |
contentprint:
|
|
Packit |
8fb591 |
switch (datatype) {
|
|
Packit |
8fb591 |
case LY_TYPE_BINARY:
|
|
Packit |
8fb591 |
case LY_TYPE_STRING:
|
|
Packit |
8fb591 |
case LY_TYPE_BITS:
|
|
Packit |
8fb591 |
case LY_TYPE_ENUM:
|
|
Packit |
8fb591 |
case LY_TYPE_INST:
|
|
Packit |
8fb591 |
case LY_TYPE_INT64:
|
|
Packit |
8fb591 |
case LY_TYPE_UINT64:
|
|
Packit |
8fb591 |
case LY_TYPE_UNION:
|
|
Packit |
8fb591 |
case LY_TYPE_DEC64:
|
|
Packit |
8fb591 |
json_print_string(out, leaf->value_str);
|
|
Packit |
8fb591 |
break;
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
case LY_TYPE_INT8:
|
|
Packit |
8fb591 |
case LY_TYPE_INT16:
|
|
Packit |
8fb591 |
case LY_TYPE_INT32:
|
|
Packit |
8fb591 |
case LY_TYPE_UINT8:
|
|
Packit |
8fb591 |
case LY_TYPE_UINT16:
|
|
Packit |
8fb591 |
case LY_TYPE_UINT32:
|
|
Packit |
8fb591 |
case LY_TYPE_BOOL:
|
|
Packit |
8fb591 |
ly_print(out, "%s", leaf->value_str[0] ? leaf->value_str : "null");
|
|
Packit |
8fb591 |
break;
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
case LY_TYPE_IDENT:
|
|
Packit |
8fb591 |
p = strchr(leaf->value_str, ':');
|
|
Packit |
8fb591 |
assert(p);
|
|
Packit |
8fb591 |
len = p - leaf->value_str;
|
|
Packit |
8fb591 |
mod_name = leaf->schema->module->name;
|
|
Packit |
8fb591 |
if (!strncmp(leaf->value_str, mod_name, len) && !mod_name[len]) {
|
|
Packit |
8fb591 |
/* do not print the prefix, it is the default prefix for this node */
|
|
Packit |
8fb591 |
json_print_string(out, ++p);
|
|
Packit |
8fb591 |
} else {
|
|
Packit |
8fb591 |
json_print_string(out, leaf->value_str);
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
break;
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
case LY_TYPE_LEAFREF:
|
|
Packit |
8fb591 |
iter = (struct lyd_node_leaf_list *)leaf->value.leafref;
|
|
Packit |
8fb591 |
while (iter && (iter->value_type == LY_TYPE_LEAFREF)) {
|
|
Packit |
8fb591 |
iter = (struct lyd_node_leaf_list *)iter->value.leafref;
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
if (!iter) {
|
|
Packit |
8fb591 |
/* unresolved and invalid, but we can learn the correct type anyway */
|
|
Packit |
8fb591 |
type = lyd_leaf_type((struct lyd_node_leaf_list *)leaf);
|
|
Packit |
8fb591 |
if (!type) {
|
|
Packit |
8fb591 |
/* error */
|
|
Packit |
8fb591 |
ly_print(out, "\"(!error!)\"");
|
|
Packit |
8fb591 |
return EXIT_FAILURE;
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
datatype = type->base;
|
|
Packit |
8fb591 |
} else {
|
|
Packit |
8fb591 |
datatype = iter->value_type;
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
goto contentprint;
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
case LY_TYPE_EMPTY:
|
|
Packit |
8fb591 |
ly_print(out, "[null]");
|
|
Packit |
8fb591 |
break;
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
default:
|
|
Packit |
8fb591 |
/* error */
|
|
Packit |
8fb591 |
ly_print(out, "\"(!error!)\"");
|
|
Packit |
8fb591 |
return EXIT_FAILURE;
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
/* print attributes as sibling leafs */
|
|
Packit |
8fb591 |
if (!onlyvalue && (node->attr || wdmod)) {
|
|
Packit |
8fb591 |
if (schema) {
|
|
Packit |
8fb591 |
ly_print(out, ",%s%*s\"@%s:%s\":%s{%s", (level ? "\n" : ""), LEVEL, INDENT, schema, node->schema->name,
|
|
Packit |
8fb591 |
(level ? " " : ""), (level ? "\n" : ""));
|
|
Packit |
8fb591 |
} else {
|
|
Packit |
8fb591 |
ly_print(out, ",%s%*s\"@%s\":%s{%s", (level ? "\n" : ""), LEVEL, INDENT, node->schema->name,
|
|
Packit |
8fb591 |
(level ? " " : ""), (level ? "\n" : ""));
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
if (json_print_attrs(out, (level ? level + 1 : level), node, wdmod)) {
|
|
Packit |
8fb591 |
return EXIT_FAILURE;
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
ly_print(out, "%*s}", LEVEL, INDENT);
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
return EXIT_SUCCESS;
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
static int
|
|
Packit |
8fb591 |
json_print_container(struct lyout *out, int level, const struct lyd_node *node, int toplevel, int options)
|
|
Packit |
8fb591 |
{
|
|
Packit |
8fb591 |
const char *schema;
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
if (toplevel || !node->parent || nscmp(node, node->parent)) {
|
|
Packit |
8fb591 |
/* print "namespace" */
|
|
Packit |
8fb591 |
schema = lys_node_module(node->schema)->name;
|
|
Packit |
8fb591 |
ly_print(out, "%*s\"%s:%s\":%s{%s", LEVEL, INDENT, schema, node->schema->name, (level ? " " : ""), (level ? "\n" : ""));
|
|
Packit |
8fb591 |
} else {
|
|
Packit |
8fb591 |
ly_print(out, "%*s\"%s\":%s{%s", LEVEL, INDENT, node->schema->name, (level ? " " : ""), (level ? "\n" : ""));
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
if (level) {
|
|
Packit |
8fb591 |
level++;
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
if (node->attr) {
|
|
Packit |
8fb591 |
ly_print(out, "%*s\"@\":%s{%s", LEVEL, INDENT, (level ? " " : ""), (level ? "\n" : ""));
|
|
Packit |
8fb591 |
if (json_print_attrs(out, (level ? level + 1 : level), node, NULL)) {
|
|
Packit |
8fb591 |
return EXIT_FAILURE;
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
ly_print(out, "%*s}", LEVEL, INDENT);
|
|
Packit |
8fb591 |
if (node->child) {
|
|
Packit |
8fb591 |
ly_print(out, ",%s", (level ? "\n" : ""));
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
if (json_print_nodes(out, level, node->child, 1, 0, options)) {
|
|
Packit |
8fb591 |
return EXIT_FAILURE;
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
if (level) {
|
|
Packit |
8fb591 |
level--;
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
ly_print(out, "%*s}", LEVEL, INDENT);
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
return EXIT_SUCCESS;
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
static int
|
|
Packit |
8fb591 |
json_print_leaf_list(struct lyout *out, int level, const struct lyd_node *node, int is_list, int toplevel, int options)
|
|
Packit |
8fb591 |
{
|
|
Packit |
8fb591 |
const char *schema = NULL;
|
|
Packit |
8fb591 |
const struct lyd_node *list = node;
|
|
Packit |
8fb591 |
int flag_empty = 0, flag_attrs = 0;
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
if (is_list && !list->child) {
|
|
Packit |
8fb591 |
/* empty, e.g. in case of filter */
|
|
Packit |
8fb591 |
flag_empty = 1;
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
if (toplevel || !node->parent || nscmp(node, node->parent)) {
|
|
Packit |
8fb591 |
/* print "namespace" */
|
|
Packit |
8fb591 |
schema = lys_node_module(node->schema)->name;
|
|
Packit |
8fb591 |
ly_print(out, "%*s\"%s:%s\":", LEVEL, INDENT, schema, node->schema->name);
|
|
Packit |
8fb591 |
} else {
|
|
Packit |
8fb591 |
ly_print(out, "%*s\"%s\":", LEVEL, INDENT, node->schema->name);
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
if (flag_empty) {
|
|
Packit |
8fb591 |
ly_print(out, "%snull", (level ? " " : ""));
|
|
Packit |
8fb591 |
return EXIT_SUCCESS;
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
ly_print(out, "%s[%s", (level ? " " : ""), (level ? "\n" : ""));
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
if (!is_list && level) {
|
|
Packit |
8fb591 |
++level;
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
while (list) {
|
|
Packit |
8fb591 |
if (is_list) {
|
|
Packit |
8fb591 |
/* list print */
|
|
Packit |
8fb591 |
if (level) {
|
|
Packit |
8fb591 |
++level;
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
ly_print(out, "%*s{%s", LEVEL, INDENT, (level ? "\n" : ""));
|
|
Packit |
8fb591 |
if (level) {
|
|
Packit |
8fb591 |
++level;
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
if (list->attr) {
|
|
Packit |
8fb591 |
ly_print(out, "%*s\"@\":%s{%s", LEVEL, INDENT, (level ? " " : ""), (level ? "\n" : ""));
|
|
Packit |
8fb591 |
if (json_print_attrs(out, (level ? level + 1 : level), list, NULL)) {
|
|
Packit |
8fb591 |
return EXIT_FAILURE;
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
if (list->child) {
|
|
Packit |
8fb591 |
ly_print(out, "%*s},%s", LEVEL, INDENT, (level ? "\n" : ""));
|
|
Packit |
8fb591 |
} else {
|
|
Packit |
8fb591 |
ly_print(out, "%*s}", LEVEL, INDENT);
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
if (json_print_nodes(out, level, list->child, 1, 0, options)) {
|
|
Packit |
8fb591 |
return EXIT_FAILURE;
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
if (level) {
|
|
Packit |
8fb591 |
--level;
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
ly_print(out, "%*s}", LEVEL, INDENT);
|
|
Packit |
8fb591 |
if (level) {
|
|
Packit |
8fb591 |
--level;
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
} else {
|
|
Packit |
8fb591 |
/* leaf-list print */
|
|
Packit |
8fb591 |
ly_print(out, "%*s", LEVEL, INDENT);
|
|
Packit |
8fb591 |
if (json_print_leaf(out, level, list, 1, toplevel, options)) {
|
|
Packit |
8fb591 |
return EXIT_FAILURE;
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
if (list->attr) {
|
|
Packit |
8fb591 |
flag_attrs = 1;
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
if (toplevel && !(options & LYP_WITHSIBLINGS)) {
|
|
Packit |
8fb591 |
/* if initially called without LYP_WITHSIBLINGS do not print other list entries */
|
|
Packit |
8fb591 |
break;
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
for (list = list->next; list && list->schema != node->schema; list = list->next);
|
|
Packit |
8fb591 |
if (list) {
|
|
Packit |
8fb591 |
ly_print(out, ",%s", (level ? "\n" : ""));
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
if (!is_list && level) {
|
|
Packit |
8fb591 |
--level;
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
ly_print(out, "%s%*s]", (level ? "\n" : ""), LEVEL, INDENT);
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
/* attributes */
|
|
Packit |
8fb591 |
if (!is_list && flag_attrs) {
|
|
Packit |
8fb591 |
if (schema) {
|
|
Packit |
8fb591 |
ly_print(out, ",%s%*s\"@%s:%s\":%s[%s", (level ? "\n" : ""), LEVEL, INDENT, schema, node->schema->name,
|
|
Packit |
8fb591 |
(level ? " " : ""), (level ? "\n" : ""));
|
|
Packit |
8fb591 |
} else {
|
|
Packit |
8fb591 |
ly_print(out, ",%s%*s\"@%s\":%s[%s", (level ? "\n" : ""), LEVEL, INDENT, node->schema->name,
|
|
Packit |
8fb591 |
(level ? " " : ""), (level ? "\n" : ""));
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
if (level) {
|
|
Packit |
8fb591 |
level++;
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
for (list = node; list; ) {
|
|
Packit |
8fb591 |
if (list->attr) {
|
|
Packit |
8fb591 |
ly_print(out, "%*s{%s", LEVEL, INDENT, (level ? " " : ""));
|
|
Packit |
8fb591 |
if (json_print_attrs(out, 0, list, NULL)) {
|
|
Packit |
8fb591 |
return EXIT_FAILURE;
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
ly_print(out, "%*s}", LEVEL, INDENT);
|
|
Packit |
8fb591 |
} else {
|
|
Packit |
8fb591 |
ly_print(out, "%*snull", LEVEL, INDENT);
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
for (list = list->next; list && list->schema != node->schema; list = list->next);
|
|
Packit |
8fb591 |
if (list) {
|
|
Packit |
8fb591 |
ly_print(out, ",%s", (level ? "\n" : ""));
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
if (level) {
|
|
Packit |
8fb591 |
level--;
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
ly_print(out, "%s%*s]", (level ? "\n" : ""), LEVEL, INDENT);
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
return EXIT_SUCCESS;
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
static int
|
|
Packit |
8fb591 |
json_print_anydataxml(struct lyout *out, int level, const struct lyd_node *node, int toplevel, int options)
|
|
Packit |
8fb591 |
{
|
|
Packit |
8fb591 |
struct lyd_node_anydata *any = (struct lyd_node_anydata *)node;
|
|
Packit |
8fb591 |
int is_object = 0;
|
|
Packit |
8fb591 |
char *buf;
|
|
Packit |
8fb591 |
const char *schema = NULL;
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
if (toplevel || !node->parent || nscmp(node, node->parent)) {
|
|
Packit |
8fb591 |
/* print "namespace" */
|
|
Packit |
8fb591 |
schema = lys_node_module(node->schema)->name;
|
|
Packit |
8fb591 |
ly_print(out, "%*s\"%s:%s\":", LEVEL, INDENT, schema, node->schema->name);
|
|
Packit |
8fb591 |
} else {
|
|
Packit |
8fb591 |
ly_print(out, "%*s\"%s\":", LEVEL, INDENT, node->schema->name);
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
if (level) {
|
|
Packit |
8fb591 |
level++;
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
switch (any->value_type) {
|
|
Packit |
8fb591 |
case LYD_ANYDATA_DATATREE:
|
|
Packit |
8fb591 |
is_object = 1;
|
|
Packit |
8fb591 |
ly_print(out, "%s{%s", (level ? " " : ""), (level ? "\n" : ""));
|
|
Packit |
8fb591 |
/* do not print any default values nor empty containers */
|
|
Packit |
8fb591 |
if (json_print_nodes(out, level, any->value.tree, 1, 0, LYP_WITHSIBLINGS | (options & ~LYP_NETCONF))) {
|
|
Packit |
8fb591 |
return EXIT_FAILURE;
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
break;
|
|
Packit |
8fb591 |
case LYD_ANYDATA_JSON:
|
|
Packit |
8fb591 |
if (level) {
|
|
Packit |
8fb591 |
ly_print(out, "\n");
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
if (any->value.str) {
|
|
Packit |
8fb591 |
ly_print(out, "%s", any->value.str);
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
if (level && (!any->value.str || (any->value.str[strlen(any->value.str) - 1] != '\n'))) {
|
|
Packit |
8fb591 |
/* do not print 2 newlines */
|
|
Packit |
8fb591 |
ly_print(out, "\n");
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
break;
|
|
Packit |
8fb591 |
case LYD_ANYDATA_XML:
|
|
Packit |
8fb591 |
lyxml_print_mem(&buf, any->value.xml, (level ? LYXML_PRINT_FORMAT | LYXML_PRINT_NO_LAST_NEWLINE : 0)
|
|
Packit |
8fb591 |
| LYXML_PRINT_SIBLINGS);
|
|
Packit |
8fb591 |
if (level) {
|
|
Packit |
8fb591 |
ly_print(out, " ");
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
json_print_string(out, buf);
|
|
Packit |
8fb591 |
free(buf);
|
|
Packit |
8fb591 |
break;
|
|
Packit |
8fb591 |
case LYD_ANYDATA_CONSTSTRING:
|
|
Packit |
8fb591 |
case LYD_ANYDATA_SXML:
|
|
Packit |
8fb591 |
if (level) {
|
|
Packit |
8fb591 |
ly_print(out, " ");
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
if (any->value.str) {
|
|
Packit |
8fb591 |
json_print_string(out, any->value.str);
|
|
Packit |
8fb591 |
} else {
|
|
Packit |
8fb591 |
ly_print(out, "\"\"");
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
break;
|
|
Packit |
8fb591 |
case LYD_ANYDATA_STRING:
|
|
Packit |
8fb591 |
case LYD_ANYDATA_SXMLD:
|
|
Packit |
8fb591 |
case LYD_ANYDATA_JSOND:
|
|
Packit |
8fb591 |
case LYD_ANYDATA_LYBD:
|
|
Packit |
8fb591 |
case LYD_ANYDATA_LYB:
|
|
Packit |
8fb591 |
/* other formats are not supported */
|
|
Packit |
8fb591 |
json_print_string(out, "(error)");
|
|
Packit |
8fb591 |
break;
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
/* print attributes as sibling leaf */
|
|
Packit |
8fb591 |
if (node->attr) {
|
|
Packit |
8fb591 |
if (schema) {
|
|
Packit |
8fb591 |
ly_print(out, ",%s%*s\"@%s:%s\":%s{%s", (level ? "\n" : ""), LEVEL, INDENT, schema, node->schema->name,
|
|
Packit |
8fb591 |
(level ? " " : ""), (level ? "\n" : ""));
|
|
Packit |
8fb591 |
} else {
|
|
Packit |
8fb591 |
ly_print(out, ",%s%*s\"@%s\":%s{%s", (level ? "\n" : ""), LEVEL, INDENT, node->schema->name,
|
|
Packit |
8fb591 |
(level ? " " : ""), (level ? "\n" : ""));
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
if (json_print_attrs(out, (level ? level + 1 : level), node, NULL)) {
|
|
Packit |
8fb591 |
return EXIT_FAILURE;
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
ly_print(out, "%*s}", LEVEL, INDENT);
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
if (level) {
|
|
Packit |
8fb591 |
level--;
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
if (is_object) {
|
|
Packit |
8fb591 |
ly_print(out, "%*s}", LEVEL, INDENT);
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
return EXIT_SUCCESS;
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
static int
|
|
Packit |
8fb591 |
json_print_nodes(struct lyout *out, int level, const struct lyd_node *root, int withsiblings, int toplevel, int options)
|
|
Packit |
8fb591 |
{
|
|
Packit |
8fb591 |
int ret = EXIT_SUCCESS,comma_flag = 0;
|
|
Packit |
8fb591 |
const struct lyd_node *node, *iter;
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
LY_TREE_FOR(root, node) {
|
|
Packit |
8fb591 |
if (!lyd_wd_toprint(node, options)) {
|
|
Packit |
8fb591 |
/* wd says do not print */
|
|
Packit |
8fb591 |
continue;
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
switch (node->schema->nodetype) {
|
|
Packit |
8fb591 |
case LYS_RPC:
|
|
Packit |
8fb591 |
case LYS_ACTION:
|
|
Packit |
8fb591 |
case LYS_NOTIF:
|
|
Packit |
8fb591 |
case LYS_CONTAINER:
|
|
Packit |
8fb591 |
if (comma_flag) {
|
|
Packit |
8fb591 |
/* print the previous comma */
|
|
Packit |
8fb591 |
ly_print(out, ",%s", (level ? "\n" : ""));
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
ret = json_print_container(out, level, node, toplevel, options);
|
|
Packit |
8fb591 |
break;
|
|
Packit |
8fb591 |
case LYS_LEAF:
|
|
Packit |
8fb591 |
if (comma_flag) {
|
|
Packit |
8fb591 |
/* print the previous comma */
|
|
Packit |
8fb591 |
ly_print(out, ",%s", (level ? "\n" : ""));
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
ret = json_print_leaf(out, level, node, 0, toplevel, options);
|
|
Packit |
8fb591 |
break;
|
|
Packit |
8fb591 |
case LYS_LEAFLIST:
|
|
Packit |
8fb591 |
case LYS_LIST:
|
|
Packit |
8fb591 |
/* is it already printed? (root node is not) */
|
|
Packit |
8fb591 |
for (iter = node->prev; iter->next && node != root; iter = iter->prev) {
|
|
Packit |
8fb591 |
if (iter == node) {
|
|
Packit |
8fb591 |
continue;
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
if (iter->schema == node->schema) {
|
|
Packit |
8fb591 |
/* the list has alread some previous instance and therefore it is already printed */
|
|
Packit |
8fb591 |
break;
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
if (!iter->next || node == root) {
|
|
Packit |
8fb591 |
if (comma_flag) {
|
|
Packit |
8fb591 |
/* print the previous comma */
|
|
Packit |
8fb591 |
ly_print(out, ",%s", (level ? "\n" : ""));
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
/* print the list/leaflist */
|
|
Packit |
8fb591 |
ret = json_print_leaf_list(out, level, node, node->schema->nodetype == LYS_LIST ? 1 : 0, toplevel, options);
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
break;
|
|
Packit |
8fb591 |
case LYS_ANYXML:
|
|
Packit |
8fb591 |
case LYS_ANYDATA:
|
|
Packit |
8fb591 |
if (comma_flag) {
|
|
Packit |
8fb591 |
/* print the previous comma */
|
|
Packit |
8fb591 |
ly_print(out, ",%s", (level ? "\n" : ""));
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
ret = json_print_anydataxml(out, level, node, toplevel, options);
|
|
Packit |
8fb591 |
break;
|
|
Packit |
8fb591 |
default:
|
|
Packit |
8fb591 |
LOGINT(node->schema->module->ctx);
|
|
Packit |
8fb591 |
ret = EXIT_FAILURE;
|
|
Packit |
8fb591 |
break;
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
if (!withsiblings) {
|
|
Packit |
8fb591 |
break;
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
comma_flag = 1;
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
if (root && level) {
|
|
Packit |
8fb591 |
ly_print(out, "\n");
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
return ret;
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
int
|
|
Packit |
8fb591 |
json_print_data(struct lyout *out, const struct lyd_node *root, int options)
|
|
Packit |
8fb591 |
{
|
|
Packit |
8fb591 |
const struct lyd_node *node, *next;
|
|
Packit |
8fb591 |
int level = 0, action_input = 0;
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
if (options & LYP_FORMAT) {
|
|
Packit |
8fb591 |
++level;
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
if (options & LYP_NETCONF) {
|
|
Packit |
8fb591 |
if (root->schema->nodetype != LYS_RPC) {
|
|
Packit |
8fb591 |
/* learn whether we are printing an action */
|
|
Packit |
8fb591 |
LY_TREE_DFS_BEGIN(root, next, node) {
|
|
Packit |
8fb591 |
if (node->schema->nodetype == LYS_ACTION) {
|
|
Packit |
8fb591 |
break;
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
LY_TREE_DFS_END(root, next, node);
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
} else {
|
|
Packit |
8fb591 |
node = root;
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
if (node && (node->schema->nodetype & (LYS_RPC | LYS_ACTION))) {
|
|
Packit |
8fb591 |
if (node->child && (node->child->schema->parent->nodetype == LYS_OUTPUT)) {
|
|
Packit |
8fb591 |
/* skip the container */
|
|
Packit |
8fb591 |
root = node->child;
|
|
Packit |
8fb591 |
} else if (node->schema->nodetype == LYS_ACTION) {
|
|
Packit |
8fb591 |
action_input = 1;
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
/* start */
|
|
Packit |
8fb591 |
ly_print(out, "{%s", (level ? "\n" : ""));
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
if (action_input) {
|
|
Packit |
8fb591 |
ly_print(out, "%*s\"yang:action\":%s{%s", LEVEL, INDENT, (level ? " " : ""), (level ? "\n" : ""));
|
|
Packit |
8fb591 |
if (level) {
|
|
Packit |
8fb591 |
++level;
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
/* content */
|
|
Packit |
8fb591 |
if (json_print_nodes(out, level, root, options & LYP_WITHSIBLINGS, 1, options)) {
|
|
Packit |
8fb591 |
return EXIT_FAILURE;
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
if (action_input) {
|
|
Packit |
8fb591 |
if (level) {
|
|
Packit |
8fb591 |
--level;
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
ly_print(out, "%*s}%s", LEVEL, INDENT, (level ? "\n" : ""));
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
/* end */
|
|
Packit |
8fb591 |
ly_print(out, "}%s", (level ? "\n" : ""));
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
ly_print_flush(out);
|
|
Packit |
8fb591 |
return EXIT_SUCCESS;
|
|
Packit |
8fb591 |
}
|