Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding ability to use JSON 'null' values #2216

Merged
merged 1 commit into from
Apr 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/parser_data.h
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,8 @@ struct ly_in;
be checked (length, range, pattern, ...) and if a value can be stored,
it is. Calling separate validation on these data always checks all the
restrictions as well. */
#define LYD_PARSE_JSON_NULL 0x4000000 /**< Allow using JSON empty value 'null' within JSON input. By default such value
is not supported and according to RFC 7951 '[null]' shall be used instead. */

#define LYD_PARSE_OPTS_MASK 0xFFFF0000 /**< Mask for all the LYD_PARSE_ options. */

Expand Down
9 changes: 8 additions & 1 deletion src/parser_json.c
Original file line number Diff line number Diff line change
Expand Up @@ -1492,7 +1492,10 @@ lydjson_parse_instance(struct lyd_json_ctx *lydctx, struct lyd_node *parent, str
if (r == LY_SUCCESS) {
assert(snode->nodetype & (LYD_NODE_TERM | LYD_NODE_INNER | LYD_NODE_ANY));
if (snode->nodetype & LYD_NODE_TERM) {
if ((*status != LYJSON_ARRAY) && (*status != LYJSON_NUMBER) && (*status != LYJSON_STRING) &&
if ((lydctx->parse_opts & LYD_PARSE_JSON_NULL) && (*status == LYJSON_NULL)) {
/* do not do anything if value is JSON 'null' */
goto cleanup;
} else if ((*status != LYJSON_ARRAY) && (*status != LYJSON_NUMBER) && (*status != LYJSON_STRING) &&
(*status != LYJSON_FALSE) && (*status != LYJSON_TRUE) && (*status != LYJSON_NULL)) {
rc = LY_ENOT;
goto cleanup;
Expand All @@ -1519,6 +1522,10 @@ lydjson_parse_instance(struct lyd_json_ctx *lydctx, struct lyd_node *parent, str
r = lydjson_parse_instance_inner(lydctx, snode, ext, status, node);
LY_DPARSER_ERR_GOTO(r, rc = r, lydctx, cleanup);
} else {
if ((lydctx->parse_opts & LYD_PARSE_JSON_NULL) && (*status == LYJSON_NULL)) {
/* do not do anything if value is JSON 'null' */
goto cleanup;
}
/* create any node */
r = lydjson_parse_any(lydctx, snode, ext, status, node);
LY_DPARSER_ERR_GOTO(r, rc = r, lydctx, cleanup);
Expand Down
10 changes: 10 additions & 0 deletions tests/utests/data/test_parser_json.c
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,11 @@ test_leaf(void **state)
data = "{\"@a:foo\":{\"a:hi\\nt\":1},\"a:foo\":\"xxx\"}";
assert_int_equal(LY_EINVAL, lyd_parse_data_mem(UTEST_LYCTX, data, LYD_JSON, 0, LYD_VALIDATE_PRESENT, &tree));
CHECK_LOG_CTX("Annotation definition for attribute \"a:hi\nt\" not found.", "/@a:foo/@a:hi\nt", 1);

data = "{\"a:foo\": null}";
PARSER_CHECK_ERROR(data, 0, LYD_VALIDATE_PRESENT, tree, LY_EVALID, "Invalid non-string-encoded string value \"\".", "/a:foo", 1);
CHECK_PARSE_LYD(data, LYD_PARSE_JSON_NULL, LYD_VALIDATE_PRESENT, tree);
assert_null(tree);
}

static void
Expand Down Expand Up @@ -291,6 +296,11 @@ test_anydata(void **state)
1, LYS_ANYDATA, 0, 0, NULL, 0);
CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
lyd_free_all(tree);

data = "{\"a:any\": null}";
PARSER_CHECK_ERROR(data, 0, LYD_VALIDATE_PRESENT, tree, LY_EVALID, "Expecting JSON name/object but anydata \"any\" is represented in input data as name/null.", NULL, 1);
CHECK_PARSE_LYD(data, LYD_PARSE_JSON_NULL, LYD_VALIDATE_PRESENT, tree);
assert_null(tree);
}

static void
Expand Down
10 changes: 9 additions & 1 deletion tools/lint/main_ni.c
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,9 @@ help(int shortout)
printf(" -X, --extended-leafref\n"
" Allow usage of deref() XPath function within leafref\n\n");

printf(" -J, --json-null\n"
" Allow usage of JSON empty values ('null') within input data\n\n");

printf(" -G GROUPS, --debug=GROUPS\n"
#ifndef NDEBUG
" Enable printing of specific debugging message group\n"
Expand Down Expand Up @@ -463,6 +466,7 @@ fill_context(int argc, char *argv[], struct yl_opt *yo, struct ly_ctx **ctx)
{"yang-library", no_argument, NULL, 'y'},
{"yang-library-file", required_argument, NULL, 'Y'},
{"extended-leafref", no_argument, NULL, 'X'},
{"json-null", no_argument, NULL, 'J'},
{"debug", required_argument, NULL, 'G'},
{NULL, 0, NULL, 0}
};
Expand All @@ -474,7 +478,7 @@ fill_context(int argc, char *argv[], struct yl_opt *yo, struct ly_ctx **ctx)
yo->line_length = 0;

opterr = 0;
while ((opt = getopt_long(argc, argv, "hvVQf:I:p:DF:iP:qs:neE:t:d:lL:o:O:R:myY:Xx:G:", options, &opt_index)) != -1) {
while ((opt = getopt_long(argc, argv, "hvVQf:I:p:DF:iP:qs:neE:t:d:lL:o:O:R:myY:XJx:G:", options, &opt_index)) != -1) {
switch (opt) {
case 'h': /* --help */
help(0);
Expand Down Expand Up @@ -654,6 +658,10 @@ fill_context(int argc, char *argv[], struct yl_opt *yo, struct ly_ctx **ctx)
yo->ctx_options |= LY_CTX_LEAFREF_EXTENDED;
break;

case 'J': /* --json-null */
yo->data_parse_options |= LYD_PARSE_JSON_NULL;
break;

case 'G': /* --debug */
if (set_debug_groups(optarg, yo)) {
return -1;
Expand Down
Loading