json BUGFIX yet another major anydata/anyxml refactoring

Anydata values are, in fact, only subset (objects)
of anyxml values (values, include objects).

Refs #1797
diff --git a/src/parser_json.c b/src/parser_json.c
index c9fc573..c967063 100644
--- a/src/parser_json.c
+++ b/src/parser_json.c
@@ -265,27 +265,27 @@
 lydjson_data_skip(struct lyjson_ctx *jsonctx)
 {
     enum LYJSON_PARSER_STATUS status, current;
-    size_t sublevels = 1;
+    uint32_t sublevels, prev_depth;
 
     status = lyjson_ctx_status(jsonctx, 0);
+    if (status == LYJSON_OBJECT) {
+        sublevels = 1;
+    } else {
+        sublevels = 0;
+    }
 
     /* skip after the content */
     do {
-        uint32_t prev_depth = jsonctx->depth;
-
+        prev_depth = jsonctx->depth;
         LY_CHECK_RET(lyjson_ctx_next(jsonctx, &current));
 
-        if (current == status) {
+        if ((current == LYJSON_OBJECT) && (prev_depth < jsonctx->depth)) {
             /* lyjson_ctx_next() can return LYSJON_OBJECT in two cases, either when
              * a new object is encountered, or when it finishes parsing a value from a
              * previous key-value pair. In the latter case the sublevel shouldn't increase.
-            */
-            if ((status == LYJSON_OBJECT) && (prev_depth == jsonctx->depth)) {
-                continue;
-            }
-
+             */
             sublevels++;
-        } else if ((status == LYJSON_OBJECT) && (current == LYJSON_OBJECT_CLOSED)) {
+        } else if (current == LYJSON_OBJECT_CLOSED) {
             sublevels--;
         }
     } while ((current != status + 1) || sublevels);
@@ -1245,6 +1245,136 @@
 }
 
 /**
+ * @brief Parse a single anydata/anyxml node.
+ *
+ * @param[in] lydctx JSON data parser context. When the function returns, the context is in the same state
+ * as before calling, despite it is necessary to process input data for checking.
+ * @param[in] snode Schema node corresponding to the member currently being processed in the context.
+ * @param[in,out] status JSON parser status, is updated.
+ * @param[out] node Parsed data (or opaque) node.
+ * @return LY_SUCCESS if a node was successfully parsed,
+ * @return LY_ENOT in case of invalid JSON encoding,
+ * @return LY_ERR on other errors.
+ */
+static LY_ERR
+lydjson_parse_any(struct lyd_json_ctx *lydctx, const struct lysc_node *snode, enum LYJSON_PARSER_STATUS *status,
+        struct lyd_node **node)
+{
+    LY_ERR r;
+    uint32_t prev_parse_opts, prev_int_opts;
+    struct ly_in in_start;
+    char *val;
+    struct lyd_node *tree = NULL;
+
+    assert(snode->nodetype & LYD_NODE_ANY);
+
+    /* status check according to allowed JSON types */
+    if (snode->nodetype == LYS_ANYXML) {
+        LY_CHECK_RET((*status != LYJSON_OBJECT) && (*status != LYJSON_OBJECT_EMPTY) && (*status != LYJSON_ARRAY) &&
+                (*status != LYJSON_NUMBER) && (*status != LYJSON_STRING) && (*status != LYJSON_FALSE) &&
+                (*status != LYJSON_TRUE) && (*status != LYJSON_NULL), LY_ENOT);
+    } else {
+        LY_CHECK_RET((*status != LYJSON_OBJECT) && (*status != LYJSON_OBJECT_EMPTY) && (*status != LYJSON_ARRAY), LY_ENOT);
+    }
+
+    if ((snode->nodetype == LYS_ANYDATA) && (*status == LYJSON_ARRAY)) {
+        /* only special anydata [null] allowed, 2 more moves are needed */
+        LY_CHECK_RET(lyjson_ctx_next(lydctx->jsonctx, status));
+        LY_CHECK_RET(*status != LYJSON_NULL, LY_ENOT);
+        LY_CHECK_RET(lyjson_ctx_next(lydctx->jsonctx, status));
+        LY_CHECK_RET(*status != LYJSON_ARRAY_CLOSED, LY_ENOT);
+
+        return lyd_create_any(snode, "[null]", LYD_ANYDATA_JSON, 0, node);
+    }
+
+    /* create any node */
+    switch (*status) {
+    case LYJSON_OBJECT:
+        /* parse any data tree with correct options, first backup the current options and then make the parser
+         * process data as opaq nodes */
+        prev_parse_opts = lydctx->parse_opts;
+        lydctx->parse_opts &= ~LYD_PARSE_STRICT;
+        lydctx->parse_opts |= LYD_PARSE_OPAQ;
+        prev_int_opts = lydctx->int_opts;
+        lydctx->int_opts |= LYD_INTOPT_ANY | LYD_INTOPT_WITH_SIBLINGS;
+
+        /* process the anydata content */
+        while (*status != LYJSON_OBJECT_CLOSED) {
+            LY_CHECK_RET(lydjson_subtree_r(lydctx, NULL, &tree, NULL));
+            *status = lyjson_ctx_status(lydctx->jsonctx, 0);
+        }
+
+        /* restore parser options */
+        lydctx->parse_opts = prev_parse_opts;
+        lydctx->int_opts = prev_int_opts;
+
+        /* finish linking metadata */
+        LY_CHECK_RET(lydjson_metadata_finish(lydctx, &tree));
+
+        LY_CHECK_RET(lyd_create_any(snode, tree, LYD_ANYDATA_DATATREE, 1, node));
+        break;
+    case LYJSON_ARRAY:
+        /* skip until the array end */
+        in_start = *lydctx->jsonctx->in;
+        LY_CHECK_RET(lydjson_data_skip(lydctx->jsonctx));
+
+        /* make a copy of the whole array and store it */
+        if (asprintf(&val, "[%.*s", (int)(lydctx->jsonctx->in->current - in_start.current), in_start.current) == -1) {
+            LOGMEM(lydctx->jsonctx->ctx);
+            return LY_EMEM;
+        }
+        r = lyd_create_any(snode, val, LYD_ANYDATA_JSON, 1, node);
+        if (r) {
+            free(val);
+            return r;
+        }
+        break;
+    case LYJSON_STRING:
+        /* string value */
+        if (lydctx->jsonctx->dynamic) {
+            LY_CHECK_RET(lyd_create_any(snode, lydctx->jsonctx->value, LYD_ANYDATA_STRING, 1, node));
+            lydctx->jsonctx->dynamic = 0;
+        } else {
+            val = strndup(lydctx->jsonctx->value, lydctx->jsonctx->value_len);
+            LY_CHECK_ERR_RET(!val, LOGMEM(lydctx->jsonctx->ctx), LY_EMEM);
+
+            r = lyd_create_any(snode, val, LYD_ANYDATA_STRING, 1, node);
+            if (r) {
+                free(val);
+                return r;
+            }
+        }
+        break;
+    case LYJSON_NUMBER:
+    case LYJSON_FALSE:
+    case LYJSON_TRUE:
+        /* JSON value */
+        assert(!lydctx->jsonctx->dynamic);
+        val = strndup(lydctx->jsonctx->value, lydctx->jsonctx->value_len);
+        LY_CHECK_ERR_RET(!val, LOGMEM(lydctx->jsonctx->ctx), LY_EMEM);
+
+        r = lyd_create_any(snode, val, LYD_ANYDATA_JSON, 1, node);
+        if (r) {
+            free(val);
+            return r;
+        }
+        break;
+    case LYJSON_NULL:
+        /* no value */
+        LY_CHECK_RET(lyd_create_any(snode, NULL, LYD_ANYDATA_JSON, 1, node));
+        break;
+    case LYJSON_OBJECT_EMPTY:
+        /* empty object */
+        LY_CHECK_RET(lyd_create_any(snode, NULL, LYD_ANYDATA_DATATREE, 1, node));
+        break;
+    default:
+        LOGINT_RET(lydctx->jsonctx->ctx);
+    }
+
+    return LY_SUCCESS;
+}
+
+/**
  * @brief Parse a single instance of a node.
  *
  * @param[in] lydctx JSON data parser context. When the function returns, the context is in the same state
@@ -1268,9 +1398,7 @@
         enum LYJSON_PARSER_STATUS *status, struct lyd_node **node)
 {
     LY_ERR ret;
-    uint32_t type_hints = 0, prev_parse_opts, prev_int_opts;
-    char *val;
-    struct lyd_node *tree = NULL;
+    uint32_t type_hints = 0;
 
     ret = lydjson_data_check_opaq(lydctx, snode, &type_hints);
     if (ret == LY_SUCCESS) {
@@ -1293,32 +1421,11 @@
                 LY_CHECK_RET(lyjson_ctx_next(lydctx->jsonctx, status));
                 assert(*status == LYJSON_ARRAY_CLOSED);
             }
-        } else if (snode->nodetype == LYS_ANYXML) {
-            LY_CHECK_RET((*status != LYJSON_STRING) && (*status != LYJSON_NULL), LY_ENOT);
-
-            /* create anyxml node */
-            if (*status == LYJSON_NULL) {
-                ret = lyd_create_any(snode, NULL, LYD_ANYDATA_STRING, 1, node);
-                LY_CHECK_RET(ret);
-            } else if (lydctx->jsonctx->dynamic) {
-                ret = lyd_create_any(snode, lydctx->jsonctx->value, LYD_ANYDATA_STRING, 1, node);
-                LY_CHECK_RET(ret);
-                lydctx->jsonctx->dynamic = 0;
-            } else {
-                val = strndup(lydctx->jsonctx->value, lydctx->jsonctx->value_len);
-                LY_CHECK_ERR_RET(!val, LOGMEM(lydctx->jsonctx->ctx), LY_EMEM);
-                ret = lyd_create_any(snode, val, LYD_ANYDATA_STRING, 1, node);
-                if (ret) {
-                    free(val);
-                    return ret;
-                }
-            }
         } else if (snode->nodetype & LYD_NODE_INNER) {
             /* create inner node */
             LY_CHECK_RET((*status != LYJSON_OBJECT) && (*status != LYJSON_OBJECT_EMPTY), LY_ENOT);
 
-            ret = lyd_create_inner(snode, node);
-            LY_CHECK_RET(ret);
+            LY_CHECK_RET(lyd_create_inner(snode, node));
 
             LOG_LOCSET(snode, *node, NULL, NULL);
 
@@ -1351,35 +1458,9 @@
             }
 
             LOG_LOCBACK(1, 1, 0, 0);
