summaryrefslogtreecommitdiffstats
path: root/src/printer_json.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/printer_json.c')
-rw-r--r--src/printer_json.c134
1 files changed, 80 insertions, 54 deletions
diff --git a/src/printer_json.c b/src/printer_json.c
index 327799b..66ae154 100644
--- a/src/printer_json.c
+++ b/src/printer_json.c
@@ -4,7 +4,7 @@
* @author Michal Vasko <mvasko@cesnet.cz>
* @brief JSON printer for libyang data structure
*
- * Copyright (c) 2015 - 2022 CESNET, z.s.p.o.
+ * Copyright (c) 2015 - 2023 CESNET, z.s.p.o.
*
* This source code is licensed under BSD 3-Clause License (the "License").
* You may not use this file except in compliance with the License.
@@ -14,6 +14,7 @@
*/
#include <assert.h>
+#include <ctype.h>
#include <stdint.h>
#include <stdlib.h>
@@ -45,7 +46,7 @@ struct jsonpr_ctx {
uint16_t level_printed; /* level where some data were already printed */
struct ly_set open; /* currently open array(s) */
- const struct lyd_node *print_sibling_metadata;
+ const struct lyd_node *first_leaflist; /**< first printed leaf-list instance, used when printing its metadata/attributes */
};
/**
@@ -219,31 +220,38 @@ json_nscmp(const struct lyd_node *node1, const struct lyd_node *node2)
static LY_ERR
json_print_string(struct ly_out *out, const char *text)
{
- uint64_t i, n;
+ uint64_t i;
if (!text) {
return LY_SUCCESS;
}
ly_write_(out, "\"", 1);
- for (i = n = 0; text[i]; i++) {
- const unsigned char ascii = text[i];
+ for (i = 0; text[i]; i++) {
+ const unsigned char byte = text[i];
- if (ascii < 0x20) {
- /* control character */
- ly_print_(out, "\\u%.4X", ascii);
- } else {
- switch (ascii) {
- case '"':
- ly_print_(out, "\\\"");
- break;
- case '\\':
- ly_print_(out, "\\\\");
- break;
- default:
+ switch (byte) {
+ case '"':
+ ly_print_(out, "\\\"");
+ break;
+ case '\\':
+ ly_print_(out, "\\\\");
+ break;
+ case '\r':
+ ly_print_(out, "\\r");
+ break;
+ case '\t':
+ ly_print_(out, "\\t");
+ break;
+ default:
+ if (iscntrl(byte)) {
+ /* control character */
+ ly_print_(out, "\\u%.4X", byte);
+ } else {
+ /* printable character (even non-ASCII UTF8) */
ly_write_(out, &text[i], 1);
- n++;
}
+ break;
}
}
ly_write_(out, "\"", 1);
@@ -294,18 +302,21 @@ json_print_member2(struct jsonpr_ctx *pctx, const struct lyd_node *parent, LY_VA
/* determine prefix string */
if (name) {
- const struct lys_module *mod;
-
switch (format) {
case LY_VALUE_JSON:
module_name = name->module_name;
break;
- case LY_VALUE_XML:
- mod = ly_ctx_get_module_implemented_ns(pctx->ctx, name->module_ns);
+ case LY_VALUE_XML: {
+ const struct lys_module *mod = NULL;
+
+ if (name->module_ns) {
+ mod = ly_ctx_get_module_implemented_ns(pctx->ctx, name->module_ns);
+ }
if (mod) {
module_name = mod->name;
}
break;
+ }
default:
/* cannot be created */
LOGINT_RET(pctx->ctx);
@@ -332,15 +343,19 @@ json_print_member2(struct jsonpr_ctx *pctx, const struct lyd_node *parent, LY_VA
* @param[in] pctx JSON printer context.
* @param[in] ctx Context used to print the value.
* @param[in] val Data value to be printed.
+ * @param[in] local_mod Module of the current node.
* @return LY_ERR value.
*/
static LY_ERR
-json_print_value(struct jsonpr_ctx *pctx, const struct ly_ctx *ctx, const struct lyd_value *val)
+json_print_value(struct jsonpr_ctx *pctx, const struct ly_ctx *ctx, const struct lyd_value *val,
+ const struct lys_module *local_mod)
{
ly_bool dynamic;
LY_DATA_TYPE basetype;
- const char *value = val->realtype->plugin->print(ctx, val, LY_VALUE_JSON, NULL, &dynamic, NULL);
+ const char *value;
+ value = val->realtype->plugin->print(ctx, val, LY_VALUE_JSON, (void *)local_mod, &dynamic, NULL);
+ LY_CHECK_RET(!value, LY_EINVAL);
basetype = val->realtype->basetype;
print_val:
@@ -348,7 +363,8 @@ print_val:
switch (basetype) {
case LY_TYPE_UNION:
/* use the resolved type */
- basetype = val->subvalue->value.realtype->basetype;
+ val = &val->subvalue->value;
+ basetype = val->realtype->basetype;
goto print_val;
case LY_TYPE_BINARY:
@@ -394,19 +410,13 @@ print_val:
*
* @param[in] ctx JSON printer context.
* @param[in] node Opaq node where the attributes are placed.
- * @param[in] wdmod With-defaults module to mark that default attribute is supposed to be printed.
* @return LY_ERR value.
*/
static LY_ERR
-json_print_attribute(struct jsonpr_ctx *pctx, const struct lyd_node_opaq *node, const struct lys_module *wdmod)
+json_print_attribute(struct jsonpr_ctx *pctx, const struct lyd_node_opaq *node)
{
struct lyd_attr *attr;
- if (wdmod) {
- ly_print_(pctx->out, "%*s\"%s:default\":true", INDENT, wdmod->name);
- LEVEL_PRINTED;
- }
-
for (attr = node->attr; attr; attr = attr->next) {
json_print_member2(pctx, &node->node, attr->format, &attr->name, 0);
@@ -440,14 +450,14 @@ json_print_metadata(struct jsonpr_ctx *pctx, const struct lyd_node *node, const
struct lyd_meta *meta;
if (wdmod) {
- ly_print_(pctx->out, "%*s\"%s:default\":true", INDENT, wdmod->name);
+ ly_print_(pctx->out, "%*s\"%s:default\":%strue", INDENT, wdmod->name, DO_FORMAT ? " " : "");
LEVEL_PRINTED;
}
for (meta = node->meta; meta; meta = meta->next) {
PRINT_COMMA;
ly_print_(pctx->out, "%*s\"%s:%s\":%s", INDENT, meta->annotation->module->name, meta->name, DO_FORMAT ? " " : "");
- LY_CHECK_RET(json_print_value(pctx, LYD_CTX(node), &meta->value));
+ LY_CHECK_RET(json_print_value(pctx, LYD_CTX(node), &meta->value, NULL));
LEVEL_PRINTED;
}
@@ -495,7 +505,7 @@ json_print_attributes(struct jsonpr_ctx *pctx, const struct lyd_node *node, ly_b
}
ly_print_(pctx->out, "{%s", (DO_FORMAT ? "\n" : ""));
LEVEL_INC;
- LY_CHECK_RET(json_print_attribute(pctx, (struct lyd_node_opaq *)node, wdmod));
+ LY_CHECK_RET(json_print_attribute(pctx, (struct lyd_node_opaq *)node));
LEVEL_DEC;
ly_print_(pctx->out, "%s%*s}", DO_FORMAT ? "\n" : "", INDENT);
LEVEL_PRINTED;
@@ -515,7 +525,7 @@ static LY_ERR
json_print_leaf(struct jsonpr_ctx *pctx, const struct lyd_node *node)
{
LY_CHECK_RET(json_print_member(pctx, node, 0));
- LY_CHECK_RET(json_print_value(pctx, LYD_CTX(node), &((const struct lyd_node_term *)node)->value));
+ LY_CHECK_RET(json_print_value(pctx, LYD_CTX(node), &((const struct lyd_node_term *)node)->value, node->schema->module));
LEVEL_PRINTED;
/* print attributes as sibling */
@@ -780,16 +790,16 @@ json_print_leaf_list(struct jsonpr_ctx *pctx, const struct lyd_node *node)
} else {
assert(node->schema->nodetype == LYS_LEAFLIST);
- LY_CHECK_RET(json_print_value(pctx, LYD_CTX(node), &((const struct lyd_node_term *)node)->value));
+ LY_CHECK_RET(json_print_value(pctx, LYD_CTX(node), &((const struct lyd_node_term *)node)->value, node->schema->module));
- if (!pctx->print_sibling_metadata) {
+ if (!pctx->first_leaflist) {
if ((node->flags & LYD_DEFAULT) && (pctx->options & (LYD_PRINT_WD_ALL_TAG | LYD_PRINT_WD_IMPL_TAG))) {
/* we have implicit OR explicit default node, get with-defaults module */
wdmod = ly_ctx_get_module_implemented(LYD_CTX(node), "ietf-netconf-with-defaults");
}
if (node->meta || wdmod) {
/* we will be printing metadata for these siblings */
- pctx->print_sibling_metadata = node;
+ pctx->first_leaflist = node;
}
}
}
@@ -802,21 +812,20 @@ json_print_leaf_list(struct jsonpr_ctx *pctx, const struct lyd_node *node)
}
/**
- * @brief Print leaf-list's metadata in case they were marked in the last call to json_print_leaf_list().
+ * @brief Print leaf-list's metadata or opaque nodes attributes.
* This function is supposed to be called when the leaf-list array is closed.
*
* @param[in] ctx JSON printer context.
* @return LY_ERR value.
*/
static LY_ERR
-json_print_metadata_leaflist(struct jsonpr_ctx *pctx)
+json_print_meta_attr_leaflist(struct jsonpr_ctx *pctx)
{
const struct lyd_node *prev, *node, *iter;
const struct lys_module *wdmod = NULL;
+ const struct lyd_node_opaq *opaq = NULL;
- if (!pctx->print_sibling_metadata) {
- return LY_SUCCESS;
- }
+ assert(pctx->first_leaflist);
if (pctx->options & (LYD_PRINT_WD_ALL_TAG | LYD_PRINT_WD_IMPL_TAG)) {
/* get with-defaults module */
@@ -824,19 +833,31 @@ json_print_metadata_leaflist(struct jsonpr_ctx *pctx)
}
/* node is the first instance of the leaf-list */
- for (node = pctx->print_sibling_metadata, prev = pctx->print_sibling_metadata->prev;
+ for (node = pctx->first_leaflist, prev = pctx->first_leaflist->prev;
prev->next && matching_node(node, prev);
node = prev, prev = node->prev) {}
- LY_CHECK_RET(json_print_member(pctx, node, 1));
+ if (node->schema) {
+ LY_CHECK_RET(json_print_member(pctx, node, 1));
+ } else {
+ opaq = (struct lyd_node_opaq *)node;
+ LY_CHECK_RET(json_print_member2(pctx, lyd_parent(node), opaq->format, &opaq->name, 1));
+ }
+
ly_print_(pctx->out, "[%s", (DO_FORMAT ? "\n" : ""));
LEVEL_INC;
LY_LIST_FOR(node, iter) {
PRINT_COMMA;
- if (iter->meta || (iter->flags & LYD_DEFAULT)) {
+ if ((iter->schema && (iter->meta || (iter->flags & LYD_DEFAULT))) || (opaq && opaq->attr)) {
ly_print_(pctx->out, "%*s%s", INDENT, DO_FORMAT ? "{\n" : "{");
LEVEL_INC;
- LY_CHECK_RET(json_print_metadata(pctx, iter, (iter->flags & LYD_DEFAULT) ? wdmod : NULL));
+
+ if (iter->schema) {
+ LY_CHECK_RET(json_print_metadata(pctx, iter, (iter->flags & LYD_DEFAULT) ? wdmod : NULL));
+ } else {
+ LY_CHECK_RET(json_print_attribute(pctx, (struct lyd_node_opaq *)iter));
+ }
+
LEVEL_DEC;
ly_print_(pctx->out, "%s%*s}", DO_FORMAT ? "\n" : "", INDENT);
} else {
@@ -897,12 +918,17 @@ json_print_opaq(struct jsonpr_ctx *pctx, const struct lyd_node_opaq *node)
ly_print_(pctx->out, "%s", node->value);
} else {
/* string or a large number */
- ly_print_(pctx->out, "\"%s\"", node->value);
+ json_print_string(pctx->out, node->value);
}
LEVEL_PRINTED;
- /* attributes */
- json_print_attributes(pctx, (const struct lyd_node *)node, 0);
+ if (!(node->hints & LYD_NODEHINT_LEAFLIST)) {
+ /* attributes */
+ json_print_attributes(pctx, (const struct lyd_node *)node, 0);
+ } else if (!pctx->first_leaflist && node->attr) {
+ /* attributes printed later */
+ pctx->first_leaflist = &node->node;
+ }
}
if (last && (node->hints & (LYD_NODEHINT_LIST | LYD_NODEHINT_LEAFLIST))) {
@@ -959,9 +985,9 @@ json_print_node(struct jsonpr_ctx *pctx, const struct lyd_node *node)
pctx->level_printed = pctx->level;
- if (pctx->print_sibling_metadata && !matching_node(node->next, pctx->print_sibling_metadata)) {
- json_print_metadata_leaflist(pctx);
- pctx->print_sibling_metadata = NULL;
+ if (pctx->first_leaflist && !matching_node(node->next, pctx->first_leaflist)) {
+ json_print_meta_attr_leaflist(pctx);
+ pctx->first_leaflist = NULL;
}
return LY_SUCCESS;