diff --git a/apps/backend/backend_plugin.c b/apps/backend/backend_plugin.c index a3c18d46..f9675a35 100644 --- a/apps/backend/backend_plugin.c +++ b/apps/backend/backend_plugin.c @@ -387,15 +387,9 @@ clixon_plugin_statedata_all(clicon_handle h, } if (xml_sort_recurse(x) < 0) goto done; - /* Mark non-presence containers */ - if (xml_apply(x, CX_ELMNT, xml_nopresence_default_mark, (void*)XML_FLAG_TRANSIENT) < 0) + /* Remove global defaults and empty non-presence containers */ + if (xml_defaults_nopresence(x, 1) < 0) goto done; - /* Clear XML tree of defaults */ - if (xml_tree_prune_flagged(x, XML_FLAG_TRANSIENT, 1) < 0) - goto done; - /* clear mark and change */ - xml_apply0(x, CX_ELMNT, (xml_applyfn_t*)xml_flag_reset, - (void*)(0xffff)); if (xml_default_recurse(x, 1) < 0) goto done; if ((ret = netconf_trymerge(x, yspec, xret)) < 0) diff --git a/lib/clixon/clixon_xml_map.h b/lib/clixon/clixon_xml_map.h index aa93d85d..cd60bd55 100644 --- a/lib/clixon/clixon_xml_map.h +++ b/lib/clixon/clixon_xml_map.h @@ -63,8 +63,7 @@ int xml_tree_prune_flags(cxobj *xt, int flags, int mask); int xml_namespace_change(cxobj *x, char *ns, char *prefix); int xml_default_recurse(cxobj *xn, int state); int xml_global_defaults(clicon_handle h, cxobj *xn, cvec *nsc, const char *xpath, yang_stmt *yspec, int state); -int xml_nopresence_default(cxobj *xt); -int xml_nopresence_default_mark(cxobj *x, void *arg); +int xml_defaults_nopresence(cxobj *xn, int purge); int xml_sanity(cxobj *x, void *arg); int xml_non_config_data(cxobj *xt, cxobj **xerr); int xml2xpath(cxobj *x, cvec *nsc, char **xpath); diff --git a/lib/src/clixon_datastore_read.c b/lib/src/clixon_datastore_read.c index 5e0c0ae8..72d8bbde 100644 --- a/lib/src/clixon_datastore_read.c +++ b/lib/src/clixon_datastore_read.c @@ -889,15 +889,8 @@ xmldb_get_cache(clicon_handle h, if (xml_apply(x1t, CX_ELMNT, (xml_applyfn_t*)xml_flag_reset, (void*)(XML_FLAG_MARK|XML_FLAG_CHANGE)) < 0) goto done; } - /* Remove global defaults from cache - * Mark non-presence containers */ - if (xml_apply(x0t, CX_ELMNT, xml_nopresence_default_mark, (void*)XML_FLAG_TRANSIENT) < 0) - goto done; - /* clear XML tree of defaults */ - if (xml_tree_prune_flagged(x0t, XML_FLAG_DEFAULT, 1) < 0) - goto done; - /* Clear XML tree of defaults */ - if (xml_tree_prune_flagged(x0t, XML_FLAG_TRANSIENT, 1) < 0) + /* Remove global defaults and empty non-presence containers */ + if (xml_defaults_nopresence(x0t, 1) < 0) goto done; if (yb != YB_NONE){ /* Add default global values */ @@ -1169,14 +1162,10 @@ xmldb_get0_clear(clicon_handle h, if (x == NULL) goto ok; - /* Mark non-presence containers */ - if (xml_apply(x, CX_ELMNT, xml_nopresence_default_mark, (void*)XML_FLAG_TRANSIENT) < 0) + /* Remove global defaults and empty non-presence containers */ + if (xml_defaults_nopresence(x, 1) < 0) goto done; - /* Clear XML tree of defaults */ - if (xml_tree_prune_flagged(x, XML_FLAG_TRANSIENT, 1) < 0) - goto done; - - /* clear mark and change */ + /* clear flags: mark and change */ xml_apply0(x, CX_ELMNT, (xml_applyfn_t*)xml_flag_reset, (void*)(XML_FLAG_MARK|XML_FLAG_ADD|XML_FLAG_CHANGE)); ok: diff --git a/lib/src/clixon_datastore_write.c b/lib/src/clixon_datastore_write.c index ac07dd8c..e05ea2fc 100644 --- a/lib/src/clixon_datastore_write.c +++ b/lib/src/clixon_datastore_write.c @@ -535,7 +535,7 @@ text_modify(clicon_handle h, goto fail; if (createstr != NULL && (op == OP_REPLACE || op == OP_MERGE || op == OP_CREATE)){ - if (x0 == NULL || xml_nopresence_default(x0)){ /* does not exist or is default */ + if (x0 == NULL || xml_defaults_nopresence(x0, 0)){ /* does not exist or is default */ if (strcmp(createstr, "false")==0){ /* RFC 8040 4.6 PATCH: * If the target resource instance does not exist, the server MUST NOT create it. @@ -784,7 +784,7 @@ text_modify(clicon_handle h, switch(op){ case OP_CREATE: if (x0){ - if (xml_nopresence_default(x0) == 0){ + if (xml_defaults_nopresence(x0, 0) == 0){ if (netconf_data_exists(cbret, "Data already exists; cannot create new resource") < 0) goto done; goto fail; @@ -1257,11 +1257,8 @@ xmldb_put(clicon_handle h, if (xml_apply(x0, CX_ELMNT, (xml_applyfn_t*)xml_flag_reset, (void*)(XML_FLAG_NONE|XML_FLAG_MARK)) < 0) goto done; - /* Mark non-presence containers */ - if (xml_apply(x0, CX_ELMNT, xml_nopresence_default_mark, (void*)XML_FLAG_TRANSIENT) < 0) - goto done; - /* Clear XML tree of defaults */ - if (xml_tree_prune_flagged(x0, XML_FLAG_TRANSIENT, 1) < 0) + /* Remove global defaults and empty non-presence containers */ + if (xml_defaults_nopresence(x0, 1) < 0) goto done; #if 0 /* debug */ if (xml_apply0(x0, -1, xml_sort_verify, NULL) < 0) diff --git a/lib/src/clixon_xml_map.c b/lib/src/clixon_xml_map.c index d7778194..b271715d 100644 --- a/lib/src/clixon_xml_map.c +++ b/lib/src/clixon_xml_map.c @@ -1092,55 +1092,55 @@ xml_global_defaults(clicon_handle h, return retval; } -/*! This node is a default set value or (recursively) a non-presence container - * @retval 1 xt is a nopresence/default node (ie "virtual") - * @retval 0 xt is not such a node +/*! Recursively find empty nopresence containers and default leaves, optionally purge + * + * @param[in] xn XML tree + * @param[in] purge Remove sub-nodes that is empty non-presence container or default leaf + * @retval 1 Node is an (recursive) empty non-presence container or default leaf + * @retval 0 Other node + * @retval -1 Error + * @note xn is not itself removed if purge */ int -xml_nopresence_default(cxobj *xt) +xml_defaults_nopresence(cxobj *xn, + int purge) { - cxobj *xc; - yang_stmt *yt; - - if ((yt = xml_spec(xt)) == NULL) - return 0; - switch (yang_keyword_get(yt)){ - case Y_CONTAINER: - if (yang_find(yt, Y_PRESENCE, NULL)) - return 0; - break; - case Y_LEAF: - return xml_flag(xt, XML_FLAG_DEFAULT)?1:0; - break; - default: - return 0; + int retval = -1; + cxobj *x; + cxobj *xprev; + yang_stmt *yn; + int rmx = 0; /* If set, remove this xn */ + int ret; + enum rfc_6020 keyw; + + if ((yn = xml_spec(xn)) != NULL){ + keyw = yang_keyword_get(yn); + if (keyw == Y_CONTAINER && + yang_find(yn, Y_PRESENCE, NULL) == NULL) + rmx = 1; + else if (keyw == Y_LEAF && + xml_flag(xn, XML_FLAG_DEFAULT)) + rmx = 1; } - xc = NULL; - while ((xc = xml_child_each(xt, xc, CX_ELMNT)) != NULL) { - if (xml_nopresence_default(xc) == 0) - return 0; + /* Loop thru children */ + x = NULL; + xprev = NULL; + while ((x = xml_child_each(xn, x, CX_ELMNT)) != NULL) { + if ((ret = xml_defaults_nopresence(x, purge)) < 0) + goto done; + if (ret == 1){ + if (purge){ + if (xml_purge(x) < 0) + goto done; + x = xprev; + } + } + else if (rmx) + rmx = 0; } - return 1; -} - -/*! Remove xml container if it is non-presence and only contains default leafs - * Called from xml_apply. Reason for marking is to delete it afterwords. - * @param[in] x - * @param[in] arg (flag value) - * @code - * if (xml_apply(xt, CX_ELMNT, xml_nopresence_default_mark, (void*)XML_FLAG_TRANSIENT) < 0) - * err; - * if (xml_tree_prune_flagged(xt, XML_FLAG_TRANSIENT, 1) < 0) - * goto done; - * @endcode - */ -int -xml_nopresence_default_mark(cxobj *x, - void *arg) -{ - if (xml_nopresence_default(x)) - xml_flag_set(x, (intptr_t)arg); - return 0; + retval = rmx; + done: + return retval; } /*! Sanitize an xml tree: xml node has matching yang_stmt pointer