-        } else if (snode->nodetype == LYS_ANYDATA) {
+        } else {
             /* create any node */
-            LY_CHECK_RET((*status != LYJSON_OBJECT) && (*status != LYJSON_OBJECT_EMPTY), LY_ENOT);
-
-            /* parse any data tree with correct options */
-            /* first backup the current options and then make the parser to process data as opaq nodes */
-            prev_parse_opts = lydctx->parse_opts;
-            lydctx->parse_opts &= ~LYD_PARSE_STRICT;
-            lydctx->parse_opts |= LYD_PARSE_OPAQ;
-            prev_int_opts = lydctx->int_opts;
-            lydctx->int_opts |= LYD_INTOPT_ANY | LYD_INTOPT_WITH_SIBLINGS;
-
-            /* process the anydata content */
-            while ((*status != LYJSON_OBJECT_CLOSED) && (*status != LYJSON_OBJECT_EMPTY)) {
-                ret = lydjson_subtree_r(lydctx, NULL, &tree, NULL);
-                LY_CHECK_RET(ret);
-                *status = lyjson_ctx_status(lydctx->jsonctx, 0);
-            }
-
-            /* restore parser options */
-            lydctx->parse_opts = prev_parse_opts;
-            lydctx->int_opts = prev_int_opts;
-
-            /* finish linking metadata */
-            ret = lydjson_metadata_finish(lydctx, &tree);
-            LY_CHECK_RET(ret);
-
-            ret = lyd_create_any(snode, tree, LYD_ANYDATA_DATATREE, 1, node);
-            LY_CHECK_RET(ret);
+            LY_CHECK_RET(lydjson_parse_any(lydctx, snode, status, node));
         }
 
         /* add/correct flags */
