Reverted some of the nsc xpath API changes. In the revert, xpath_first() and xpath_vec() retain their old syntax with nsc==NULL.

The reason is to be conservative with the API. However, less used functions, such as xpath_vec_bool(), xpath_vec_ctx() and xpath_vec_flag()  are changed with a new `nsc`parameter, which should be set to NULL in most cases.
This commit is contained in:
Olof hagsand 2019-07-09 12:19:03 +02:00
parent 89f751357d
commit 40d5b99d3b
32 changed files with 391 additions and 266 deletions

View file

@ -69,17 +69,18 @@
### API changes on existing features (you may need to change your code)
* The Clixon API has been extended with namespaces, or namespace contexts in the following cases [Netconf get/get-config :xpath capability does not support namespaces](https://github.com/clicon/clixon/issues/75)
* CLIspec functions have added namespace parameter:
* The Clixon API has been extended with namespaces, or namespace contexts in the following cases (see [README.md#xml-and-xpath] for explanation):
* CLIspec functions have added optional namespace parameter:
* `cli_show_config <db> <format> <xpath>` --> `cli_show_config <db> <format> <xpath> <namespace>`
* `cli_copy_config <db> <xpath> ...` --> `cli_copy_config <db> <xpath> <namespace> ...`
* Xpath API
* `xpath_first(x, format, ...)` --> `xpath_first(x, nsc, format, ...)`
* `xpath_vec(x, format, vec, veclen, ...)` --> `xpath_vec(x, nsc, format, vec, veclen, ...)`
* `xpath_vec_flag(x, format, flags, vec, veclen, ...)` --> `xpath_vec_flag(x, format, flags, vec, veclen, ...)`
* Change the following Xpath API functions (xpath_first and xpath_vec remain as-is):
* `xpath_vec_flag(x, format, flags, vec, veclen, ...)` --> `xpath_vec_flag(x, nsc, format, flags, vec, veclen, ...)`
* `xpath_vec_bool(x, format, ...)` --> `xpath_vec_bool(x, nsc, format, ...)`
* `xpath_vec_ctx(x, xpath, xp)` --> `xpath_vec_ctx(x, nsc, xpath, xp)`
* xmldb_get0 has an added `nsc` parameter:
* New Xpath API functions with namespace contexts:
* `xpath_first_nsc(x, nsc, format, ...)`
* `xpath_vec_nsc(x, nsc, format, vec, veclen, ...)`
* Change xmldb_get0 with added `nsc` parameter:
* `xmldb_get0(h, db, xpath, copy, xret, msd)` --> `xmldb_get0(h, db, nsc, xpath, copy, xret, msd)`
* The plugin statedata callback (ca_statedata) has been extended with an nsc parameter:
* `int example_statedata(clicon_handle h, cvec *nsc, char *xpath, cxobj *xstate);`
@ -104,7 +105,6 @@
```
curl -X PUT http://localhost/restconf/data/mod:a -d {"a":"x"}
```
* Undefine `RESTCONF_NS_DATA_CHECK` in include/clixon_custom.h to disable strict check.
* Many validation functions have changed error parameter from cbuf to xml tree.
* XML trees are more flexible for utility tools
* If you use these(mostly internal), you need to change the error function: `generic_validate, from_validate_common, xml_yang_validate_all_top, xml_yang_validate_all, xml_yang_validate_add, xml_yang_validate_rpc, xml_yang_validate_list_key_only`

View file

@ -131,14 +131,14 @@ The standards covered include:
- [Namespaces in XML 1.0](https://www.w3.org/TR/2009/REC-xml-names-20091208)
- [XPATH 1.0](https://www.w3.org/TR/xpath-10)
Not supported:
Not supported in the XML:
- !DOCTYPE (ie DTD)
The following xpath axes are supported:
- CHILD, DESCENDANT, DESCENDANT_OR_SELF, SELF, and PARENT
The following XPATH axes are supported:
- child, descendant, descendant_or_self, self, and parent
The following xpath axes are _not_ supported:
- PRECEEDING, PRECEEDING_SIBLING, NAMESPACE, FOLLOWING_SIBLING, FOLLOWING, ANCESTOR,ANCESTOR_OR_SELF, ATTRIBUTE
- preceeding, preceeding_sibling, namespace, following_sibling, following, ancestor,ancestor_or_self, and attribute
Note that base netconf namespace syntax is not enforced but recommended, which means that the following two expressions are treated equivalently:
```
@ -157,7 +157,10 @@ XPATHs may contain prefixes. Example: `/if:a/if:b`. The prefixes have
associated namespaces. For example, `if` may be bound to
`urn:ietf:params:xml:ns:yang:ietf-interfaces`. The prefix to namespace binding is called a _namespace context_ (nsc).
In yang, the xpath and xml prefixes may not be well-known. For example, the import statement specifies a prefix to an imported module that is local in scope. Other modules may use another prefix. The module name and namespace however are unique.
In the Clixon API, there are two variants on namespace contexts: _implicit_ (given by the XML); or _explicit_ given by an external mapping.
#### 1. Implicit namespace mapping
Implicit mapping is typical for basic known XML, where the context is
@ -169,7 +172,8 @@ Example:
XML: <if:a xmlns:if="urn:example:if" xmlns:ip="urn:example:ip"><ip:b/></if>
XPATH: /if:a/ip:b
```
When you call an xpath API function, call it with nsc set to NULL. This is the default.
When you call an xpath API function, call it with nsc set to NULL, or use an API function without an nsc parameter.
This is the default and normal case.
#### 2. Explicit namespace mapping
@ -184,7 +188,7 @@ call. Example:
XML: <if:a xmlns:if="urn:example:if" xmlns:ip="urn:example:ip"><ip:b/></if>
NETCONF:<get-config><filter select="/x:a/y:b" xmlns:x="urn:example:if" xmlns:y="urn:example:ip/>
```
Here, x,y are prefixes used for two namespaces that are given by if,ip
Here, x,y are prefixes used for two namespaces that are given by `if,ip`
in the xml. In this case, the namespaces (eg `urn:example:if`) must be
compared instead.

View file

@ -266,7 +266,7 @@ client_statedata(clicon_handle h,
* Actually this is a safety catch, should realy be done in plugins
* and modules_state functions.
*/
if (xpath_vec(*xret, nsc, "%s", &xvec, &xlen, xpath?xpath:"/") < 0)
if (xpath_vec_nsc(*xret, nsc, "%s", &xvec, &xlen, xpath?xpath:"/") < 0)
goto done;
/* If vectors are specified then mark the nodes found and
* then filter out everything else,
@ -363,7 +363,7 @@ from_client_get_config(clicon_handle h,
if ((ret = nacm_access_pre(h, username, NACM_DATA, &xnacm)) < 0)
goto done;
if (ret == 0){ /* Do NACM validation */
if (xpath_vec(xret, nsc, "%s", &xvec, &xlen, xpath?xpath:"/") < 0)
if (xpath_vec_nsc(xret, nsc, "%s", &xvec, &xlen, xpath?xpath:"/") < 0)
goto done;
/* NACM datanode/module read validation */
if (nacm_datanode_read(xret, xvec, xlen, username, xnacm) < 0)
@ -455,14 +455,14 @@ from_client_edit_config(clicon_handle h,
goto done;
goto ok;
}
if ((x = xpath_first(xn, NULL, "default-operation")) != NULL){
if ((x = xpath_first(xn, "default-operation")) != NULL){
if (xml_operation(xml_body(x), &operation) < 0){
if (netconf_invalid_value(cbret, "protocol", "Wrong operation")< 0)
goto done;
goto ok;
}
}
if ((xc = xpath_first(xn, NULL, "config")) == NULL){
if ((xc = xpath_first(xn, "config")) == NULL){
if (netconf_missing_element(cbret, "protocol", "config", NULL) < 0)
goto done;
goto ok;
@ -858,7 +858,7 @@ from_client_get(clicon_handle h,
if ((ret = nacm_access_pre(h, username, NACM_DATA, &xnacm)) < 0)
goto done;
if (ret == 0){ /* Do NACM validation */
if (xpath_vec(xret, nsc, "%s", &xvec, &xlen, xpath?xpath:"/") < 0)
if (xpath_vec_nsc(xret, nsc, "%s", &xvec, &xlen, xpath?xpath:"/") < 0)
goto done;
/* NACM datanode/module read validation */
if (nacm_datanode_read(xret, xvec, xlen, username, xnacm) < 0)
@ -1016,9 +1016,9 @@ from_client_create_subscription(clicon_handle h,
if ((nsc = xml_nsctx_init(NULL, "urn:ietf:params:xml:ns:netmod:notification")) == NULL)
goto done;
if ((x = xpath_first(xe, nsc, "//stream")) != NULL)
if ((x = xpath_first_nsc(xe, nsc, "//stream")) != NULL)
stream = xml_find_value(x, "body");
if ((x = xpath_first(xe, nsc, "//stopTime")) != NULL){
if ((x = xpath_first_nsc(xe, nsc, "//stopTime")) != NULL){
if ((stoptime = xml_find_value(x, "body")) != NULL &&
str2time(stoptime, &stop) < 0){
if (netconf_bad_element(cbret, "application", "stopTime", "Expected timestamp") < 0)
@ -1026,7 +1026,7 @@ from_client_create_subscription(clicon_handle h,
goto ok;
}
}
if ((x = xpath_first(xe, nsc, "//startTime")) != NULL){
if ((x = xpath_first_nsc(xe, nsc, "//startTime")) != NULL){
if ((starttime = xml_find_value(x, "body")) != NULL &&
str2time(starttime, &start) < 0){
if (netconf_bad_element(cbret, "application", "startTime", "Expected timestamp") < 0)
@ -1034,7 +1034,7 @@ from_client_create_subscription(clicon_handle h,
goto ok;
}
}
if ((xfilter = xpath_first(xe, nsc, "//filter")) != NULL){
if ((xfilter = xpath_first_nsc(xe, nsc, "//filter")) != NULL){
if ((ftype = xml_find_value(xfilter, "type")) != NULL){
/* Only accept xpath as filter type */
if (strcmp(ftype, "xpath") != 0){
@ -1175,7 +1175,7 @@ from_client_msg(clicon_handle h,
goto reply;
}
if ((x = xpath_first(xt, NULL, "/rpc")) == NULL){
if ((x = xpath_first_nsc(xt, NULL, "/rpc")) == NULL){
if (netconf_malformed_message(cbret, "rpc keyword expected")< 0)
goto done;
goto reply;

View file

@ -682,13 +682,13 @@ compare_dbs(clicon_handle h,
astext = 0;
if (clicon_rpc_get_config(h, "running", "/", NULL, &xc1) < 0)
goto done;
if ((xerr = xpath_first(xc1, NULL, "/rpc-error")) != NULL){
if ((xerr = xpath_first(xc1, "/rpc-error")) != NULL){
clicon_rpc_generate_error("Get configuration", xerr);
goto done;
}
if (clicon_rpc_get_config(h, "candidate", "/", NULL, &xc2) < 0)
goto done;
if ((xerr = xpath_first(xc2, NULL, "/rpc-error")) != NULL){
if ((xerr = xpath_first(xc2, "/rpc-error")) != NULL){
clicon_rpc_generate_error("Get configuration", xerr);
goto done;
}
@ -853,7 +853,7 @@ save_config_file(clicon_handle h,
clicon_err(OE_CFG, 0, "get config: empty tree"); /* Shouldnt happen */
goto done;
}
if ((xerr = xpath_first(xt, NULL, "/rpc-error")) != NULL){
if ((xerr = xpath_first(xt, "/rpc-error")) != NULL){
clicon_rpc_generate_error("Get configuration", xerr);
goto done;
}
@ -961,7 +961,7 @@ cli_notification_cb(int s,
}
if (clicon_msg_decode(reply, NULL, &xt) < 0) /* XXX pass yang_spec */
goto done;
if ((xe = xpath_first(xt, NULL, "//event")) != NULL){
if ((xe = xpath_first(xt, "//event")) != NULL){
x = NULL;
while ((x = xml_child_each(xe, x, -1)) != NULL) {
switch (format){
@ -1191,7 +1191,7 @@ cli_copy_config(clicon_handle h,
/* Get from object configuration and store in x1 */
if (clicon_rpc_get_config(h, db, cbuf_get(cb), namespace, &x1) < 0)
goto done;
if ((xerr = xpath_first(x1, NULL, "/rpc-error")) != NULL){
if ((xerr = xpath_first(x1, "/rpc-error")) != NULL){
clicon_rpc_generate_error("Get configuration", xerr);
goto done;
}
@ -1211,7 +1211,7 @@ cli_copy_config(clicon_handle h,
cprintf(cb, "/%s", keyname);
if ((nsc = xml_nsctx_init(NULL, namespace)) == NULL)
goto done;
if ((x = xpath_first(x2, nsc, "%s", cbuf_get(cb))) == NULL){
if ((x = xpath_first_nsc(x2, nsc, "%s", cbuf_get(cb))) == NULL){
clicon_err(OE_PLUGIN, 0, "Field %s not found in copy tree", keyname);
goto done;
}

View file

@ -157,7 +157,7 @@ expand_dbvar(void *h,
/* Get configuration */
if (clicon_rpc_get_config(h, dbstr, xpath, namespace, &xt) < 0) /* XXX */
goto done;
if ((xerr = xpath_first(xt, NULL, "/rpc-error")) != NULL){
if ((xerr = xpath_first(xt, "/rpc-error")) != NULL){
clicon_rpc_generate_error("Get configuration", xerr);
goto ok;
}
@ -198,12 +198,12 @@ expand_dbvar(void *h,
fprintf(stderr, "%s\n", reason);
goto done;
}
if ((xcur = xpath_first(xt, nsc, "%s", xpath)) == NULL){
if ((xcur = xpath_first_nsc(xt, nsc, "%s", xpath)) == NULL){
clicon_err(OE_DB, 0, "xpath %s should return merged content", xpath);
goto done;
}
}
if (xpath_vec(xcur, nsc, "%s", &xvec, &xlen, xpathcur) < 0)
if (xpath_vec_nsc(xcur, nsc, "%s", &xvec, &xlen, xpathcur) < 0)
goto done;
bodystr0 = NULL; /* Assume sorted XML where duplicates are adjacent */
for (i = 0; i < xlen; i++) {
@ -463,7 +463,7 @@ cli_show_config1(clicon_handle h,
if (clicon_rpc_get(h, cbuf_get(cbxpath), namespace, &xt) < 0)
goto done;
}
if ((xerr = xpath_first(xt, NULL, "/rpc-error")) != NULL){
if ((xerr = xpath_first(xt, "/rpc-error")) != NULL){
clicon_rpc_generate_error("Get configuration", xerr);
goto done;
}
@ -608,13 +608,13 @@ show_conf_xpath(clicon_handle h,
if (clicon_rpc_get_config(h, str, xpath, namespace, &xt) < 0)
goto done;
if ((xerr = xpath_first(xt, NULL, "/rpc-error")) != NULL){
if ((xerr = xpath_first(xt, "/rpc-error")) != NULL){
clicon_rpc_generate_error("Get configuration", xerr);
goto done;
}
if ((nsc = xml_nsctx_init(NULL, namespace)) == NULL)
goto done;
if (xpath_vec(xt, nsc, "%s", &xv, &xlen, xpath) < 0)
if (xpath_vec_nsc(xt, nsc, "%s", &xv, &xlen, xpath) < 0)
goto done;
for (i=0; i<xlen; i++)
xml_print(stdout, xv[i]);
@ -715,11 +715,11 @@ cli_show_auto1(clicon_handle h,
goto done;
}
if ((xerr = xpath_first(xt, NULL, "/rpc-error")) != NULL){
if ((xerr = xpath_first(xt, "/rpc-error")) != NULL){
clicon_rpc_generate_error("Get configuration", xerr);
goto done;
}
if ((xp = xpath_first(xt, nsc, "%s", xpath)) != NULL)
if ((xp = xpath_first_nsc(xt, nsc, "%s", xpath)) != NULL)
/* Print configuration according to format */
switch (format){
case FORMAT_XML:

View file

@ -100,7 +100,7 @@ netconf_hello_dispatch(cxobj *xn)
cxobj *xp;
int retval = -1;
if ((xp = xpath_first(xn, NULL, "//hello")) != NULL)
if ((xp = xpath_first(xn, "//hello")) != NULL)
retval = netconf_hello(xp);
return retval;
}

View file

@ -164,14 +164,14 @@ netconf_get_target(cxobj *xn,
cxobj *x;
char *target = NULL;
if ((x = xpath_first(xn, NULL, "%s", path)) != NULL){
if (xpath_first(x, NULL, "candidate") != NULL)
if ((x = xpath_first(xn, "%s", path)) != NULL){
if (xpath_first(x, "candidate") != NULL)
target = "candidate";
else
if (xpath_first(x, NULL, "running") != NULL)
if (xpath_first(x, "running") != NULL)
target = "running";
else
if (xpath_first(x, NULL, "startup") != NULL)
if (xpath_first(x, "startup") != NULL)
target = "startup";
}
return target;

View file

@ -121,7 +121,7 @@ netconf_input_packet(clicon_handle h,
goto done;
}
free(str0);
if ((xrpc=xpath_first(xreq, NULL, "//rpc")) != NULL){
if ((xrpc=xpath_first(xreq, "//rpc")) != NULL){
isrpc++;
if (xml_spec_populate_rpc(h, xrpc, yspec) < 0)
goto done;
@ -134,7 +134,7 @@ netconf_input_packet(clicon_handle h,
}
}
else
if (xpath_first(xreq, NULL, "//hello") != NULL)
if (xpath_first(xreq, "//hello") != NULL)
;
else{
clicon_log(LOG_WARNING, "Invalid netconf msg: neither rpc or hello: dropped");

View file

@ -140,7 +140,7 @@ netconf_get_config(clicon_handle h,
cxobj *xconf;
/* ie <filter>...</filter> */
if ((xfilter = xpath_first(xn, NULL, "filter")) != NULL)
if ((xfilter = xpath_first(xn, "filter")) != NULL)
ftype = xml_find_value(xfilter, "type");
if (ftype == NULL || strcmp(ftype, "xpath")==0){
if (clicon_rpc_netconf_xml(h, xml_parent(xn), xret, NULL) < 0)
@ -154,8 +154,8 @@ netconf_get_config(clicon_handle h,
if (clicon_rpc_netconf_xml(h, xml_parent(xn), xret, NULL) < 0)
goto done;
if (xfilter &&
(xfilterconf = xpath_first(xfilter, NULL, "//configuration"))!= NULL &&
(xconf = xpath_first(*xret, NULL, "/rpc-reply/data")) != NULL){
(xfilterconf = xpath_first(xfilter, "//configuration"))!= NULL &&
(xconf = xpath_first(*xret, "/rpc-reply/data")) != NULL){
/* xml_filter removes parts of xml tree not matching */
if ((strcmp(xml_name(xfilterconf), xml_name(xconf))!=0) ||
xml_filter(xfilterconf, xconf) < 0){
@ -208,7 +208,7 @@ get_edit_opts(cxobj *xn,
cxobj *x;
char *optstr;
if ((x = xpath_first(xn, NULL, "test-option")) != NULL){
if ((x = xpath_first(xn, "test-option")) != NULL){
if ((optstr = xml_body(x)) != NULL){
if (strcmp(optstr, "test-then-set") == 0)
*testopt = TEST_THEN_SET;
@ -220,7 +220,7 @@ get_edit_opts(cxobj *xn,
goto parerr;
}
}
if ((x = xpath_first(xn, NULL, "error-option")) != NULL){
if ((x = xpath_first(xn, "error-option")) != NULL){
if ((optstr = xml_body(x)) != NULL){
if (strcmp(optstr, "stop-on-error") == 0)
*erropt = STOP_ON_ERROR;
@ -352,7 +352,7 @@ netconf_get(clicon_handle h,
cxobj *xconf;
/* ie <filter>...</filter> */
if ((xfilter = xpath_first(xn, NULL, "filter")) != NULL)
if ((xfilter = xpath_first(xn, "filter")) != NULL)
ftype = xml_find_value(xfilter, "type");
if (ftype == NULL || strcmp(ftype, "xpath")==0){
if (clicon_rpc_netconf_xml(h, xml_parent(xn), xret, NULL) < 0)
@ -366,8 +366,8 @@ netconf_get(clicon_handle h,
if (clicon_rpc_netconf_xml(h, xml_parent(xn), xret, NULL) < 0)
goto done;
if (xfilter &&
(xfilterconf = xpath_first(xfilter, NULL, "//configuration"))!= NULL &&
(xconf = xpath_first(*xret, NULL, "/rpc-reply/data")) != NULL){
(xfilterconf = xpath_first(xfilter, "//configuration"))!= NULL &&
(xconf = xpath_first(*xret, "/rpc-reply/data")) != NULL){
/* xml_filter removes parts of xml tree not matching */
if ((strcmp(xml_name(xfilterconf), xml_name(xconf))!=0) ||
xml_filter(xfilterconf, xconf) < 0){
@ -448,7 +448,7 @@ netconf_notification_cb(int s,
if ((nsc = xml_nsctx_init(NULL, "urn:ietf:params:xml:ns:netconf:notification:1.0")) == NULL)
goto done;
if ((xn = xpath_first(xt, nsc, "notification")) == NULL)
if ((xn = xpath_first_nsc(xt, nsc, "notification")) == NULL)
goto ok;
/* create netconf message */
if ((cb = cbuf_new()) == NULL){
@ -500,7 +500,7 @@ netconf_create_subscription(clicon_handle h,
int s;
char *ftype;
if ((xfilter = xpath_first(xn, NULL, "//filter")) != NULL){
if ((xfilter = xpath_first(xn, "//filter")) != NULL){
if ((ftype = xml_find_value(xfilter, "type")) != NULL){
if (strcmp(ftype, "xpath") != 0){
xml_parse_va(xret, NULL, "<rpc-reply><rpc-error>"
@ -516,7 +516,7 @@ netconf_create_subscription(clicon_handle h,
}
if (clicon_rpc_netconf_xml(h, xml_parent(xn), xret, &s) < 0)
goto done;
if (xpath_first(*xret, NULL, "rpc-reply/rpc-error") != NULL)
if (xpath_first(*xret, "rpc-reply/rpc-error") != NULL)
goto ok;
if (event_reg_fd(s,
netconf_notification_cb,
@ -622,7 +622,7 @@ netconf_application_rpc(clicon_handle h,
*/
if (0)
if ((youtput = yang_find(yrpc, Y_OUTPUT, NULL)) != NULL){
xoutput=xpath_first(*xret, NULL, "/");
xoutput=xpath_first(*xret, "/");
xml_spec_set(xoutput, youtput); /* needed for xml_spec_populate */
if (xml_apply(xoutput, CX_ELMNT, xml_spec_populate, yspec) < 0)
goto done;

View file

@ -415,7 +415,7 @@ api_return_err(clicon_handle h,
clicon_debug(1, "%s", __FUNCTION__);
if ((cb = cbuf_new()) == NULL)
goto done;
if ((xtag = xpath_first(xerr, NULL, "//error-tag")) == NULL){
if ((xtag = xpath_first(xerr, "//error-tag")) == NULL){
notfound(r);
goto ok;
}

View file

@ -396,7 +396,7 @@ api_restconf(clicon_handle h,
else{
if (netconf_access_denied_xml(&xret, "protocol", "The requested URL was unauthorized") < 0)
goto done;
if ((xerr = xpath_first(xret, NULL, "//rpc-error")) != NULL){
if ((xerr = xpath_first(xret, "//rpc-error")) != NULL){
if (api_return_err(h, r, xerr, pretty, use_xml, 0) < 0)
goto done;
goto ok;

View file

@ -212,7 +212,7 @@ api_data_get2(clicon_handle h,
if (netconf_operation_failed_xml(&xerr, "protocol", clicon_err_reason) < 0)
goto done;
clicon_err_reset();
if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){
if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
goto done;
}
@ -229,7 +229,7 @@ api_data_get2(clicon_handle h,
if (clicon_rpc_get(h, xpath, namespace, &xret) < 0){
if (netconf_operation_failed_xml(&xerr, "protocol", clicon_err_reason) < 0)
goto done;
if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){
if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
goto done;
}
@ -251,7 +251,7 @@ api_data_get2(clicon_handle h,
}
#endif
/* Check if error return */
if ((xe = xpath_first(xret, NULL, "//rpc-error")) != NULL){
if ((xe = xpath_first(xret, "//rpc-error")) != NULL){
if (api_return_err(h, r, xe, pretty, use_xml, 0) < 0)
goto done;
goto ok;
@ -276,10 +276,10 @@ api_data_get2(clicon_handle h,
}
}
else{
if (xpath_vec(xret, nsc, "%s", &xvec, &xlen, xpath) < 0){
if (xpath_vec_nsc(xret, nsc, "%s", &xvec, &xlen, xpath) < 0){
if (netconf_operation_failed_xml(&xerr, "application", clicon_err_reason) < 0)
goto done;
if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){
if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
goto done;
}
@ -465,10 +465,8 @@ api_data_post(clicon_handle h,
cxobj *xtop = NULL; /* top of api-path */
cxobj *xbot = NULL; /* bottom of api-path */
yang_stmt *ybot = NULL; /* yang of xbot */
#ifdef RESTCONF_NS_DATA_CHECK
yang_stmt *ymodapi = NULL; /* yang module of api-path (if any) */
yang_stmt *ymoddata = NULL; /* yang module of data (-d) */
#endif
yang_stmt *yspec;
cxobj *xa;
cxobj *xret = NULL;
@ -496,15 +494,13 @@ api_data_post(clicon_handle h,
if (api_path){
if ((ret = api_path2xml(api_path, yspec, xtop, YC_DATANODE, 1, &xbot, &ybot)) < 0)
goto done;
#ifdef RESTCONF_NS_DATA_CHECK
if (ybot)
ymodapi=ys_module(ybot);
#endif
if (ret == 0){ /* validation failed */
if (netconf_malformed_message_xml(&xerr, clicon_err_reason) < 0)
goto done;
clicon_err_reset();
if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){
if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
goto done;
}
@ -518,7 +514,7 @@ api_data_post(clicon_handle h,
if (xml_parse_string(data, NULL, &xdata0) < 0){
if (netconf_malformed_message_xml(&xerr, clicon_err_reason) < 0)
goto done;
if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){
if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
goto done;
}
@ -531,7 +527,7 @@ api_data_post(clicon_handle h,
if ((ret = json_parse_str(data, yspec, &xdata0, &xerr)) < 0){
if (netconf_malformed_message_xml(&xerr, clicon_err_reason) < 0)
goto done;
if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){
if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
goto done;
}
@ -540,7 +536,7 @@ api_data_post(clicon_handle h,
goto ok;
}
if (ret == 0){
if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){
if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
goto done;
}
@ -555,7 +551,7 @@ api_data_post(clicon_handle h,
if (xml_child_nr(xdata0) != 1){
if (netconf_malformed_message_xml(&xerr, clicon_err_reason) < 0)
goto done;
if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){
if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
goto done;
}
@ -564,7 +560,6 @@ api_data_post(clicon_handle h,
goto ok;
}
xdata = xml_child_i(xdata0,0);
#ifdef RESTCONF_NS_DATA_CHECK
/* If the api-path (above) defines a module, then xdata must have a prefix
* and it match the module defined in api-path.
* In a POST, maybe there are cornercases where xdata (which is a child) and
@ -577,7 +572,7 @@ api_data_post(clicon_handle h,
if (ymoddata != ymodapi){
if (netconf_malformed_message_xml(&xerr, "Data is not prefixed with matching namespace") < 0)
goto done;
if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){
if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
goto done;
}
@ -594,7 +589,6 @@ api_data_post(clicon_handle h,
goto ok;
}
}
#endif /* RESTCONF_NS_DATA_CHECK */
/* Add operation (create/replace) as attribute */
if ((xa = xml_new("operation", xdata, NULL)) == NULL)
@ -620,7 +614,7 @@ api_data_post(clicon_handle h,
clicon_debug(1, "%s xml: %s api_path:%s",__FUNCTION__, cbuf_get(cbx), api_path);
if (clicon_rpc_netconf(h, cbuf_get(cbx), &xret, NULL) < 0)
goto done;
if ((xe = xpath_first(xret, NULL, "//rpc-error")) != NULL){
if ((xe = xpath_first(xret, "//rpc-error")) != NULL){
if (api_return_err(h, r, xe, pretty, use_xml, 0) < 0)
goto done;
goto ok;
@ -634,14 +628,14 @@ api_data_post(clicon_handle h,
cprintf(cbx, "<commit/></rpc>");
if (clicon_rpc_netconf(h, cbuf_get(cbx), &xretcom, NULL) < 0)
goto done;
if ((xe = xpath_first(xretcom, NULL, "//rpc-error")) != NULL){
if ((xe = xpath_first(xretcom, "//rpc-error")) != NULL){
cbuf_reset(cbx);
cprintf(cbx, "<rpc username=\"%s\">", username?username:"");
cprintf(cbx, "<discard-changes/></rpc>");
if (clicon_rpc_netconf(h, cbuf_get(cbx), &xretdis, NULL) < 0)
goto done;
/* log errors from discard, but ignore */
if ((xpath_first(xretdis, NULL, "//rpc-error")) != NULL)
if ((xpath_first(xretdis, "//rpc-error")) != NULL)
clicon_log(LOG_WARNING, "%s: discard-changes failed which may lead candidate in an inconsistent state", __FUNCTION__);
if (api_return_err(h, r, xe, pretty, use_xml, 0) < 0) /* Use original xe */
goto done;
@ -664,7 +658,7 @@ api_data_post(clicon_handle h,
if (clicon_rpc_netconf(h, cbuf_get(cbx), &xretcom, NULL) < 0)
goto done;
/* If copy-config failed, log and ignore (already committed) */
if ((xe = xpath_first(xretcom, NULL, "//rpc-error")) != NULL){
if ((xe = xpath_first(xretcom, "//rpc-error")) != NULL){
clicon_log(LOG_WARNING, "%s: copy-config running->startup failed", __FUNCTION__);
}
@ -809,10 +803,8 @@ api_data_put(clicon_handle h,
cxobj *xtop = NULL; /* top of api-path */
cxobj *xbot = NULL; /* bottom of api-path */
yang_stmt *ybot = NULL; /* yang of xbot */
#ifdef RESTCONF_NS_DATA_CHECK
yang_stmt *ymodapi = NULL; /* yang module of api-path (if any) */
yang_stmt *ymoddata = NULL; /* yang module of data (-d) */
#endif
cxobj *xparent;
yang_stmt *yp; /* yang parent */
yang_stmt *yspec;
@ -845,15 +837,13 @@ api_data_put(clicon_handle h,
if (api_path){
if ((ret = api_path2xml(api_path, yspec, xtop, YC_DATANODE, 1, &xbot, &ybot)) < 0)
goto done;
#ifdef RESTCONF_NS_DATA_CHECK
if (ybot)
ymodapi=ys_module(ybot);
#endif
if (ret == 0){ /* validation failed */
if (netconf_malformed_message_xml(&xerr, clicon_err_reason) < 0)
goto done;
clicon_err_reset();
if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){
if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
goto done;
}
@ -868,7 +858,7 @@ api_data_put(clicon_handle h,
if (xml_parse_string(data, yspec, &xdata0) < 0){
if (netconf_malformed_message_xml(&xerr, clicon_err_reason) < 0)
goto done;
if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){
if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
goto done;
}
@ -881,7 +871,7 @@ api_data_put(clicon_handle h,
if ((ret = json_parse_str(data, yspec, &xdata0, &xerr)) < 0){
if (netconf_malformed_message_xml(&xerr, clicon_err_reason) < 0)
goto done;
if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){
if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
goto done;
}
@ -890,7 +880,7 @@ api_data_put(clicon_handle h,
goto ok;
}
if (ret == 0){
if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){
if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
goto done;
}
@ -905,7 +895,7 @@ api_data_put(clicon_handle h,
if (xml_child_nr(xdata0) != 1){
if (netconf_malformed_message_xml(&xerr, clicon_err_reason) < 0)
goto done;
if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){
if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
goto done;
}
@ -914,7 +904,6 @@ api_data_put(clicon_handle h,
goto ok;
}
xdata = xml_child_i(xdata0,0);
#ifdef RESTCONF_NS_DATA_CHECK
/* If the api-path (above) defines a module, then xdata must have a prefix
* and it match the module defined in api-path
* This does not apply if api-path is / (no module)
@ -925,7 +914,7 @@ api_data_put(clicon_handle h,
if (ymoddata != ymodapi){
if (netconf_malformed_message_xml(&xerr, "Data is not prefixed with matching namespace") < 0)
goto done;
if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){
if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
goto done;
}
@ -934,7 +923,6 @@ api_data_put(clicon_handle h,
goto ok;
}
}
#endif /* RESTCONF_NS_DATA_CHECK */
/* Add operation (create/replace) as attribute */
if ((xa = xml_new("operation", xdata, NULL)) == NULL)
@ -965,7 +953,7 @@ api_data_put(clicon_handle h,
if (strcmp(dname, xml_name(xbot))){
if (netconf_operation_failed_xml(&xerr, "protocol", "Not same symbol in api-path as data") < 0)
goto done;
if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){
if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
goto done;
}
@ -990,7 +978,7 @@ api_data_put(clicon_handle h,
if (match_list_keys(ybot, xdata, xbot) < 0){
if (netconf_operation_failed_xml(&xerr, "protocol", "api-path keys do not match data keys") < 0)
goto done;
if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){
if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
goto done;
}
@ -1014,7 +1002,7 @@ api_data_put(clicon_handle h,
if (parbod == NULL || strcmp(parbod, xml_body(xdata))){
if (netconf_operation_failed_xml(&xerr, "protocol", "api-path keys do not match data keys") < 0)
goto done;
if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){
if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
goto done;
}
@ -1053,7 +1041,7 @@ api_data_put(clicon_handle h,
clicon_debug(1, "%s xml: %s api_path:%s",__FUNCTION__, cbuf_get(cbx), api_path);
if (clicon_rpc_netconf(h, cbuf_get(cbx), &xret, NULL) < 0)
goto done;
if ((xe = xpath_first(xret, NULL, "//rpc-error")) != NULL){
if ((xe = xpath_first(xret, "//rpc-error")) != NULL){
if (api_return_err(h, r, xe, pretty, use_xml, 0) < 0)
goto done;
goto ok;
@ -1066,14 +1054,14 @@ api_data_put(clicon_handle h,
cprintf(cbx, "<commit/></rpc>");
if (clicon_rpc_netconf(h, cbuf_get(cbx), &xretcom, NULL) < 0)
goto done;
if ((xe = xpath_first(xretcom, NULL, "//rpc-error")) != NULL){
if ((xe = xpath_first(xretcom, "//rpc-error")) != NULL){
cbuf_reset(cbx);
cprintf(cbx, "<rpc username=\"%s\">", username?username:"");
cprintf(cbx, "<discard-changes/></rpc>");
if (clicon_rpc_netconf(h, cbuf_get(cbx), &xretdis, NULL) < 0)
goto done;
/* log errors from discard, but ignore */
if ((xpath_first(xretdis, NULL, "//rpc-error")) != NULL)
if ((xpath_first(xretdis, "//rpc-error")) != NULL)
clicon_log(LOG_WARNING, "%s: discard-changes failed which may lead candidate in an inconsistent state", __FUNCTION__);
if (api_return_err(h, r, xe, pretty, use_xml, 0) < 0)
goto done;
@ -1096,7 +1084,7 @@ api_data_put(clicon_handle h,
if (clicon_rpc_netconf(h, cbuf_get(cbx), &xretcom, NULL) < 0)
goto done;
/* If copy-config failed, log and ignore (already committed) */
if ((xe = xpath_first(xretcom, NULL, "//rpc-error")) != NULL){
if ((xe = xpath_first(xretcom, "//rpc-error")) != NULL){
clicon_log(LOG_WARNING, "%s: copy-config running->startup failed", __FUNCTION__);
}
@ -1204,7 +1192,7 @@ api_data_delete(clicon_handle h,
if (netconf_malformed_message_xml(&xerr, clicon_err_reason) < 0)
goto done;
clicon_err_reset();
if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){
if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
goto done;
}
@ -1231,7 +1219,7 @@ api_data_delete(clicon_handle h,
cprintf(cbx, "</edit-config></rpc>");
if (clicon_rpc_netconf(h, cbuf_get(cbx), &xret, NULL) < 0)
goto done;
if ((xe = xpath_first(xret, NULL, "//rpc-error")) != NULL){
if ((xe = xpath_first(xret, "//rpc-error")) != NULL){
if (api_return_err(h, r, xe, pretty, use_xml, 0) < 0)
goto done;
goto ok;
@ -1245,14 +1233,14 @@ api_data_delete(clicon_handle h,
cprintf(cbx, "<commit/></rpc>");
if (clicon_rpc_netconf(h, cbuf_get(cbx), &xretcom, NULL) < 0)
goto done;
if ((xe = xpath_first(xretcom, NULL, "//rpc-error")) != NULL){
if ((xe = xpath_first(xretcom, "//rpc-error")) != NULL){
cbuf_reset(cbx);
cprintf(cbx, "<rpc username=\"%s\">", NACM_RECOVERY_USER);
cprintf(cbx, "<discard-changes/></rpc>");
if (clicon_rpc_netconf(h, cbuf_get(cbx), &xretdis, NULL) < 0)
goto done;
/* log errors from discard, but ignore */
if ((xpath_first(xretdis, NULL, "//rpc-error")) != NULL)
if ((xpath_first(xretdis, "//rpc-error")) != NULL)
clicon_log(LOG_WARNING, "%s: discard-changes failed which may lead candidate in an inconsistent state", __FUNCTION__);
if (api_return_err(h, r, xe, pretty, use_xml, 0) < 0)
goto done;
@ -1275,7 +1263,7 @@ api_data_delete(clicon_handle h,
if (clicon_rpc_netconf(h, cbuf_get(cbx), &xretcom, NULL) < 0)
goto done;
/* If copy-config failed, log and ignore (already committed) */
if ((xe = xpath_first(xretcom, NULL, "//rpc-error")) != NULL){
if ((xe = xpath_first(xretcom, "//rpc-error")) != NULL){
clicon_log(LOG_WARNING, "%s: copy-config running->startup failed", __FUNCTION__);
}
@ -1442,7 +1430,7 @@ api_operations_post_input(clicon_handle h,
if (xml_parse_string(data, yspec, &xdata) < 0){
if (netconf_malformed_message_xml(&xerr, clicon_err_reason) < 0)
goto done;
if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){
if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
goto done;
}
@ -1455,7 +1443,7 @@ api_operations_post_input(clicon_handle h,
if ((ret = json_parse_str(data, yspec, &xdata, &xerr)) < 0){
if (netconf_malformed_message_xml(&xerr, clicon_err_reason) < 0)
goto done;
if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){
if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
goto done;
}
@ -1464,7 +1452,7 @@ api_operations_post_input(clicon_handle h,
goto fail;
}
if (ret == 0){
if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){
if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
goto done;
}
@ -1497,7 +1485,7 @@ api_operations_post_input(clicon_handle h,
else
if (netconf_malformed_message_xml(&xerr, "restconf RPC has malformed input statement (multiple or not called input)") < 0)
goto done;
if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){
if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
goto done;
}
@ -1571,7 +1559,7 @@ api_operations_post_output(clicon_handle h,
xml_child_nr_type(xret, CX_ELMNT) != 1){
if (netconf_malformed_message_xml(&xerr, "restconf RPC does not have single input") < 0)
goto done;
if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){
if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
goto done;
}
@ -1608,7 +1596,7 @@ api_operations_post_output(clicon_handle h,
(ret = xml_yang_validate_add(h, xoutput, &xerr)) < 0)
goto done;
if (ret == 0){ /* validation failed */
if ((xe = xpath_first(xerr, NULL, "rpc-reply/rpc-error")) == NULL){
if ((xe = xpath_first(xerr, "rpc-reply/rpc-error")) == NULL){
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
goto done;
}
@ -1741,7 +1729,7 @@ api_operations_post(clicon_handle h,
if (oppath == NULL || strcmp(oppath,"/")==0){
if (netconf_operation_failed_xml(&xerr, "protocol", "Operation name expected") < 0)
goto done;
if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){
if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
goto done;
}
@ -1760,7 +1748,7 @@ api_operations_post(clicon_handle h,
if ((ys = yang_find(yspec, Y_MODULE, prefix)) == NULL){
if (netconf_operation_failed_xml(&xerr, "protocol", "yang module not found") < 0)
goto done;
if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){
if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
goto done;
}
@ -1771,7 +1759,7 @@ api_operations_post(clicon_handle h,
if ((yrpc = yang_find(ys, Y_RPC, id)) == NULL){
if (netconf_missing_element_xml(&xerr, "application", id, "RPC not defined") < 0)
goto done;
if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){
if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
goto done;
}
@ -1800,7 +1788,7 @@ api_operations_post(clicon_handle h,
if (netconf_malformed_message_xml(&xerr, clicon_err_reason) < 0)
goto done;
clicon_err_reset();
if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){
if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
goto done;
}
@ -1840,7 +1828,7 @@ api_operations_post(clicon_handle h,
if ((ret = xml_yang_validate_rpc(h, xtop, &xret)) < 0)
goto done;
if (ret == 0){
if ((xe = xpath_first(xret, NULL, "rpc-error")) == NULL){
if ((xe = xpath_first(xret, "rpc-error")) == NULL){
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
goto ok;
}
@ -1872,7 +1860,7 @@ api_operations_post(clicon_handle h,
if (xml_parse_string(cbuf_get(cbret), NULL, &xret) < 0)
goto done;
/* Local error: return it and quit */
if ((xe = xpath_first(xret, NULL, "rpc-reply/rpc-error")) != NULL){
if ((xe = xpath_first(xret, "rpc-reply/rpc-error")) != NULL){
if (api_return_err(h, r, xe, pretty, use_xml, 0) < 0)
goto done;
goto ok;
@ -1881,7 +1869,7 @@ api_operations_post(clicon_handle h,
else { /* Send to backend */
if (clicon_rpc_netconf_xml(h, xtop, &xret, NULL) < 0)
goto done;
if ((xe = xpath_first(xret, NULL, "rpc-reply/rpc-error")) != NULL){
if ((xe = xpath_first(xret, "rpc-reply/rpc-error")) != NULL){
if (api_return_err(h, r, xe, pretty, use_xml, 0) < 0)
goto done;
goto ok;

View file

@ -187,11 +187,11 @@ restconf_stream_cb(int s,
clicon_err(OE_PLUGIN, errno, "cbuf_new");
goto done;
}
if ((xn = xpath_first(xtop, NULL, "notification")) == NULL)
if ((xn = xpath_first(xtop, "notification")) == NULL)
goto ok;
#ifdef notused
xt = xpath_first(xn, NULL, "eventTime");
if ((xe = xpath_first(xn, NULL, "event")) == NULL) /* event can depend on yang? */
xt = xpath_first(xn, "eventTime");
if ((xe = xpath_first(xn, "event")) == NULL) /* event can depend on yang? */
goto ok;
if (xt)
@ -268,7 +268,7 @@ restconf_stream(clicon_handle h,
cprintf(cb, "</create-subscription></rpc>]]>]]>");
if (clicon_rpc_netconf(h, cbuf_get(cb), &xret, &s) < 0)
goto done;
if ((xe = xpath_first(xret, NULL, "rpc-reply/rpc-error")) != NULL){
if ((xe = xpath_first(xret, "rpc-reply/rpc-error")) != NULL){
if (api_return_err(h, r, xe, pretty, use_xml, 0) < 0)
goto done;
goto ok;
@ -416,7 +416,7 @@ api_stream(clicon_handle h,
else{
if (netconf_access_denied_xml(&xret, "protocol", "The requested URL was unauthorized") < 0)
goto done;
if ((xerr = xpath_first(xret, NULL, "//rpc-error")) != NULL){
if ((xerr = xpath_first(xret, "//rpc-error")) != NULL){
if (api_return_err(h, r, xerr, pretty, use_xml, 0) < 0)
goto done;
goto ok;

View file

@ -480,7 +480,7 @@ You use XPATHs on the XML trees in the transaction commit callback.
Suppose you want to print all added interfaces:
```
cxobj *target = transaction_target(td); # wanted XML tree
vec = xpath_vec_flag(target, "//interface", &len, XML_FLAG_ADD); /* Get added i/fs */
vec = xpath_vec_flag(target, NULL, "//interface", &len, XML_FLAG_ADD); /* Get added i/fs */
for (i=0; i<len; i++) /* Loop over added i/fs */
clicon_xml2file(stdout, vec[i], 0, 1); /* Print the added interface */
```

View file

@ -128,7 +128,7 @@ main_commit(clicon_handle h,
goto done;
/* Get all added i/fs */
if (xpath_vec_flag(target, NULL, "//interface", XML_FLAG_ADD, &vec, &len) < 0)
if (xpath_vec_flag(target, nsc, "//interface", XML_FLAG_ADD, &vec, &len) < 0)
return -1;
if (debug)
for (i=0; i<len; i++) /* Loop over added i/fs */
@ -319,7 +319,7 @@ example_statedata(clicon_handle h,
*/
if ((nsc1 = xml_nsctx_init(NULL, "urn:ietf:params:xml:ns:yang:ietf-interfaces")) == NULL)
goto done;
if (xpath_vec(xt, nsc1, "/interfaces/interface/name", &xvec, &xlen) < 0)
if (xpath_vec_nsc(xt, nsc1, "/interfaces/interface/name", &xvec, &xlen) < 0)
goto done;
if (xlen){
cprintf(cb, "<interfaces xmlns=\"urn:ietf:params:xml:ns:yang:ietf-interfaces\">");
@ -415,7 +415,7 @@ upgrade_2016(clicon_handle h,
if ((name = xml_find_body(xi, "name")) == NULL)
continue; /* shouldnt happen */
/* Get corresponding /interfaces/interface entry */
xif = xpath_first(xt, NULL, "/interfaces/interface[name=\"%s\"]", name);
xif = xpath_first(xt, "/interfaces/interface[name=\"%s\"]", name);
/* - Move /if:interfaces-state/if:interface/if:admin-status to
* /if:interfaces/if:interface/ */
if ((x = xml_find(xi, "admin-status")) != NULL && xif){
@ -518,7 +518,7 @@ upgrade_2018(clicon_handle h,
/* Change type /interfaces/interface/statistics/in-octets to
* decimal64 with fraction-digits 3 and divide values with 1000
*/
if ((x = xpath_first(xi, NULL, "statistics/in-octets")) != NULL){
if ((x = xpath_first(xi, "statistics/in-octets")) != NULL){
if ((xb = xml_body_get(x)) != NULL){
uint64_t u64;
cbuf *cb = cbuf_new();

View file

@ -87,7 +87,7 @@ nacm_validate(clicon_handle h,
if (_transaction_log){
transaction_log(h, td, LOG_NOTICE, __FUNCTION__);
if (_transaction_error_toggle==0 &&
xpath_first(transaction_target(td), NULL, "%s", _transaction_xpath)){
xpath_first(transaction_target(td), "%s", _transaction_xpath)){
_transaction_error_toggle=1; /* toggle if triggered */
clicon_err(OE_XML, 0, "User error");
return -1; /* induce fail */
@ -116,7 +116,7 @@ nacm_commit(clicon_handle h,
if (_transaction_log){
transaction_log(h, td, LOG_NOTICE, __FUNCTION__);
if (_transaction_error_toggle==1 &&
xpath_first(target, NULL, "%s", _transaction_xpath)){
xpath_first(target, "%s", _transaction_xpath)){
_transaction_error_toggle=0; /* toggle if triggered */
clicon_err(OE_XML, 0, "User error");
return -1; /* induce fail */

View file

@ -105,7 +105,7 @@ example_client_rpc(clicon_handle h,
/* Send to backend */
if (clicon_rpc_netconf_xml(h, xrpc, &xret, NULL) < 0)
goto done;
if ((xerr = xpath_first(xret, NULL, "//rpc-error")) != NULL){
if ((xerr = xpath_first(xret, "//rpc-error")) != NULL){
clicon_rpc_generate_error("Get configuration", xerr);
goto done;
}

View file

@ -48,9 +48,3 @@
*/
#define USE_NETCONF_NS_AS_DEFAULT
/* Make namespace check on RESTCONF PUT and POST -d data
* Should be defined according to standard
* Undefine it if you want allow no namespace (pick first name it finds in list
* of loaded modules).
*/
#define RESTCONF_NS_DATA_CHECK

View file

@ -116,20 +116,39 @@ char* xpath_tree_int2str(int nodetype);
int xpath_tree_print(cbuf *cb, xpath_tree *xs);
int xpath_tree_free(xpath_tree *xs);
int xpath_parse(cvec *nsc, char *xpath, xpath_tree **xptree);
int xpath_vec_ctx(cxobj *xcur, cvec *nsc, char *xpath, xp_ctx **xrp);
#if defined(__GNUC__) && __GNUC__ >= 3
cxobj *xpath_first(cxobj *xcur, cvec *nsc, char *format, ...) __attribute__ ((format (printf, 3, 4)));
int xpath_vec(cxobj *xcur, cvec *nsc, char *format, cxobj ***vec, size_t *veclen, ...) __attribute__ ((format (printf, 3, 6)));
int xpath_vec_flag(cxobj *xcur, cvec *nsc, char *format, uint16_t flags,
int xpath_vec_bool(cxobj *xcur, cvec *nsc, char *xpformat, ...) __attribute__ ((format (printf, 3, 4)));
int xpath_vec_flag(cxobj *xcur, cvec *nsc, char *xpformat, uint16_t flags,
cxobj ***vec, size_t *veclen, ...) __attribute__ ((format (printf, 3, 7)));
int xpath_vec_bool(cxobj *xcur, cvec *nsc, char *format, ...) __attribute__ ((format (printf, 3, 4)));
#else
cxobj *xpath_first(cxobj *xcur, cvec *nsc, char *format, ...);
int xpath_vec(cxobj *xcur, cvec *nsc, char *format, cxobj ***vec, size_t *veclen, ...);
int xpath_vec_flag(cxobj *xcur, cvec *nsc, char *format, uint16_t flags,
int xpath_vec_bool(cxobj *xcur, cvec *nsc, char *xpformat, ...);
int xpath_vec_flag(cxobj *xcur, cvec *nsc, char *xpformat, uint16_t flags,
cxobj ***vec, size_t *veclen, ...);
int xpath_vec_bool(cxobj *xcur, cvec *nsc, char *format, ...);
#endif
int xpath_vec_ctx(cxobj *xcur, cvec *nsc, char *xpath, xp_ctx **xrp);
/* Functions with explicit namespace context (nsc) set. If you do not need
* explicit namespace contexts (most do not) consider using the API functions
* below without nsc set.
* If you do not know what a namespace context is, see README.md#xml-and-xpath
*/
#if defined(__GNUC__) && __GNUC__ >= 3
cxobj *xpath_first_nsc(cxobj *xcur, cvec *nsc, char *xpformat, ...) __attribute__ ((format (printf, 3, 4)));
int xpath_vec_nsc(cxobj *xcur, cvec *nsc, char *xpformat, cxobj ***vec, size_t *veclen, ...) __attribute__ ((format (printf, 3, 6)));
#else
cxobj *xpath_first_nsc(cxobj *xcur, cvec *nsc, char *xpformat, ...);
int xpath_vec_nsc(cxobj *xcur, cvec *nsc, char *xpformat, cxobj ***vec, size_t *veclen, ...);
#endif
/* Functions with nsc == NULL (implicit xpath context). */
#if defined(__GNUC__) && __GNUC__ >= 3
cxobj *xpath_first(cxobj *xcur, char *xpformat, ...) __attribute__ ((format (printf, 2, 3)));
int xpath_vec(cxobj *xcur, char *xpformat, cxobj ***vec, size_t *veclen, ...) __attribute__ ((format (printf, 2, 5)));
#else
cxobj *xpath_first(cxobj *xcur, char *xpformat, ...);
int xpath_vec(cxobj *xcur, char *xpformat, cxobj ***vec, size_t *veclen, ...);
#endif
#endif /* _CLIXON_XPATH_H */

View file

@ -258,7 +258,7 @@ text_read_modstate(clicon_handle h,
if ((name = xml_find_body(xm, "name")) == NULL)
continue;
/* 3a) There is no such module in the system */
if ((xs = xpath_first(xmcache, NULL, "module[name=\"%s\"]", name)) == NULL){
if ((xs = xpath_first(xmcache, "module[name=\"%s\"]", name)) == NULL){
// fprintf(stderr, "%s: Module %s: not in system\n", __FUNCTION__, name);
if ((xm2 = xml_dup(xm)) == NULL)
goto done;
@ -420,7 +420,7 @@ xmldb_get_nocache(clicon_handle h,
goto done;
/* Here xt looks like: <config>...</config> */
/* Given the xpath, return a vector of matches in xvec */
if (xpath_vec(xt, nsc, "%s", &xvec, &xlen, xpath?xpath:"/") < 0)
if (xpath_vec_nsc(xt, nsc, "%s", &xvec, &xlen, xpath?xpath:"/") < 0)
goto done;
/* If vectors are specified then mark the nodes found with all ancestors
@ -526,7 +526,7 @@ xmldb_get_cache(clicon_handle h,
*/
/* Here xt looks like: <config>...</config> */
if (xpath_vec(x0t, nsc, "%s", &xvec, &xlen, xpath?xpath:"/") < 0)
if (xpath_vec_nsc(x0t, nsc, "%s", &xvec, &xlen, xpath?xpath:"/") < 0)
goto done;
/* Make new tree by copying top-of-tree from x0t to x1t */
@ -615,7 +615,7 @@ xmldb_get_zerocopy(clicon_handle h,
else
x0t = de->de_xml;
/* Here xt looks like: <config>...</config> */
if (xpath_vec(x0t, nsc, "%s", &xvec, &xlen, xpath?xpath:"/") < 0)
if (xpath_vec_nsc(x0t, nsc, "%s", &xvec, &xlen, xpath?xpath:"/") < 0)
goto done;
/* Iterate through the match vector
* For every node found in x0, mark the tree up to t1

View file

@ -662,7 +662,7 @@ xmldb_put(clicon_handle h,
if ((nsc = xml_nsctx_init(NULL, "urn:ietf:params:xml:ns:yang:ietf-netconf-acm")) == NULL)
goto done;
if (xnacm0 != NULL &&
(xnacm = xpath_first(xnacm0, nsc, "nacm")) != NULL){
(xnacm = xpath_first_nsc(xnacm0, nsc, "nacm")) != NULL){
/* Pre-NACM access step, if permit, then dont do any nacm checks in
* text_modify_* below */
if ((permit = nacm_access(mode, xnacm, username)) < 0)

View file

@ -214,7 +214,7 @@ nacm_rpc(char *rpc,
goto step10;
/* User's group */
if (xpath_vec(xnacm, nsc, "groups/group[user-name='%s']", &gvec, &glen, username) < 0)
if (xpath_vec_nsc(xnacm, nsc, "groups/group[user-name='%s']", &gvec, &glen, username) < 0)
goto done;
/* 5. If no groups are found, continue with step 10. */
if (glen == 0)
@ -223,14 +223,14 @@ nacm_rpc(char *rpc,
configuration. If a rule-list's "group" leaf-list does not
match any of the user's groups, proceed to the next rule-list
entry. */
if (xpath_vec(xnacm, nsc, "rule-list", &rlistvec, &rlistlen) < 0)
if (xpath_vec_nsc(xnacm, nsc, "rule-list", &rlistvec, &rlistlen) < 0)
goto done;
for (i=0; i<rlistlen; i++){
rlist = rlistvec[i];
/* Loop through user's group to find match in this rule-list */
for (j=0; j<glen; j++){
gname = xml_find_body(gvec[j], "name");
if (xpath_first(rlist, nsc, ".[group='%s']", gname)!=NULL)
if (xpath_first_nsc(rlist, nsc, ".[group='%s']", gname)!=NULL)
break; /* found */
}
if (j==glen) /* not found */
@ -239,7 +239,7 @@ nacm_rpc(char *rpc,
until a rule that matches the requested access operation is
found.
*/
if (xpath_vec(rlist, nsc, "rule", &rvec, &rlen) < 0)
if (xpath_vec_nsc(rlist, nsc, "rule", &rvec, &rlen) < 0)
goto done;
for (j=0; j<rlen; j++){
xrule = rvec[j];
@ -390,7 +390,7 @@ nacm_rule_datanode(cxobj *xt,
}
/* Here module is matched, now check for path if any NYI */
if (path){
if ((xpath = xpath_first(xt, nsc, "%s", path)) == NULL)
if ((xpath = xpath_first_nsc(xt, nsc, "%s", path)) == NULL)
goto nomatch;
/* The requested node xr is the node specified by the path or is a
* descendant node of the path:
@ -447,7 +447,7 @@ nacm_data_read_xr(cxobj *xt,
/* Loop through user's group to find match in this rule-list */
for (j=0; j<glen; j++){
gname = xml_find_body(gvec[j], "name");
if (xpath_first(rlist, nsc, ".[group='%s']", gname)!=NULL)
if (xpath_first_nsc(rlist, nsc, ".[group='%s']", gname)!=NULL)
break; /* found */
}
if (j==glen) /* not found */
@ -456,7 +456,7 @@ nacm_data_read_xr(cxobj *xt,
until a rule that matches the requested access operation is
found. (see 6 sub rules in nacm_rule_datanode
*/
if (xpath_vec(rlist, nsc, "rule", &rvec, &rlen) < 0)
if (xpath_vec_nsc(rlist, nsc, "rule", &rvec, &rlen) < 0)
goto done;
for (j=0; j<rlen; j++){ /* Loop through rules */
xrule = rvec[j];
@ -588,7 +588,7 @@ nacm_datanode_read(cxobj *xt,
if (username == NULL)
goto step9;
/* User's group */
if (xpath_vec(xnacm, nsc, "groups/group[user-name='%s']", &gvec, &glen, username) < 0)
if (xpath_vec_nsc(xnacm, nsc, "groups/group[user-name='%s']", &gvec, &glen, username) < 0)
goto done;
/* 4. If no groups are found (glen=0), continue and check read-default
in step 11. */
@ -596,7 +596,7 @@ nacm_datanode_read(cxobj *xt,
configuration. If a rule-list's "group" leaf-list does not
match any of the user's groups, proceed to the next rule-list
entry. */
if (xpath_vec(xnacm, nsc, "rule-list", &rlistvec, &rlistlen) < 0)
if (xpath_vec_nsc(xnacm, nsc, "rule-list", &rlistvec, &rlistlen) < 0)
goto done;
/* read-default has default permit so should never be NULL */
if ((read_default = xml_find_body(xnacm, "read-default")) == NULL){
@ -713,7 +713,7 @@ nacm_datanode_write(cxobj *xt,
if (username == NULL)
goto step9;
/* User's group */
if (xpath_vec(xnacm, nsc, "groups/group[user-name='%s']", &gvec, &glen, username) < 0)
if (xpath_vec_nsc(xnacm, nsc, "groups/group[user-name='%s']", &gvec, &glen, username) < 0)
goto done;
/* 4. If no groups are found, continue with step 9. */
if (glen == 0)
@ -722,19 +722,19 @@ nacm_datanode_write(cxobj *xt,
configuration. If a rule-list's "group" leaf-list does not
match any of the user's groups, proceed to the next rule-list
entry. */
if (xpath_vec(xnacm, nsc, "rule-list", &rlistvec, &rlistlen) < 0)
if (xpath_vec_nsc(xnacm, nsc, "rule-list", &rlistvec, &rlistlen) < 0)
goto done;
for (i=0; i<rlistlen; i++){
rlist = rlistvec[i];
/* Loop through user's group to find match in this rule-list */
for (j=0; j<glen; j++){
gname = xml_find_body(gvec[j], "name");
if (xpath_first(rlist, nsc, ".[group='%s']", gname)!=NULL)
if (xpath_first_nsc(rlist, nsc, ".[group='%s']", gname)!=NULL)
break; /* found */
}
if (j==glen) /* not found */
continue;
if (xpath_vec(rlist, nsc, "rule", &rvec, &rlen) < 0)
if (xpath_vec_nsc(rlist, nsc, "rule", &rvec, &rlen) < 0)
goto done;
/* 6. For each rule-list entry found, process all rules, in order,
until a rule that matches the requested access operation is
@ -862,7 +862,7 @@ nacm_access(char *mode,
* RFC8341 3.4 */
/* 1. If the "enable-nacm" leaf is set to "false", then the protocol
operation is permitted. */
if ((x = xpath_first(xnacm, nsc, "enable-nacm")) == NULL)
if ((x = xpath_first_nsc(xnacm, nsc, "enable-nacm")) == NULL)
goto permit;
enabled = xml_body(x);
if (strcmp(enabled, "true") != 0)
@ -937,7 +937,7 @@ nacm_access_pre(clicon_handle h,
if (xnacm0 == NULL)
goto permit;
/* If config does not exist then the operation is permitted(?) */
if ((xnacm = xpath_first(xnacm0, nsc, "nacm")) == NULL)
if ((xnacm = xpath_first_nsc(xnacm0, nsc, "nacm")) == NULL)
goto permit;
if (xml_rootchild_node(xnacm0, xnacm) < 0)
goto done;

View file

@ -1303,13 +1303,13 @@ netconf_err2cb(cxobj *xerr,
clicon_err(OE_XML, errno, "cbuf_new");
goto done;
}
if ((x=xpath_first(xerr, NULL, "error-type"))!=NULL)
if ((x=xpath_first(xerr, "error-type"))!=NULL)
cprintf(cb, "%s ", xml_body(x));
if ((x=xpath_first(xerr, NULL, "error-tag"))!=NULL)
if ((x=xpath_first(xerr, "error-tag"))!=NULL)
cprintf(cb, "%s ", xml_body(x));
if ((x=xpath_first(xerr, NULL, "error-message"))!=NULL)
if ((x=xpath_first(xerr, "error-message"))!=NULL)
cprintf(cb, "%s ", xml_body(x));
if ((x=xpath_first(xerr, NULL, "error-info"))!=NULL)
if ((x=xpath_first(xerr, "error-info"))!=NULL)
clicon_xml2cbuf(cb, xml_child_i(x,0), 0, 0);
*cberr = cb;
retval = 0;

View file

@ -201,8 +201,8 @@ parse_configfile(clicon_handle h,
/* Hard-coded config for < 3.10 and clixon-config for >= 3.10 */
if ((nsc = xml_nsctx_init(NULL, CLIXON_CONF_NS)) == NULL)
goto done;
if ((xc = xpath_first(xt, nsc, "clixon-config")) == NULL){
clicon_err(OE_CFG, 0, "Config file %s: Lacks top-level \"clixon-config\" element\nClixon config files should begin with: <clixon-config xmlns=\"%s\" (See Changelog in Clixon 3.10)>", filename, CLIXON_CONF_NS);
if ((xc = xpath_first_nsc(xt, nsc, "clixon-config")) == NULL){
clicon_err(OE_CFG, 0, "Config file %s: Lacks top-level \"clixon-config\" element\nClixon config files should begin with: <clixon-config xmlns=\"%s\">", filename, CLIXON_CONF_NS);
goto done;
}
@ -362,7 +362,6 @@ clicon_options_main(clicon_handle h,
goto done;
if (xml_spec(xconfig) == NULL){
clicon_err(OE_CFG, 0, "Config file %s: did not find corresponding Yang specification\nHint: File does not begin with: <clixon-config xmlns=\"%s\"> or clixon-config.yang not found?", configfile, CLIXON_CONF_NS);
goto done;
}
/* Set clixon_conf pointer to handle */

View file

@ -262,7 +262,7 @@ clicon_rpc_generate_error(char *prefix,
* cxobj *xt = NULL;
* if (clicon_rpc_get_config(h, "running", "/hello/world", "urn:example:hello", &xt) < 0)
* err;
* if ((xerr = xpath_first(xt, NULL, "/rpc-error")) != NULL){
* if ((xerr = xpath_first(xt, "/rpc-error")) != NULL){
* clicon_rpc_generate_error("", xerr);
* err;
* }
@ -306,9 +306,9 @@ clicon_rpc_get_config(clicon_handle h,
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, NULL, "/rpc-reply/rpc-error")) != NULL)
if ((xd = xpath_first(xret, "/rpc-reply/rpc-error")) != NULL)
xd = xml_parent(xd); /* point to rpc-reply */
else if ((xd = xpath_first(xret, NULL, "/rpc-reply/data")) == NULL)
else if ((xd = xpath_first(xret, "/rpc-reply/data")) == NULL)
if ((xd = xml_new("data", NULL, NULL)) == NULL)
goto done;
if (xt){
@ -369,7 +369,7 @@ clicon_rpc_edit_config(clicon_handle h,
goto done;
if (clicon_rpc_msg(h, msg, &xret, NULL) < 0)
goto done;
if ((xerr = xpath_first(xret, NULL, "//rpc-error")) != NULL){
if ((xerr = xpath_first(xret, "//rpc-error")) != NULL){
clicon_rpc_generate_error("Editing configuration", xerr);
goto done;
}
@ -415,7 +415,7 @@ clicon_rpc_copy_config(clicon_handle h,
goto done;
if (clicon_rpc_msg(h, msg, &xret, NULL) < 0)
goto done;
if ((xerr = xpath_first(xret, NULL, "//rpc-error")) != NULL){
if ((xerr = xpath_first(xret, "//rpc-error")) != NULL){
clicon_rpc_generate_error("Copying configuration", xerr);
goto done;
}
@ -454,7 +454,7 @@ clicon_rpc_delete_config(clicon_handle h,
goto done;
if (clicon_rpc_msg(h, msg, &xret, NULL) < 0)
goto done;
if ((xerr = xpath_first(xret, NULL, "//rpc-error")) != NULL){
if ((xerr = xpath_first(xret, "//rpc-error")) != NULL){
clicon_rpc_generate_error("Deleting configuration", xerr);
goto done;
}
@ -489,7 +489,7 @@ clicon_rpc_lock(clicon_handle h,
goto done;
if (clicon_rpc_msg(h, msg, &xret, NULL) < 0)
goto done;
if ((xerr = xpath_first(xret, NULL, "//rpc-error")) != NULL){
if ((xerr = xpath_first(xret, "//rpc-error")) != NULL){
clicon_rpc_generate_error("Locking configuration", xerr);
goto done;
}
@ -523,7 +523,7 @@ clicon_rpc_unlock(clicon_handle h,
goto done;
if (clicon_rpc_msg(h, msg, &xret, NULL) < 0)
goto done;
if ((xerr = xpath_first(xret, NULL, "//rpc-error")) != NULL){
if ((xerr = xpath_first(xret, "//rpc-error")) != NULL){
clicon_rpc_generate_error("Configuration unlock", xerr);
goto done;
}
@ -550,7 +550,7 @@ clicon_rpc_unlock(clicon_handle h,
* cxobj *xt = NULL;
* if (clicon_rpc_get(h, "/hello/world", "urn:example:hello", &xt) < 0)
* err;
* if ((xerr = xpath_first(xt, NULL, "/rpc-error")) != NULL){
* if ((xerr = xpath_first(xt, "/rpc-error")) != NULL){
* clicon_rpc_generate_error(xerr);
* err;
* }
@ -593,9 +593,9 @@ clicon_rpc_get(clicon_handle h,
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, NULL, "/rpc-reply/rpc-error")) != NULL)
if ((xd = xpath_first(xret, "/rpc-reply/rpc-error")) != NULL)
xd = xml_parent(xd); /* point to rpc-reply */
else if ((xd = xpath_first(xret, NULL, "/rpc-reply/data")) == NULL)
else if ((xd = xpath_first(xret, "/rpc-reply/data")) == NULL)
if ((xd = xml_new("data", NULL, NULL)) == NULL)
goto done;
if (xt){
@ -634,7 +634,7 @@ clicon_rpc_close_session(clicon_handle h)
goto done;
if (clicon_rpc_msg(h, msg, &xret, NULL) < 0)
goto done;
if ((xerr = xpath_first(xret, NULL, "//rpc-error")) != NULL){
if ((xerr = xpath_first(xret, "//rpc-error")) != NULL){
clicon_rpc_generate_error("Close session", xerr);
goto done;
}
@ -669,7 +669,7 @@ clicon_rpc_kill_session(clicon_handle h,
goto done;
if (clicon_rpc_msg(h, msg, &xret, NULL) < 0)
goto done;
if ((xerr = xpath_first(xret, NULL, "//rpc-error")) != NULL){
if ((xerr = xpath_first(xret, "//rpc-error")) != NULL){
clicon_rpc_generate_error("Kill session", xerr);
goto done;
}
@ -703,7 +703,7 @@ clicon_rpc_validate(clicon_handle h,
goto done;
if (clicon_rpc_msg(h, msg, &xret, NULL) < 0)
goto done;
if ((xerr = xpath_first(xret, NULL, "//rpc-error")) != NULL){
if ((xerr = xpath_first(xret, "//rpc-error")) != NULL){
clicon_rpc_generate_error(CLIXON_ERRSTR_VALIDATE_FAILED, xerr);
goto done;
}
@ -735,7 +735,7 @@ clicon_rpc_commit(clicon_handle h)
goto done;
if (clicon_rpc_msg(h, msg, &xret, NULL) < 0)
goto done;
if ((xerr = xpath_first(xret, NULL, "//rpc-error")) != NULL){
if ((xerr = xpath_first(xret, "//rpc-error")) != NULL){
clicon_rpc_generate_error(CLIXON_ERRSTR_COMMIT_FAILED, xerr);
goto done;
}
@ -767,7 +767,7 @@ clicon_rpc_discard_changes(clicon_handle h)
goto done;
if (clicon_rpc_msg(h, msg, &xret, NULL) < 0)
goto done;
if ((xerr = xpath_first(xret, NULL, "//rpc-error")) != NULL){
if ((xerr = xpath_first(xret, "//rpc-error")) != NULL){
clicon_rpc_generate_error("Discard changes", xerr);
goto done;
}
@ -812,7 +812,7 @@ clicon_rpc_create_subscription(clicon_handle h,
goto done;
if (clicon_rpc_msg(h, msg, &xret, s0) < 0)
goto done;
if ((xerr = xpath_first(xret, NULL, "//rpc-error")) != NULL){
if ((xerr = xpath_first(xret, "//rpc-error")) != NULL){
clicon_rpc_generate_error("Create subscription", xerr);
goto done;
}
@ -847,11 +847,11 @@ clicon_rpc_debug(clicon_handle h,
goto done;
if (clicon_rpc_msg(h, msg, &xret, NULL) < 0)
goto done;
if ((xerr = xpath_first(xret, NULL, "//rpc-error")) != NULL){
if ((xerr = xpath_first(xret, "//rpc-error")) != NULL){
clicon_rpc_generate_error("Debug",xerr);
goto done;
}
if (xpath_first(xret, NULL, "//rpc-reply/ok") == NULL){
if (xpath_first(xret, "//rpc-reply/ok") == NULL){
clicon_err(OE_XML, 0, "rpc error"); /* XXX extract info from rpc-error */
goto done;
}

View file

@ -514,7 +514,7 @@ stream_notify1(clicon_handle h,
else{ /* xpath match */
if (ss->ss_xpath == NULL ||
strlen(ss->ss_xpath)==0 ||
xpath_first(xevent, NULL, "%s", ss->ss_xpath) != NULL)
xpath_first(xevent, "%s", ss->ss_xpath) != NULL)
if ((*ss->ss_fn)(h, 0, xevent, ss->ss_arg) < 0)
goto done;
ss = NEXTQ(struct stream_subscription *, ss);

View file

@ -200,7 +200,7 @@ changelog_move(clicon_handle h,
int retval = -1;
cxobj *xp; /* destination parent node */
if ((xp = xpath_first(xt, nsc, "%s", dst)) == NULL){
if ((xp = xpath_first_nsc(xt, nsc, "%s", dst)) == NULL){
clicon_err(OE_XML, 0, "path required");
goto done;
}
@ -253,7 +253,7 @@ changelog_op(clicon_handle h,
if ((wxpath = xml_find_body(xi, "where")) == NULL)
goto ok;
/* Get vector of target nodes meeting the where requirement */
if (xpath_vec(xt, nsc, "%s", &wvec, &wlen, wxpath) < 0)
if (xpath_vec_nsc(xt, nsc, "%s", &wvec, &wlen, wxpath) < 0)
goto done;
for (i=0; i<wlen; i++){
xw = wvec[i];
@ -328,7 +328,7 @@ changelog_iterate(clicon_handle h,
int ret;
int i;
if (xpath_vec(xch, NULL, "step", &vec, &veclen) < 0)
if (xpath_vec(xch, "step", &vec, &veclen) < 0)
goto done;
/* Iterate through changelog items */
for (i=0; i<veclen; i++){
@ -392,7 +392,7 @@ xml_changelog_upgrade(clicon_handle h,
* - find all changelogs in the interval: [from, to]
* - note it t=0 then no changelog is applied
*/
if (xpath_vec(xchlog, NULL, "changelog[namespace=\"%s\"]",
if (xpath_vec(xchlog, "changelog[namespace=\"%s\"]",
&vec, &veclen, namespace) < 0)
goto done;
/* Get all changelogs in the interval [from,to]*/

View file

@ -287,7 +287,7 @@ validate_leafref(cxobj *xt,
/* XXX see comment above regarding typeref or not */
if (xml_nsctx_yang(ytype, &nsc) < 0)
goto done;
if (xpath_vec(xt, nsc, "%s", &xvec, &xlen, yang_argument_get(ypath)) < 0)
if (xpath_vec_nsc(xt, nsc, "%s", &xvec, &xlen, yang_argument_get(ypath)) < 0)
goto done;
for (i = 0; i < xlen; i++) {
x = xvec[i];
@ -2781,7 +2781,7 @@ xml2xpath(cxobj *x,
xt = xml_parent(xt);
xcp = xml_parent(xt);
xml_parent_set(xt, NULL);
x2 = xpath_first(xt, NULL, "%s", xpath); /* +1: skip first / */
x2 = xpath_first(xt, "%s", xpath); /* +1: skip first / */
xml_parent_set(xt, xcp);
assert(x2 && x==x2);
if (x==x2)

View file

@ -183,17 +183,17 @@ xpath_tree_free(xpath_tree *xs)
/*! Given XML tree and xpath, parse xpath, eval it and return xpath context,
* This is a raw form of xpath where you can do type conversion, etc,
* not just a nodeset.
* @param[in] nsc XML Namespace context
* @param[in] nsc External XML namespace context, or NULL
* @param[in] xpath String with XPATH 1.0 syntax
* @param[out] xptree Xpath-tree, parsed, structured XPATH, free:xpath_tree_free
* @retval 0 OK
* @retval -1 Error
* @code
* xp_ctx *xc = NULL;
* if (xpath_vec_ctx(x, NULL, xpath, &xc) < 0)
* xpath_tree *xpt = NULL;
* if (xpath_parse(NULL, xpath, &xpt) < 0)
* err;
* if (xc)
* ctx_free(xc);
* if (xpt)
* xptree_free(xpt);
* @endcode
* @see xpath_tree_free
*/
@ -238,7 +238,7 @@ xpath_parse(cvec *nsc,
* This is a raw form of xpath where you can do type conversion of the return
* value, etc, not just a nodeset.
* @param[in] xcur XML-tree where to search
* @param[in] nsc XML Namespace context
* @param[in] nsc External XML namespace context, or NULL
* @param[in] xpath String with XPATH 1.0 syntax
* @param[out] xrp Return XPATH context
* @retval 0 OK
@ -278,35 +278,33 @@ xpath_vec_ctx(cxobj *xcur,
done:
if (xptree)
xpath_tree_free(xptree);
return retval;
}
/*! Xpath nodeset function where only the first matching entry is returned
* args:
*
* @param[in] xcur XML tree where to search
* @param[in] nsc XML Namespace context
* @param[in] format string with XPATH syntax
* @param[in] nsc External XML namespace context, or NULL
* @param[in] xpformat Format string for XPATH syntax
* @retval xml-tree XML tree of first match
* @retval NULL Error or not found
*
* @code
* cxobj *x;
* cvec *nsc; // namespace context
* if ((x = xpath_first(xtop, nsc, "//symbol/foo")) != NULL) {
* if ((x = xpath_first_nsc(xtop, nsc, "//symbol/foo")) != NULL) {
* ...
* }
* @endcode
* @note the returned pointer points into the original tree so should not be freed fter use.
* @note the returned pointer points into the original tree so should not be freed after use.
* @note return value does not see difference between error and not found
* @see also xpath_vec.
* @experimental
*/
cxobj *
xpath_first(cxobj *xcur,
cvec *nsc,
char *format,
...)
xpath_first_nsc(cxobj *xcur,
cvec *nsc,
char *xpformat,
...)
{
cxobj *cx = NULL;
va_list ap;
@ -314,8 +312,8 @@ xpath_first(cxobj *xcur,
char *xpath = NULL;
xp_ctx *xr = NULL;
va_start(ap, format);
len = vsnprintf(NULL, 0, format, ap);
va_start(ap, xpformat);
len = vsnprintf(NULL, 0, xpformat, ap);
va_end(ap);
/* allocate a message string exactly fitting the message length */
if ((xpath = malloc(len+1)) == NULL){
@ -323,8 +321,8 @@ xpath_first(cxobj *xcur,
goto done;
}
/* second round: compute write message from reason and args */
va_start(ap, format);
if (vsnprintf(xpath, len+1, format, ap) < 0){
va_start(ap, xpformat);
if (vsnprintf(xpath, len+1, xpformat, ap) < 0){
clicon_err(OE_UNIX, errno, "vsnprintf");
va_end(ap);
goto done;
@ -342,20 +340,77 @@ xpath_first(cxobj *xcur,
return cx;
}
/*! Xpath nodeset function where only the first matching entry is returned
*
* @param[in] xcur XML tree where to search
* @param[in] xpformat Format string for XPATH syntax
* @retval xml-tree XML tree of first match
* @retval NULL Error or not found
*
* @code
* cxobj *x;
* if ((x = xpath_first(xtop, "//symbol/foo")) != NULL) {
* ...
* }
* @endcode
* @note the returned pointer points into the original tree so should not be freed after use.
* @note return value does not see difference between error and not found
* @see also xpath_vec.
* @see xpath_first_nsc which is more generic with namespace context
*/
cxobj *
xpath_first(cxobj *xcur,
char *xpformat,
...)
{
cxobj *cx = NULL;
va_list ap;
size_t len;
char *xpath = NULL;
xp_ctx *xr = NULL;
va_start(ap, xpformat);
len = vsnprintf(NULL, 0, xpformat, ap);
va_end(ap);
/* allocate a message string exactly fitting the message length */
if ((xpath = malloc(len+1)) == NULL){
clicon_err(OE_UNIX, errno, "malloc");
goto done;
}
/* second round: compute write message from reason and args */
va_start(ap, xpformat);
if (vsnprintf(xpath, len+1, xpformat, ap) < 0){
clicon_err(OE_UNIX, errno, "vsnprintf");
va_end(ap);
goto done;
}
va_end(ap);
if (xpath_vec_ctx(xcur, NULL, xpath, &xr) < 0)
goto done;
if (xr && xr->xc_type == XT_NODESET && xr->xc_size)
cx = xr->xc_nodeset[0];
done:
if (xr)
ctx_free(xr);
if (xpath)
free(xpath);
return cx;
}
/*! Given XML tree and xpath, returns nodeset as xml node vector
* If result is not nodeset, return empty nodeset
* @param[in] xcur xml-tree where to search
* @param[in] format stdarg string with XPATH 1.0 syntax
* @param[in] nsc XML Namespace context for XPATH
* @param[out] vec vector of xml-trees. Vector must be free():d after use
* @param[out] veclen returns length of vector in return value
* @retval 0 OK
* @retval -1 Error
* @param[in] xcur xml-tree where to search
* @param[in] nsc External XML namespace context, or NULL
* @param[in] xpformat Format string for XPATH syntax
* @param[out] vec vector of xml-trees. Vector must be free():d after use
* @param[out] veclen returns length of vector in return value
* @retval 0 OK
* @retval -1 Error
* @code
* cvec *nsc; // namespace context
* cxobj **vec;
* size_t veclen;
* if (xpath_vec(xcur, nsc, "//symbol/foo", &vec, &veclen) < 0)
* if (xpath_vec_nsc(xcur, nsc, "//symbol/foo", &vec, &veclen) < 0)
* goto err;
* for (i=0; i<veclen; i++){
* xn = vec[i];
@ -363,15 +418,14 @@ xpath_first(cxobj *xcur,
* }
* free(vec);
* @endcode
* @note Namespace prefix checking is not properly implemented
*/
int
xpath_vec(cxobj *xcur,
cvec *nsc,
char *format,
cxobj ***vec,
size_t *veclen,
...)
xpath_vec_nsc(cxobj *xcur,
cvec *nsc,
char *xpformat,
cxobj ***vec,
size_t *veclen,
...)
{
int retval = -1;
va_list ap;
@ -380,7 +434,7 @@ xpath_vec(cxobj *xcur,
xp_ctx *xr = NULL;
va_start(ap, veclen);
len = vsnprintf(NULL, 0, format, ap);
len = vsnprintf(NULL, 0, xpformat, ap);
va_end(ap);
/* allocate a message string exactly fitting the message length */
if ((xpath = malloc(len+1)) == NULL){
@ -389,7 +443,7 @@ xpath_vec(cxobj *xcur,
}
/* second round: compute write message from reason and args */
va_start(ap, veclen);
if (vsnprintf(xpath, len+1, format, ap) < 0){
if (vsnprintf(xpath, len+1, xpformat, ap) < 0){
clicon_err(OE_UNIX, errno, "vsnprintf");
va_end(ap);
goto done;
@ -413,15 +467,83 @@ xpath_vec(cxobj *xcur,
return retval;
}
/*! Given XML tree and xpath, returns nodeset as xml node vector
* If result is not nodeset, return empty nodeset
* @param[in] xcur xml-tree where to search
* @param[in] xpformat Format string for XPATH syntax
* @param[out] vec vector of xml-trees. Vector must be free():d after use
* @param[out] veclen returns length of vector in return value
* @retval 0 OK
* @retval -1 Error
* @code
* cxobj **vec;
* size_t veclen;
* if (xpath_vec(xcur, "//symbol/foo", &vec, &veclen) < 0)
* goto err;
* for (i=0; i<veclen; i++){
* xn = vec[i];
* ...
* }
* free(vec);
* @endcode
* @see xpath_vec_nsc which is more generic with namespace context
*/
int
xpath_vec(cxobj *xcur,
char *xpformat,
cxobj ***vec,
size_t *veclen,
...)
{
int retval = -1;
va_list ap;
size_t len;
char *xpath = NULL;
xp_ctx *xr = NULL;
va_start(ap, veclen);
len = vsnprintf(NULL, 0, xpformat, ap);
va_end(ap);
/* allocate a message string exactly fitting the message length */
if ((xpath = malloc(len+1)) == NULL){
clicon_err(OE_UNIX, errno, "malloc");
goto done;
}
/* second round: compute write message from reason and args */
va_start(ap, veclen);
if (vsnprintf(xpath, len+1, xpformat, ap) < 0){
clicon_err(OE_UNIX, errno, "vsnprintf");
va_end(ap);
goto done;
}
va_end(ap);
*vec=NULL;
*veclen = 0;
if (xpath_vec_ctx(xcur, NULL, xpath, &xr) < 0)
goto done;
if (xr && xr->xc_type == XT_NODESET){
*vec = xr->xc_nodeset;
xr->xc_nodeset = NULL;
*veclen = xr->xc_size;
}
retval = 0;
done:
if (xr)
ctx_free(xr);
if (xpath)
free(xpath);
return retval;
}
/* Xpath that returns a vector of matches (only nodes marked with flags)
* @param[in] xcur xml-tree where to search
* @param[in] xpath string with XPATH syntax
* @param[in] nsc External XML namespace context, or NULL
* @param[in] flags Set of flags that return nodes must match (0 if all)
* @param[out] vec vector of xml-trees. Vector must be free():d after use
* @param[out] veclen returns length of vector in return value
* @retval 0 OK
* @retval -1 error.
* @param[in] xcur xml-tree where to search
* @param[in] xpformat Format string for XPATH syntax
* @param[in] nsc External XML namespace context, or NULL
* @param[in] flags Set of flags that return nodes must match (0 if all)
* @param[out] vec vector of xml-trees. Vector must be free():d after use
* @param[out] veclen returns length of vector in return value
* @retval 0 OK
* @retval -1 error.
* @code
* cxobj **vec;
* size_t veclen;
@ -434,14 +556,13 @@ xpath_vec(cxobj *xcur,
* }
* free(vec);
* @endcode
* @Note that although the returned vector must be freed after use, the returned xml
* trees need not be.
* @see also xpath_vec This is a specialized version.
* @Note that although the returned vector must be freed after use, the returned xml trees need not be.
* @see also xpath_vec This is a specialized version.
*/
int
xpath_vec_flag(cxobj *xcur,
cvec *nsc,
char *format,
char *xpformat,
uint16_t flags,
cxobj ***vec,
size_t *veclen,
@ -456,7 +577,7 @@ xpath_vec_flag(cxobj *xcur,
cxobj *x;
va_start(ap, veclen);
len = vsnprintf(NULL, 0, format, ap);
len = vsnprintf(NULL, 0, xpformat, ap);
va_end(ap);
/* allocate a message string exactly fitting the message length */
if ((xpath = malloc(len+1)) == NULL){
@ -465,7 +586,7 @@ xpath_vec_flag(cxobj *xcur,
}
/* second round: compute write message from reason and args */
va_start(ap, veclen);
if (vsnprintf(xpath, len+1, format, ap) < 0){
if (vsnprintf(xpath, len+1, xpformat, ap) < 0){
clicon_err(OE_UNIX, errno, "vsnprintf");
va_end(ap);
goto done;
@ -494,17 +615,17 @@ xpath_vec_flag(cxobj *xcur,
/*! Given XML tree and xpath, returns boolean
* Returns true if the nodeset is non-empty
* @param[in] xcur xml-tree where to search
* @param[in] nsc External XML namespace context, or NULL
* @param[in] xpath stdarg string with XPATH 1.0 syntax
* @retval 1 True
* @retval 0 False
* @retval -1 Error
* @param[in] xcur xml-tree where to search
* @param[in] nsc External XML namespace context, or NULL
* @param[in] xpformat Format string for XPATH syntax
* @retval 1 True
* @retval 0 False
* @retval -1 Error
*/
int
xpath_vec_bool(cxobj *xcur,
cvec *nsc,
char *format,
char *xpformat,
...)
{
int retval = -1;
@ -513,8 +634,8 @@ xpath_vec_bool(cxobj *xcur,
char *xpath = NULL;
xp_ctx *xr = NULL;
va_start(ap, format);
len = vsnprintf(NULL, 0, format, ap);
va_start(ap, xpformat);
len = vsnprintf(NULL, 0, xpformat, ap);
va_end(ap);
/* allocate a message string exactly fitting the message length */
if ((xpath = malloc(len+1)) == NULL){
@ -522,8 +643,8 @@ xpath_vec_bool(cxobj *xcur,
goto done;
}
/* second round: compute write message from reason and args */
va_start(ap, format);
if (vsnprintf(xpath, len+1, format, ap) < 0){
va_start(ap, xpformat);
if (vsnprintf(xpath, len+1, xpformat, ap) < 0){
clicon_err(OE_UNIX, errno, "vsnprintf");
va_end(ap);
goto done;

View file

@ -305,7 +305,7 @@ yang_modules_state_get(clicon_handle h,
/* xc is also original tree, need to copy it */
if ((xw = xml_wrap(xc, "top")) == NULL)
goto done;
if (xpath_first(xw, NULL, "%s", xpath)){
if (xpath_first(xw, "%s", xpath)){
if ((x = xml_dup(xc)) == NULL) /* Make copy and use below */
goto done;
}
@ -337,7 +337,7 @@ yang_modules_state_get(clicon_handle h,
if ((x = xml_wrap(x, "top")) < 0)
goto done;
/* extract xpath part of module-state tree */
if (xpath_vec(x, nsc, "%s", &xvec, &xlen, xpath?xpath:"/") < 0)
if (xpath_vec_nsc(x, nsc, "%s", &xvec, &xlen, xpath?xpath:"/") < 0)
goto done;
if (xvec != NULL){
for (i=0; i<xlen; i++)

View file

@ -154,7 +154,7 @@ main(int argc, char **argv)
}
if (xml_apply(x0, CX_ELMNT, xml_spec_populate, yspec) < 0)
goto done;
if ((xb = xpath_first(x0, NULL, "%s", xpath)) == NULL){
if ((xb = xpath_first(x0, "%s", xpath)) == NULL){
clicon_err(OE_XML, 0, "xpath: %s not found in x0", xpath);
goto done;
}
@ -169,7 +169,7 @@ main(int argc, char **argv)
}
if (xml_apply(xi, CX_ELMNT, xml_spec_populate, yspec) < 0)
goto done;
if ((xi = xpath_first(xi, NULL, "%s", xpath)) == NULL){
if ((xi = xpath_first(xi, "%s", xpath)) == NULL){
clicon_err(OE_XML, 0, "xpath: %s not found in xi", xpath);
goto done;
}

View file

@ -194,7 +194,7 @@ main(int argc, char **argv)
/* If xpath0 given, position current x */
if (xpath0){
if ((x = xpath_first(x0, NULL, "%s", xpath0)) == NULL){
if ((x = xpath_first(x0, "%s", xpath0)) == NULL){
fprintf(stderr, "Error: xpath0 returned NULL\n");
return -1;
}