* Changed clicon_rpc_get and clicon_rpc_get_config functions: added username and replaced namespace with namespace context

* Fixed several issues with multiple namespaces.
This commit is contained in:
Olof hagsand 2019-10-03 22:01:16 +02:00
parent 3efd5703d6
commit 6e41592aec
16 changed files with 224 additions and 370 deletions

View file

@ -146,18 +146,18 @@ attr_ns_value(cxobj *x,
* @see xml2ns
* XXX: fail handling: if (netconf_data_missing(cbret, NULL, "Data does not exist; cannot delete resource") < 0)
goto done;
*/
static int
check_namespaces(cxobj *x0,
cxobj *x1,
cxobj *x1p)
check_namespaces(cxobj *x0,
cxobj *x1,
cxobj *x1p)
{
int retval = -1;
char *namespace = NULL;
char *prefix0 = NULL;;
char *prefix10 = NULL; /* extra just for malloc problem */
char *prefix1 = NULL;;
char *prefixb = NULL; /* identityref body prefix */
cvec *nsc0 = NULL;
cvec *nsc = NULL;
cxobj *xa = NULL;
@ -258,6 +258,8 @@ check_namespaces(cxobj *x0,
/* 6. Ensure x1 cache is updated (I think it is done w xmlns_set above) */
retval = 0;
done:
if (prefixb)
free(prefixb);
if (prefix1)
free(prefix1);
return retval;
@ -372,12 +374,9 @@ text_modify(clicon_handle h,
char *opstr = NULL;
char *x1name;
char *x1cname; /* child name */
// cxobj *x0a; /* attribute */
// cxobj *x1a; /* attribute */
cxobj *x0c; /* base child */
cxobj *x0b; /* base body */
cxobj *x1c; /* mod child */
// char *xns; /* namespace */
char *x0bstr; /* mod body string */
char *x1bstr; /* mod body string */
yang_stmt *yc; /* yang child */
@ -388,8 +387,9 @@ text_modify(clicon_handle h,
char *keystr = NULL;
char *valstr = NULL;
enum insert_type insert = INS_LAST;
int changed = 0; /* Only if x0p's children have changed-> sort is necessary */
int changed = 0; /* Only if x0p's children have changed-> sort necessary */
cvec *nscx1 = NULL;
/* Check for operations embedded in tree according to netconf */
if ((ret = attr_ns_value(x1,
"operation", NETCONF_BASE_NAMESPACE,
@ -514,7 +514,7 @@ text_modify(clicon_handle h,
}
}
if (changed){
if (xml_insert(x0p, x0, insert, valstr) < 0)
if (xml_insert(x0p, x0, insert, valstr, NULL) < 0)
goto done;
}
break;
@ -563,6 +563,7 @@ text_modify(clicon_handle h,
"key", YANG_XML_NAMESPACE,
cbret, &keystr)) < 0)
goto done;
/* if insert/before, key attribute must be there */
if ((insert == INS_AFTER || insert == INS_BEFORE) &&
keystr == NULL){
@ -570,7 +571,9 @@ text_modify(clicon_handle h,
goto done;
goto fail;
}
/* If keystr is set, need a full namespace context */
if (keystr && xml_nsctx_node(x1, &nscx1) < 0)
goto done;
}
switch(op){
case OP_CREATE:
@ -623,8 +626,6 @@ text_modify(clicon_handle h,
}
if ((x0 = xml_new(x1name, x0p, (yang_stmt*)y0)) == NULL)
goto done;
// XXX if (check_namespaces(x1, x0) < 0)
// goto done;
if (xml_copy(x1, x0) < 0)
goto done;
break;
@ -708,7 +709,7 @@ text_modify(clicon_handle h,
goto fail;
}
if (changed){
if (xml_insert(x0p, x0, insert, keystr) < 0)
if (xml_insert(x0p, x0, insert, keystr, nscx1) < 0)
goto done;
}
break;

View file

@ -71,6 +71,7 @@
#include "clixon_proto.h"
#include "clixon_err.h"
#include "clixon_err_string.h"
#include "clixon_xml_nsctx.h"
#include "clixon_netconf_lib.h"
#include "clixon_proto_client.h"
@ -251,54 +252,70 @@ clicon_rpc_generate_error(char *prefix,
/*! Get database configuration
* Same as clicon_proto_change just with a cvec instead of lvec
* @param[in] h CLICON handle
* @param[in] username If NULL, use default
* @param[in] db Name of database
* @param[in] xpath XPath (or "")
* @param[in] namespace Namespace associated w xpath
* @param[in] nsc Namespace context for filter
* @param[out] xt XML tree. Free with xml_free.
* Either <config> or <rpc-error>.
* @retval 0 OK
* @retval -1 Error, fatal or xml
* @code
* cxobj *xt = NULL;
* if (clicon_rpc_get_config(h, "running", "/hello/world", "urn:example:hello", &xt) < 0)
* cxobj *xt = NULL;
* cvec *nsc = NULL;
*
* if ((nsc = xml_nsctx_init(NULL, "urn:example:hello")) == NULL)
* err;
* if (clicon_rpc_get_config(h, NULL, "running", "/hello/world", nsc, &xt) < 0)
* err;
* if ((xerr = xpath_first(xt, "/rpc-error")) != NULL){
* clicon_rpc_generate_error("", xerr);
* err;
* }
* if (xt)
* xml_free(xt);
* }
* if (xt)
* xml_free(xt);
* if (nsc)
* xml_nsctx_free(nsc);
* @endcode
* @see clicon_rpc_generate_error
*/
int
clicon_rpc_get_config(clicon_handle h,
char *db,
char *xpath,
char *namespace,
cxobj **xt)
clicon_rpc_get_config(clicon_handle h,
char *username,
char *db,
char *xpath,
cvec *nsc,
cxobj **xt)
{
int retval = -1;
struct clicon_msg *msg = NULL;
cbuf *cb = NULL;
cxobj *xret = NULL;
cxobj *xd;
char *username;
cg_var *cv = NULL;
char *prefix;
if ((cb = cbuf_new()) == NULL)
goto done;
cprintf(cb, "<rpc");
if ((username = clicon_username_get(h)) != NULL)
if (username == NULL)
username = clicon_username_get(h);
if (username != NULL)
cprintf(cb, " username=\"%s\"", username);
if (namespace)
cprintf(cb, " xmlns:nc=\"%s\"", NETCONF_BASE_NAMESPACE);
cprintf(cb, " xmlns:%s=\"%s\"",
NETCONF_BASE_PREFIX, NETCONF_BASE_NAMESPACE);
cprintf(cb, "><get-config><source><%s/></source>", db);
if (xpath && strlen(xpath)){
if (namespace)
cprintf(cb, "<nc:filter nc:type=\"xpath\" nc:select=\"%s\" xmlns=\"%s\"/>",
xpath, namespace);
else /* If xpath != /, this will probably yield an error later */
cprintf(cb, "<filter type=\"xpath\" select=\"%s\"/>", xpath);
cprintf(cb, "<%s:filter %s:type=\"xpath\" %s:select=\"%s\"",
NETCONF_BASE_PREFIX, NETCONF_BASE_PREFIX, NETCONF_BASE_PREFIX,
xpath);
while ((cv = cvec_each(nsc, cv)) != NULL){
cprintf(cb, " xmlns");
if ((prefix = cv_name_get(cv)))
cprintf(cb, ":%s", prefix);
cprintf(cb, "=\"%s\"", cv_string_get(cv));
}
cprintf(cb, "/>");
}
cprintf(cb, "</get-config></rpc>");
if ((msg = clicon_msg_encode("%s", cbuf_get(cb))) == NULL)
@ -327,6 +344,7 @@ clicon_rpc_get_config(clicon_handle h,
return retval;
}
/*! Send database entries as XML to backend daemon
* @param[in] h CLICON handle
* @param[in] db Name of database
@ -541,6 +559,7 @@ clicon_rpc_unlock(clicon_handle h,
* @param[in] h Clicon handle
* @param[in] xpath XPath in a filter stmt (or NULL/"" for no filter)
* @param[in] namespace Namespace associated w xpath
* @param[in] nsc Namespace context for filter
* @param[in] content Clixon extension: all, config, noconfig. -1 means all
* @param[in] depth Nr of XML levels to get, -1 is all, 0 is none
* @param[out] xt XML tree. Free with xml_free.
@ -550,15 +569,21 @@ clicon_rpc_unlock(clicon_handle h,
* @note if xpath is set but namespace is NULL, the default, netconf base
* namespace will be used which is most probably wrong.
* @code
* cxobj *xt = NULL;
* if (clicon_rpc_get(h, "/hello/world", "urn:example:hello", CONTENT_ALL, -1, &xt) < 0)
* err;
* if ((xerr = xpath_first(xt, "/rpc-error")) != NULL){
* clicon_rpc_generate_error(xerr);
* err;
* cxobj *xt = NULL;
* cvec *nsc = NULL;
*
* if ((nsc = xml_nsctx_init(NULL, "urn:example:hello")) == NULL)
* err;
* if (clicon_rpc_get(h, "/hello/world", nsc, CONTENT_ALL, -1, &xt) < 0)
* err;
* if ((xerr = xpath_first(xt, "/rpc-error")) != NULL){
* clicon_rpc_generate_error(xerr);
* err;
* }
* if (xt)
* xml_free(xt);
* if (xt)
* xml_free(xt);
* if (nsc)
* xml_nsctx_free(nsc);
* @endcode
* @see clicon_rpc_get_config which is almost the same as with content=config, but you can also select dbname
* @see clicon_rpc_generate_error
@ -566,7 +591,7 @@ clicon_rpc_unlock(clicon_handle h,
int
clicon_rpc_get(clicon_handle h,
char *xpath,
char *namespace,
cvec *nsc, /* namespace context for filter */
netconf_content content,
int32_t depth,
cxobj **xt)
@ -577,71 +602,6 @@ clicon_rpc_get(clicon_handle h,
cxobj *xret = NULL;
cxobj *xd;
char *username;
if ((cb = cbuf_new()) == NULL)
goto done;
cprintf(cb, "<rpc");
if ((username = clicon_username_get(h)) != NULL)
cprintf(cb, " username=\"%s\"", username);
if (namespace)
cprintf(cb, " xmlns:%s=\"%s\"",
NETCONF_BASE_PREFIX, NETCONF_BASE_NAMESPACE);
cprintf(cb, "><get");
/* Clixon extension, content=all,config, or nonconfig */
if (content != -1)
cprintf(cb, " content=\"%s\"", netconf_content_int2str(content));
/* Clixon extension, depth=<level> */
if (depth != -1)
cprintf(cb, " depth=\"%d\"", depth);
cprintf(cb, ">");
if (xpath && strlen(xpath)) {
if (namespace)
cprintf(cb, "<nc:filter nc:type=\"xpath\" nc:select=\"%s\" xmlns=\"%s\"/>",
xpath, namespace);
else /* If xpath != /, this will probably yield an error later */
cprintf(cb, "<filter type=\"xpath\" select=\"%s\"/>", xpath);
}
cprintf(cb, "</get></rpc>");
if ((msg = clicon_msg_encode("%s", cbuf_get(cb))) == NULL)
goto done;
if (clicon_rpc_msg(h, msg, &xret, NULL) < 0)
goto done;
/* Send xml error back: first check error, then ok */
if ((xd = xpath_first(xret, "/rpc-reply/rpc-error")) != NULL)
xd = xml_parent(xd); /* point to rpc-reply */
else if ((xd = xpath_first(xret, "/rpc-reply/data")) == NULL)
if ((xd = xml_new("data", NULL, NULL)) == NULL)
goto done;
if (xt){
if (xml_rm(xd) < 0)
goto done;
*xt = xd;
}
retval = 0;
done:
if (cb)
cbuf_free(cb);
if (xret)
xml_free(xret);
if (msg)
free(msg);
return retval;
}
int
clicon_rpc_get_nsc(clicon_handle h,
char *xpath,
cvec *nsc, /* namespace context for filter */
netconf_content content,
int32_t depth,
cxobj **xt)
{
int retval = -1;
struct clicon_msg *msg = NULL;
cbuf *cb = NULL;
cxobj *xret = NULL;
cxobj *xd;
char *username;
cg_var *cv = NULL;
char *prefix;

View file

@ -422,8 +422,8 @@ xmlns_set(cxobj *x,
else{ /* xmlns="<uri>" */
if ((xa = xml_new("xmlns", x, NULL)) == NULL)
goto done;
xml_type_set(xa, CX_ATTR);
}
xml_type_set(xa, CX_ATTR);
if (xml_value_set(xa, ns) < 0)
goto done;
/* (re)set namespace cache (as used in xml2ns) */
@ -449,38 +449,41 @@ xml2prefix(cxobj *xn,
{
int retval = -1;
cxobj *xa = NULL;
cxobj *xp;
char *prefix = NULL;
int ret;
while (xn != NULL){
if (nscache_get_prefix(xn, namespace, &prefix) == 1) /* found */
goto found;
// if (xn->x_ns_cache == NULL){ /* Look in node */
xa = NULL;
while ((xa = xml_child_each(xn, xa, CX_ATTR)) != NULL) {
/* xmlns=namespace */
if (strcmp("xmlns", xml_name(xa)) == 0){
if (strcmp(xml_value(xa), namespace) == 0){
clicon_debug(1, "%sA NULL %s", __FUNCTION__, namespace);
if (nscache_set(xn, NULL, namespace) < 0)
goto done;
prefix = NULL;
goto found;
}
}
/* xmlns:prefix=namespace */
else if (strcmp("xmlns", xml_prefix(xa)) == 0){
if (strcmp(xml_value(xa), namespace) == 0){
prefix = xml_name(xa);
assert(strcmp(prefix, "xmlns"));
if (nscache_set(xn, prefix, namespace) < 0)
goto done;
goto found;
}
}
if (nscache_get_prefix(xn, namespace, &prefix) == 1) /* found */
goto found;
xa = NULL;
while ((xa = xml_child_each(xn, xa, CX_ATTR)) != NULL) {
/* xmlns=namespace */
if (strcmp("xmlns", xml_name(xa)) == 0){
if (strcmp(xml_value(xa), namespace) == 0){
if (nscache_set(xn, NULL, namespace) < 0)
goto done;
prefix = NULL; /* Maybe should set all caches in ns:s children? */
goto found;
}
// }
xn = xml_parent(xn);
}
/* xmlns:prefix=namespace */
else if (strcmp("xmlns", xml_prefix(xa)) == 0){
if (strcmp(xml_value(xa), namespace) == 0){
prefix = xml_name(xa);
if (nscache_set(xn, prefix, namespace) < 0)
goto done;
goto found;
}
}
}
if ((xp = xml_parent(xn)) != NULL){
if ((ret = xml2prefix(xp, namespace, &prefix)) < 0)
goto done;
if (ret == 1){
if (nscache_set(xn, prefix, namespace) < 0)
goto done;
goto found;
}
}
retval = 0;
done:

View file

@ -2212,7 +2212,7 @@ xml_default(cxobj *xt,
goto done;
free(str);
added++;
if (xml_insert(xt, xc, INS_LAST, NULL) < 0)
if (xml_insert(xt, xc, INS_LAST, NULL, NULL) < 0)
goto done;
}
}
@ -2401,29 +2401,30 @@ xml_spec_populate(cxobj *x,
return retval;
}
/*! Translate from restconf api-path(cvv) to xml xpath(cbuf) and namespace
/*! Translate from restconf api-path(cvv) to xml xpath(cbuf) and namespace context
*
* @param[in] api_path URI-encoded path expression" (RFC8040 3.5.3) as cvec
* @param[in] offset Offset of cvec, where api-path starts
* @param[in] yspec Yang spec
* @param[in,out] xpath The xpath as cbuf (must be created and may have content)
* @param[out] namespace Namespace of xpath (direct pointer don't free)
* @param[out] nsc Namespace context of xpath (free w xml_nsctx_free)
* @param[out] xerr Netconf error message
* @retval 1 OK
* @retval 0 Invalid api_path or associated XML, netconf error xml set
* @retval -1 Fatal error, clicon_err called
*
* @code
* cbuf *xpath = cbuf_new();
* cvec *cvv = NULL;
* cvec *nsc = NULL;
* if (str2cvec("www.foo.com/restconf/a/b=c", '/', '=', &cvv) < 0)
* err;
* if ((ret = api_path2xpath_cvv(yspec, cvv, 0, cxpath, NULL)) < 0)
* if ((ret = api_path2xpath_cvv(yspec, cvv, 0, cxpath, &nsc, NULL)) < 0)
* err;
* if (ret == 1)
* ... access xpath as cbuf_get(xpath)
* cbuf_free(xpath)
* cbuf_free(xpath);
* cvec_free(nsc);
* @endcode
* It works like this:
* Assume origin incoming path is
@ -2441,137 +2442,8 @@ api_path2xpath_cvv(cvec *api_path,
int offset,
yang_stmt *yspec,
cbuf *xpath,
char **namespace,
cvec **nscp,
cxobj **xerr)
{
int retval = -1;
int i;
cg_var *cv;
char *nodeid;
char *prefix = NULL;
char *name = NULL;
cvec *cvk = NULL; /* vector of index keys */
yang_stmt *y = NULL;
yang_stmt *ymod = NULL;
char *val;
cg_var *cvi;
char **valvec = NULL;
int vi;
int nvalvec;
cbuf *cberr = NULL;
for (i=offset; i<cvec_len(api_path); i++){
cv = cvec_i(api_path, i);
nodeid = cv_name_get(cv);
if (nodeid_split(nodeid, &prefix, &name) < 0)
goto done;
clicon_debug(1, "%s [%d] cvname: %s:%s",
__FUNCTION__, i, prefix?prefix:"", name);
if (i == offset){ /* top-node */
if (prefix == NULL){
if ((cberr = cbuf_new()) == NULL){
clicon_err(OE_UNIX, errno, "cbuf_new");
goto done;
}
cprintf(cberr, "'%s': Expected prefix:name", nodeid);
if (netconf_invalid_value_xml(xerr, "application", cbuf_get(cberr)) < 0)
goto done;
goto fail;
}
if ((ymod = yang_find_module_by_name(yspec, prefix)) == NULL){
if ((cberr = cbuf_new()) == NULL){
clicon_err(OE_UNIX, errno, "cbuf_new");
goto done;
}
cprintf(cberr, "No such yang module: %s", prefix);
if (netconf_invalid_value_xml(xerr, "application", cbuf_get(cberr)) < 0)
goto done;
goto fail;
}
y = yang_find_datanode(ymod, name);
}
else
y = yang_find_datanode(y, name);
if (y == NULL){
if (netconf_unknown_element_xml(xerr, "application", name, "Unknown element") < 0)
goto done;
goto fail;
}
/* Check if has value, means '=' */
if (cv2str(cv, NULL, 0) > 0){
if ((val = cv2str_dup(cv)) == NULL)
goto done;
switch (yang_keyword_get(y)){
case Y_LIST:
/* Transform value "a,b,c" to "a" "b" "c" (nvalvec=3)
* Note that vnr can be < length of cvk, due to empty or unset values
*/
if (valvec){ /* loop, valvec may have been used before */
free(valvec);
valvec = NULL;
}
if ((valvec = clicon_strsep(val, ",", &nvalvec)) == NULL)
goto done;
cvk = y->ys_cvec; /* Use Y_LIST cache, see ys_populate_list() */
cvi = NULL;
/* Iterate over individual yang keys */
cprintf(xpath, "/%s", name);
vi = 0;
while ((cvi = cvec_each(cvk, cvi)) != NULL && vi<nvalvec)
cprintf(xpath, "[%s='%s']", cv_string_get(cvi), valvec[vi++]);
break;
case Y_LEAF_LIST: /* XXX: LOOP? */
cprintf(xpath, "/%s", name);
if (val)
cprintf(xpath, "[.='%s']", val);
else
cprintf(xpath, "[.='']");
break;
default:
cprintf(xpath, "%s%s", (i==offset?"":"/"), name);
break;
}
if (val)
free(val);
}
else
cprintf(xpath, "%s%s", (i==offset?"":"/"), name);
if (prefix){
free(prefix);
prefix = NULL;
}
if (name){
free(name);
name = NULL;
}
} /* for */
/* return values: yang module */
if (namespace)
*namespace = yang_find_mynamespace(ymod);
retval = 1; /* OK */
done:
if (cberr != NULL)
cbuf_free(cberr);
if (valvec)
free(valvec);
if (prefix)
free(prefix);
if (name)
free(name);
return retval;
fail:
retval = 0; /* Validation failed */
goto done;
}
/*! Temp alternative to api_path2xpath_cvv */
int
api_path2xpath_cvv2(cvec *api_path,
int offset,
yang_stmt *yspec,
cbuf *xpath,
cvec *nsc,
cxobj **xerr)
{
int retval = -1;
int i;
@ -2590,7 +2462,11 @@ api_path2xpath_cvv2(cvec *api_path,
int nvalvec;
cbuf *cberr = NULL;
char *namespace = NULL;
cvec *nsc = NULL;
/* Initialize namespace context */
if ((nsc = xml_nsctx_init(NULL, NULL)) == NULL)
goto done;
for (i=offset; i<cvec_len(api_path); i++){
cv = cvec_i(api_path, i);
nodeid = cv_name_get(cv);
@ -2633,6 +2509,7 @@ api_path2xpath_cvv2(cvec *api_path,
goto done;
goto fail;
}
/* Get XML/xpath prefix given namespace.
* note different from api-path prefix
*/
@ -2712,6 +2589,10 @@ api_path2xpath_cvv2(cvec *api_path,
}
} /* for */
retval = 1; /* OK */
if (nscp){
*nscp = nsc;
nsc = NULL;
}
done:
clicon_debug(1, "%s retval:%d", __FUNCTION__, retval);
if (cberr != NULL)
@ -2720,6 +2601,8 @@ api_path2xpath_cvv2(cvec *api_path,
free(valvec);
if (prefix)
free(prefix);
if (nsc)
cvec_free(nsc);
if (name)
free(name);
return retval;
@ -2732,17 +2615,19 @@ api_path2xpath_cvv2(cvec *api_path,
* @param[in] api_path URI-encoded path expression" (RFC8040 3.5.3)
* @param[in] yspec Yang spec
* @param[out] xpath xpath (use free() to deallocate)
* @param[out] namespace Namespace of xpath (direct pointer don't free)
* @param[out] nsc Namespace context of xpath (free w xml_nsctx_free)
* @retval 1 OK
* @retval 0 Invalid api_path or associated XML, netconf called
* @retval -1 Fatal error, clicon_err called
* @code
* char *xpath = NULL;
* if ((ret = api_path2xpath("/module:a/b", yspec, &xpath, &namespace)) < 0)
* cvec *nsc = NULL;
* if ((ret = api_path2xpath("/module:a/b", yspec, &xpath, &nsc)) < 0)
* err;
* if (ret == 1)
* ... access xpath as cbuf_get(xpath)
* free(xpath)
* cvec_free(nsc);
* @endcode
*
* @see api_path2xml_cvv which uses other parameter formats
@ -2751,7 +2636,7 @@ int
api_path2xpath(char *api_path,
yang_stmt *yspec,
char **xpathp,
char **namespace)
cvec **nsc)
{
int retval = -1;
cvec *cvv = NULL; /* api-path vector */
@ -2763,7 +2648,7 @@ api_path2xpath(char *api_path,
goto done;
if ((xpath = cbuf_new()) == NULL)
goto done;
if ((retval = api_path2xpath_cvv(cvv, 0, yspec, xpath, namespace, &xerr)) < 0){
if ((retval = api_path2xpath_cvv(cvv, 0, yspec, xpath, nsc, &xerr)) < 0){
clicon_err(OE_UNIX, errno, "strdup");
goto done;
}

View file

@ -138,7 +138,7 @@ xml_nsctx_set(cvec *cvv,
/*! Create and initialize XML namespace context
* @param[in] prefix Namespace prefix, or NULL for default
* @param[in] namespace Cached namespace to set (assume non-null?)
* @param[in] namespace Set this namespace. If NULL create empty nsctx
* @retval nsc Return namespace context in form of a cvec
* @retval NULL Error
* @code
@ -161,7 +161,7 @@ xml_nsctx_init(char *prefix,
clicon_err(OE_XML, errno, "cvec_new");
goto done;
}
if (xml_nsctx_set(cvv, prefix, namespace) < 0)
if (namespace && xml_nsctx_set(cvv, prefix, namespace) < 0)
goto done;
done:
return cvv;

View file

@ -481,6 +481,7 @@ xml_search(cxobj *xp,
* @param[in] yn Yang stmt of xml child node
* @param[in] ins Insert operation (if ordered-by user)
* @param[in] key_val Key if LIST and ins is before/after, val if LEAF_LIST
* @param[in] nsc_key Network namespace for key
* @retval i Order where xn should be inserted into xp:s children
* @retval -1 Error
* LIST: RFC 7950 7.8.6:
@ -493,14 +494,14 @@ xml_search(cxobj *xp,
* yang:insert="after"
* yang:value="3des-cbc">blowfish-cbc</cipher>)
*/
static int
xml_insert_userorder(cxobj *xp,
cxobj *xn,
yang_stmt *yn,
int mid,
enum insert_type ins,
char *key_val)
char *key_val,
cvec *nsc_key)
{
int retval = -1;
int i;
@ -538,7 +539,7 @@ xml_insert_userorder(cxobj *xp,
else{
switch (yang_keyword_get(yn)){
case Y_LEAF_LIST:
if ((xc = xpath_first(xp, "%s[.='%s']", xml_name(xn),key_val)) == NULL)
if ((xc = xpath_first_nsc(xp, nsc_key, "%s[.='%s']", xml_name(xn), key_val)) == NULL)
clicon_err(OE_YANG, 0, "bad-attribute: value, missing-instance: %s", key_val);
else {
if ((i = xml_child_order(xp, xc)) < 0)
@ -548,7 +549,7 @@ xml_insert_userorder(cxobj *xp,
}
break;
case Y_LIST:
if ((xc = xpath_first(xp, "%s%s", xml_name(xn), key_val)) == NULL)
if ((xc = xpath_first_nsc(xp, nsc_key, "%s%s", xml_name(xn), key_val)) == NULL)
clicon_err(OE_YANG, 0, "bad-attribute: key, missing-instance: %s", key_val);
else {
if ((i = xml_child_order(xp, xc)) < 0)
@ -577,6 +578,7 @@ xml_insert_userorder(cxobj *xp,
* @param[in] userorder Set if ordered-by user, otherwise 0
* @param[in] ins Insert operation (if ordered-by user)
* @param[in] key_val Key if LIST and ins is before/after, val if LEAF_LIST
* @param[in] nsc_key Network namespace for key
* @param[in] low Lower range limit
* @param[in] upper Upper range limit
* @retval i Order where xn should be inserted into xp:s children
@ -590,6 +592,7 @@ xml_insert2(cxobj *xp,
int userorder,
enum insert_type ins,
char *key_val,
cvec *nsc_key,
int low,
int upper)
{
@ -623,7 +626,7 @@ xml_insert2(cxobj *xp,
}
if (yc == yn){ /* Same yang */
if (userorder){ /* append: increment linearly until no longer equal */
retval = xml_insert_userorder(xp, xn, yn, mid, ins, key_val);
retval = xml_insert_userorder(xp, xn, yn, mid, ins, key_val, nsc_key);
goto done;
}
else /* Ordered by system */
@ -649,9 +652,9 @@ xml_insert2(cxobj *xp,
goto done;
}
else if (cmp < 0)
return xml_insert2(xp, xn, yn, yni, userorder, ins, key_val, low, mid);
return xml_insert2(xp, xn, yn, yni, userorder, ins, key_val, nsc_key, low, mid);
else
return xml_insert2(xp, xn, yn, yni, userorder, ins, key_val, mid+1, upper);
return xml_insert2(xp, xn, yn, yni, userorder, ins, key_val, nsc_key, mid+1, upper);
done:
return retval;
}
@ -660,7 +663,8 @@ xml_insert2(cxobj *xp,
* @param[in] xp Parent xml node. If NULL just remove from old parent.
* @param[in] x Child xml node to insert under xp
* @param[in] ins Insert operation (if ordered-by user)
* @param[in] key_val Key if LIST and ins is before/after, val if LEAF_LIST
* @param[in] key_val Key if x is LIST and ins is before/after, val if LEAF_LIST
* @param[in] nsc_key Network namespace for key
* @retval 0 OK
* @retval -1 Error
* @see xml_addsub where xc is appended. xml_insert is xml_addsub();xml_sort()
@ -669,7 +673,8 @@ int
xml_insert(cxobj *xp,
cxobj *xi,
enum insert_type ins,
char *key_val)
char *key_val,
cvec *nsc_key)
{
int retval = -1;
cxobj *xa;
@ -704,7 +709,7 @@ xml_insert(cxobj *xp,
userorder = (yang_find(y, Y_ORDERED_BY, "user") != NULL);
yi = yang_order(y);
if ((i = xml_insert2(xp, xi, y, yi,
userorder, ins, key_val,
userorder, ins, key_val, nsc_key,
low, upper)) < 0)
goto done;
if (xml_child_insert_pos(xp, xi, i) < 0)