diff --git a/src/printer_json.c b/src/printer_json.c
index fd0f477..2e3ff48 100644
--- a/src/printer_json.c
+++ b/src/printer_json.c
@@ -531,16 +531,7 @@
     struct lyd_node *iter;
     uint32_t prev_opts, prev_lo;
 
-    /* anyxml - printed as name/value pair;
-     * anydata - printed as an object */
-
-    if (!any->value.tree) {
-        /* no content */
-        if (any->schema->nodetype == LYS_ANYXML) {
-            ly_print_(pctx->out, "null");
-        }
-        return LY_SUCCESS;
-    }
+    assert(any->schema->nodetype & LYD_NODE_ANY);
 
     if (any->value_type == LYD_ANYDATA_LYB) {
         uint32_t parser_options = LYD_PARSE_ONLY | LYD_PARSE_OPAQ | LYD_PARSE_STRICT;
@@ -562,48 +553,57 @@
 
     switch (any->value_type) {
     case LYD_ANYDATA_DATATREE:
-        if (any->schema->nodetype == LYS_ANYXML) {
-            /* print always as a string */
-            ly_print_(pctx->out, "\"%s", DO_FORMAT ? "\n" : "");
-        }
+        /* print as an object */
+        ly_print_(pctx->out, "{%s", DO_FORMAT ? "\n" : "");
+        LEVEL_INC;
 
         /* close opening tag and print data */
         prev_opts = pctx->options;
         pctx->options &= ~LYD_PRINT_WITHSIBLINGS;
-
         LY_LIST_FOR(any->value.tree, iter) {
             ret = json_print_node(pctx, iter);
             LY_CHECK_ERR_RET(ret, LEVEL_DEC, ret);
         }
-
         pctx->options = prev_opts;
 
-        if (any->schema->nodetype == LYS_ANYXML) {
-            /* terminate the string */
-            ly_print_(pctx->out, "\"");
+        /* terminate the object */
+        if (DO_FORMAT) {
+            ly_print_(pctx->out, "\n%*s}", INDENT);
+        } else {
+            ly_print_(pctx->out, "}");
         }
+        LEVEL_DEC;
         break;
     case LYD_ANYDATA_JSON:
-        /* print without escaping special characters */
-        if (any->schema->nodetype == LYS_ANYXML) {
-            /* print as a raw JSON */
-            ly_print_(pctx->out, "%s", any->value.str);
-        } else if (any->value.str[0]) {
-            /* print with indent */
-            ly_print_(pctx->out, "%*s%s", INDENT, any->value.str);
+        if (!any->value.json) {
+            /* no content */
+            if (any->schema->nodetype == LYS_ANYXML) {
+                ly_print_(pctx->out, "null");
+            } else {
+                ly_print_(pctx->out, "{}");
+            }
+        } else {
+            /* print without escaping special characters */
+            ly_print_(pctx->out, "%s", any->value.json);
         }
         break;
     case LYD_ANYDATA_STRING:
     case LYD_ANYDATA_XML:
-        if (any->schema->nodetype == LYS_ANYXML) {
+        if (!any->value.str) {
+            /* no content */
+            if (any->schema->nodetype == LYS_ANYXML) {
+                ly_print_(pctx->out, "null");
+            } else {
+                ly_print_(pctx->out, "{}");
+            }
+        } else {
             /* print as a string */
             ly_print_(pctx->out, "\"%s\"", any->value.str);
-            break;
         }
-    /* fallthrough */
+        break;
     case LYD_ANYDATA_LYB:
-        /* JSON and LYB format is not supported */
-        LOGWRN(pctx->ctx, "Unable to print anydata content (type %d) as XML.", any->value_type);
+        /* LYB format is not supported */
+        LOGWRN(pctx->ctx, "Unable to print anydata content (type %d) as JSON.", any->value_type);
         break;
     }
 
@@ -611,7 +611,7 @@
 }
 
 /**
- * @brief Print content of a single container/list/anydata data node including its metadata.
+ * @brief Print content of a single container/list data node including its metadata.
  * The envelope specific to nodes are expected to be printed by the caller.
  *
  * @param[in] ctx JSON printer context.
@@ -631,8 +631,6 @@
     }
     if (node->meta || child) {
         has_content = 1;
-    } else if (node->schema && (node->schema->nodetype & LYD_NODE_ANY) && ((struct lyd_node_any *)node)->value.tree) {
-        has_content = 1;
     }
 
     if ((node->schema && (node->schema->nodetype == LYS_LIST)) ||
@@ -647,14 +645,9 @@
 
     json_print_attributes(pctx, node, 1);
 
-    if (!node->schema || !(node->schema->nodetype & LYS_ANYDATA)) {
-        /* print children */
-        LY_LIST_FOR(lyd_child(node), child) {
-            LY_CHECK_RET(json_print_node(pctx, child));
-        }
-    } else {
-        /* anydata */
-        json_print_any_content(pctx, (struct lyd_node_any *)node);
+    /* print children */
+    LY_LIST_FOR(lyd_child(node), child) {
+        LY_CHECK_RET(json_print_node(pctx, child));
     }
 
     LEVEL_DEC;
@@ -685,14 +678,14 @@
 }
 
 /**
- * @brief Print anyxml data node including its metadata.
+ * @brief Print anydata/anyxml data node including its metadata.
  *
  * @param[in] ctx JSON printer context.
  * @param[in] node Data node to print.
  * @return LY_ERR value.
  */
 static int
-json_print_anyxml(struct jsonpr_ctx *pctx, const struct lyd_node *node)
+json_print_any(struct jsonpr_ctx *pctx, const struct lyd_node *node)
 {
     LY_CHECK_RET(json_print_member(pctx, node, 0));
     LY_CHECK_RET(json_print_any_content(pctx, (struct lyd_node_any *)node));
@@ -912,7 +905,6 @@
         case LYS_RPC:
         case LYS_ACTION:
         case LYS_NOTIF:
-        case LYS_ANYDATA:
         case LYS_CONTAINER:
             LY_CHECK_RET(json_print_container(pctx, node));
             break;
@@ -923,8 +915,9 @@
         case LYS_LIST:
             LY_CHECK_RET(json_print_leaf_list(pctx, node));
             break;
+        case LYS_ANYDATA:
         case LYS_ANYXML:
-            LY_CHECK_RET(json_print_anyxml(pctx, node));
+            LY_CHECK_RET(json_print_any(pctx, node));
             break;
         default:
             LOGINT(pctx->ctx);
diff --git a/tests/utests/data/test_parser_json.c b/tests/utests/data/test_parser_json.c
index e9fb705..a9c537f 100644
--- a/tests/utests/data/test_parser_json.c
+++ b/tests/utests/data/test_parser_json.c
@@ -37,6 +37,7 @@
             "}"
             "container cp {presence \"container switch\"; leaf y {type string;} leaf z {type int8;}}"
             "anydata any {config false;}"
+            "anyxml axml;"
             "leaf-list ll1 { type uint8; }"
             "leaf foo2 { type string; default \"default-val\"; }"
             "leaf foo3 { type uint32; }"
@@ -246,7 +247,7 @@
     CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree);
     assert_non_null(tree);
     tree = tree->next;
-    CHECK_LYSC_NODE(tree->schema, NULL, 0, LYS_SET_ENUM | LYS_CONFIG_R | LYS_YIN_ARGUMENT, 1, "any",
+    CHECK_LYSC_NODE(tree->schema, NULL, 0, LYS_STATUS_CURR | LYS_CONFIG_R | LYS_SET_CONFIG, 1, "any",
             1, LYS_ANYDATA, 0, 0, NULL, 0);
     CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
     lyd_free_all(tree);
@@ -255,10 +256,99 @@
     CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree);
     assert_non_null(tree);
     tree = tree->next;
-    CHECK_LYSC_NODE(tree->schema, NULL, 0, LYS_SET_ENUM | LYS_CONFIG_R | LYS_YIN_ARGUMENT, 1, "any",
+    CHECK_LYSC_NODE(tree->schema, NULL, 0, LYS_STATUS_CURR | LYS_CONFIG_R | LYS_SET_CONFIG, 1, "any",
             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]}";
+    CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree);
+    assert_non_null(tree);
+    tree = tree->next;
+    CHECK_LYSC_NODE(tree->schema, NULL, 0, LYS_STATUS_CURR | LYS_CONFIG_R | LYS_SET_CONFIG, 1, "any",
+            1, LYS_ANYDATA, 0, 0, NULL, 0);
+    CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
+    lyd_free_all(tree);
+}
+
+static void
+test_anyxml(void **state)
+{
+    const char *data;
+    struct lyd_node *tree;
+
+    data = "{\"a:axml\":\"some-value in string\"}";
+    CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree);
+    assert_non_null(tree);
+    tree = tree->next;
+    CHECK_LYSC_NODE(tree->schema, NULL, 0, LYS_STATUS_CURR | LYS_CONFIG_W, 1, "axml", 1, LYS_ANYXML, 0, 0, NULL, 0);
+    CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
+    lyd_free_all(tree);
+
+    data = "{\"a:axml\":\"\"}";
+    CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree);
+    assert_non_null(tree);
+    tree = tree->next;
+    CHECK_LYSC_NODE(tree->schema, NULL, 0, LYS_STATUS_CURR | LYS_CONFIG_W, 1, "axml", 1, LYS_ANYXML, 0, 0, NULL, 0);
+    CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
+    lyd_free_all(tree);
+
+    data = "{\"a:axml\":55}";
+    CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree);
+    assert_non_null(tree);
+    tree = tree->next;
+    CHECK_LYSC_NODE(tree->schema, NULL, 0, LYS_STATUS_CURR | LYS_CONFIG_W, 1, "axml", 1, LYS_ANYXML, 0, 0, NULL, 0);
+    CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
+    lyd_free_all(tree);
+
+    data = "{\"a:axml\":false}";
+    CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree);
+    assert_non_null(tree);
+    tree = tree->next;
+    CHECK_LYSC_NODE(tree->schema, NULL, 0, LYS_STATUS_CURR | LYS_CONFIG_W, 1, "axml", 1, LYS_ANYXML, 0, 0, NULL, 0);
+    CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
+    lyd_free_all(tree);
+
+    data = "{\"a:axml\":null}";
+    CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree);
+    assert_non_null(tree);
+    tree = tree->next;
+    CHECK_LYSC_NODE(tree->schema, NULL, 0, LYS_STATUS_CURR | LYS_CONFIG_W, 1, "axml", 1, LYS_ANYXML, 0, 0, NULL, 0);
+    CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
+    lyd_free_all(tree);
+
+    data = "{\"a:axml\":[null,true,false]}";
+    CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree);
+    assert_non_null(tree);
+    tree = tree->next;
+    CHECK_LYSC_NODE(tree->schema, NULL, 0, LYS_STATUS_CURR | LYS_CONFIG_W, 1, "axml", 1, LYS_ANYXML, 0, 0, NULL, 0);
+    CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
+    lyd_free_all(tree);
+
+    data = "{\"a:axml\":[null,true,{\"name\":[25,40, false]}]}";
+    CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree);
+    assert_non_null(tree);
+    tree = tree->next;
+    CHECK_LYSC_NODE(tree->schema, NULL, 0, LYS_STATUS_CURR | LYS_CONFIG_W, 1, "axml", 1, LYS_ANYXML, 0, 0, NULL, 0);
+    CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
+    lyd_free_all(tree);
+
+    /* same as anydata tests */
+    data = "{\"a:axml\":{\"x:element1\":{\"element2\":\"/a:some/a:path\",\"list\":[{},{\"key\":\"a\"}]}}}";
+    CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree);
+    assert_non_null(tree);
+    tree = tree->next;
+    CHECK_LYSC_NODE(tree->schema, NULL, 0, LYS_STATUS_CURR | LYS_CONFIG_W, 1, "axml", 1, LYS_ANYXML, 0, 0, NULL, 0);
+    CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
+    lyd_free_all(tree);
+
+    data = "{\"a:axml\":{}}";
+    CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree);
+    assert_non_null(tree);
+    tree = tree->next;
+    CHECK_LYSC_NODE(tree->schema, NULL, 0, LYS_STATUS_CURR | LYS_CONFIG_W, 1, "axml", 1, LYS_ANYXML, 0, 0, NULL, 0);
+    CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
+    lyd_free_all(tree);
 }
 
 static void
@@ -655,6 +745,7 @@
         UTEST(test_leaf, setup),
         UTEST(test_leaflist, setup),
         UTEST(test_anydata, setup),
+        UTEST(test_anyxml, setup),
         UTEST(test_list, setup),
         UTEST(test_container, setup),
         UTEST(test_opaq, setup),