diff options
Diffstat (limited to 'src/printer_json.c')
-rw-r--r-- | src/printer_json.c | 134 |
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; |