diff --git a/CHANGELOG.md b/CHANGELOG.md
index 8044c3b2..8622973c 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,6 +7,9 @@
* RESTCONF PATCH (plain patch) is being implemented according to RFC 8040 Section 4.6.1
* Note RESTCONF plain patch is different from RFC 8072 "YANG Patch Media Type" which is not implemented
* RESTCONF "content" query parameter supported
+ * Extended Netconf with content attribute for internal use
+ * RESTCONF "depth" query parameter supported
+ * Extended Netconf with depth attribute for internal use
* RESTCONF "insert" and "point" query parameters supported
* Applies to ordered-by-user leaf and leaf-lists
* RESTCONF PUT/POST erroneously returned 200 OK. Instead restconf now returns:
@@ -45,10 +48,15 @@
* Empty yang container encoded as `{}`
* Empty leaf/leaf-list of type empty encoded as `[null]`
* Other empty values remain as `null`
+* C API changes:
+ * Added `depth` parameter to function `clicon_xml2cbuf`, default is -1.
+ * Added two parameters to function `clicon_rpc_get`
+ * `content`: to select state or config. Allowed values: CONTENT_CONFIG,CONTENT_NOCONFIG, CONTENT_ALL (default)
+ * `depth`: Get levels of XML in get function: -1 is unbounded, 0 is nothing, 1 is top-level node only.
+
### Minor changes
* Added experimental binary search API function: `xml_binsearch`
-* Added content parameter to `clicon_rpc_get` (-1 or CONTENT_ALL is default)
* Removed unnecessary configure dependencies
* libnsl, libcrypt, if_vlan,...
* pseudo-plugin added, to enable callbacks also for main programs. Useful for extensions
diff --git a/README.md b/README.md
index aa4d3106..026ad920 100644
--- a/README.md
+++ b/README.md
@@ -236,15 +236,14 @@ run with NGINX.
The implementatation is based on [RFC 8040: RESTCONF Protocol](https://tools.ietf.org/html/rfc8040).
The following features of RFC8040 are supported:
-- OPTIONS, HEAD, GET, POST, PUT, DELETE
+- OPTIONS, HEAD, GET, POST, PUT, DELETE, PATCH
- stream notifications (Sec 6)
-- query parameters: "insert", "point", "start-time" and "stop-time".
+- query parameters: "insert", "point", "content", "depth", "start-time" and "stop-time".
- Monitoring (Sec 9)
The following features are not implemented:
- ETag/Last-Modified
-- PATCH
-- Query parameters: "content", "depth", "fields", "filter", "with-defaults"
+- Query parameters: "fields", "filter", "with-defaults"
See [more detailed instructions](apps/restconf/README.md).
diff --git a/apps/backend/backend_client.c b/apps/backend/backend_client.c
index c6b46b74..bbdb0b54 100644
--- a/apps/backend/backend_client.c
+++ b/apps/backend/backend_client.c
@@ -176,6 +176,8 @@ client_get_capabilities(clicon_handle h,
goto done;
if (xml_parse_va(&xcap, yspec, "urn:ietf:params:restconf:capability:defaults:1.0?basic-mode=explicit") < 0)
goto done;
+ if (xml_parse_va(&xcap, yspec, "urn:ietf:params:restconf:capability:depth:1.0") < 0)
+ goto done;
retval = 0;
done:
return retval;
@@ -428,7 +430,7 @@ from_client_get_config(clicon_handle h,
else{
if (xml_name_set(xret, "data") < 0)
goto done;
- if (clicon_xml2cbuf(cbret, xret, 0, 0) < 0)
+ if (clicon_xml2cbuf(cbret, xret, 0, 0, -1) < 0)
goto done;
}
cprintf(cbret, "");
@@ -541,7 +543,7 @@ from_client_edit_config(clicon_handle h,
if ((ret = xml_yang_validate_list_key_only(h, xc, &xret)) < 0)
goto done;
if (ret == 0){
- if (clicon_xml2cbuf(cbret, xret, 0, 0) < 0)
+ if (clicon_xml2cbuf(cbret, xret, 0, 0, -1) < 0)
goto done;
goto ok;
}
@@ -877,6 +879,7 @@ from_client_get(clicon_handle h,
cvec *nsc = NULL; /* Create a netconf namespace context from filter */
char *attr;
netconf_content content = CONTENT_ALL;
+ int32_t depth = -1; /* Nr of levels to print, -1 is all, 0 is none */
username = clicon_username_get(h);
if ((xfilter = xml_find(xe, "filter")) != NULL){
@@ -890,9 +893,24 @@ from_client_get(clicon_handle h,
if (xml_nsctx_node(xfilter, &nsc) < 0)
goto done;
}
+ /* Clixon extensions: depth and content */
if ((attr = xml_find_value(xe, "content")) != NULL)
content = netconf_content_str2int(attr);
+ if ((attr = xml_find_value(xe, "depth")) != NULL){
+ char *reason = NULL;
+ if ((ret = parse_int32(attr, &depth, &reason)) < 0){
+ clicon_err(OE_XML, errno, "parse_int32");
+ goto done;
+ }
+ if (ret == 0){
+ if (netconf_bad_attribute(cbret, "application",
+ "depth", "Unrecognized value of depth attribute") < 0)
+ goto done;
+ goto ok;
+ }
+ }
+
if (content != CONTENT_NONCONFIG){
/* Get config
* Note xret can be pruned by nacm below and change name and
@@ -911,7 +929,7 @@ from_client_get(clicon_handle h,
if ((ret = client_statedata(h, xpath, nsc, &xret)) < 0)
goto done;
if (ret == 0){ /* Error from callback (error in xret) */
- if (clicon_xml2cbuf(cbret, xret, 0, 0) < 0)
+ if (clicon_xml2cbuf(cbret, xret, 0, 0, -1) < 0)
goto done;
goto ok;
}
@@ -932,7 +950,8 @@ from_client_get(clicon_handle h,
else{
if (xml_name_set(xret, "data") < 0)
goto done;
- if (clicon_xml2cbuf(cbret, xret, 0, 0) < 0)
+ /* Top level is data, so add 1 to depth if significant */
+ if (clicon_xml2cbuf(cbret, xret, 0, 0, depth>0?depth+1:depth) < 0)
goto done;
}
cprintf(cbret, "");
@@ -1250,7 +1269,7 @@ from_client_msg(clicon_handle h,
if ((ret = xml_yang_validate_rpc(h, x, &xret)) < 0)
goto done;
if (ret == 0){
- if (clicon_xml2cbuf(cbret, xret, 0, 0) < 0)
+ if (clicon_xml2cbuf(cbret, xret, 0, 0, -1) < 0)
goto done;
goto reply;
}
diff --git a/apps/backend/backend_commit.c b/apps/backend/backend_commit.c
index 66d2a628..3c115532 100644
--- a/apps/backend/backend_commit.c
+++ b/apps/backend/backend_commit.c
@@ -230,7 +230,7 @@ startup_common(clicon_handle h,
if ((ret = generic_validate(h, yspec, td, &xret)) < 0)
goto done;
if (ret == 0){
- if (clicon_xml2cbuf(cbret, xret, 0, 0) < 0)
+ if (clicon_xml2cbuf(cbret, xret, 0, 0, -1) < 0)
goto done;
goto fail; /* STARTUP_INVALID */
}
@@ -522,7 +522,7 @@ candidate_commit(clicon_handle h,
if ((ret = from_validate_common(h, candidate, td, &xret)) < 0)
goto done;
if (ret == 0){
- if (clicon_xml2cbuf(cbret, xret, 0, 0) < 0)
+ if (clicon_xml2cbuf(cbret, xret, 0, 0, -1) < 0)
goto done;
goto fail;
}
@@ -755,7 +755,7 @@ from_client_validate(clicon_handle h,
/* A little complex due to several sources of validation fails or errors.
* (1) xerr is set -> translate to cbret; (2) cbret set use that; otherwise
* use clicon_err. */
- if (xret && clicon_xml2cbuf(cbret, xret, 0, 0) < 0)
+ if (xret && clicon_xml2cbuf(cbret, xret, 0, 0, -1) < 0)
goto done;
plugin_transaction_abort(h, td);
if (!cbuf_len(cbret) &&
diff --git a/apps/backend/clixon_backend_transaction.c b/apps/backend/clixon_backend_transaction.c
index 46d4f827..a5779633 100644
--- a/apps/backend/clixon_backend_transaction.c
+++ b/apps/backend/clixon_backend_transaction.c
@@ -240,7 +240,7 @@ transaction_log(clicon_handle h,
}
for (i=0; itd_dlen; i++){
xn = td->td_dvec[i];
- clicon_xml2cbuf(cb, xn, 0, 0);
+ clicon_xml2cbuf(cb, xn, 0, 0, -1);
}
if (i)
clicon_log(level, "%s %" PRIu64 " %s del: %s",
@@ -248,7 +248,7 @@ transaction_log(clicon_handle h,
cbuf_reset(cb);
for (i=0; itd_alen; i++){
xn = td->td_avec[i];
- clicon_xml2cbuf(cb, xn, 0, 0);
+ clicon_xml2cbuf(cb, xn, 0, 0, -1);
}
if (i)
clicon_log(level, "%s %" PRIu64 " %s add: %s", __FUNCTION__, td->td_id, op, cbuf_get(cb));
@@ -256,10 +256,10 @@ transaction_log(clicon_handle h,
for (i=0; itd_clen; i++){
if (td->td_scvec){
xn = td->td_scvec[i];
- clicon_xml2cbuf(cb, xn, 0, 0);
+ clicon_xml2cbuf(cb, xn, 0, 0, -1);
}
xn = td->td_tcvec[i];
- clicon_xml2cbuf(cb, xn, 0, 0);
+ clicon_xml2cbuf(cb, xn, 0, 0, -1);
}
if (i)
clicon_log(level, "%s %" PRIu64 " %s change: %s", __FUNCTION__, td->td_id, op, cbuf_get(cb));
diff --git a/apps/cli/cli_common.c b/apps/cli/cli_common.c
index f0840491..4d0bdb8b 100644
--- a/apps/cli/cli_common.c
+++ b/apps/cli/cli_common.c
@@ -279,7 +279,7 @@ cli_dbxml(clicon_handle h,
clicon_err(OE_XML, errno, "cbuf_new");
goto done;
}
- if (clicon_xml2cbuf(cb, xtop, 0, 0) < 0)
+ if (clicon_xml2cbuf(cb, xtop, 0, 0, -1) < 0)
goto done;
if (clicon_rpc_edit_config(h, "candidate", OP_NONE, cbuf_get(cb)) < 0)
goto done;
@@ -792,7 +792,7 @@ load_config_file(clicon_handle h,
while ((x = xml_child_each(xt, x, -1)) != NULL) {
/* Ensure top-level is "config", maybe this is too rough? */
xml_name_set(x, "config");
- if (clicon_xml2cbuf(cbxml, x, 0, 0) < 0)
+ if (clicon_xml2cbuf(cbxml, x, 0, 0, -1) < 0)
goto done;
}
if (clicon_rpc_edit_config(h, "candidate",
@@ -1235,7 +1235,7 @@ cli_copy_config(clicon_handle h,
/* resuse cb */
cbuf_reset(cb);
/* create xml copy tree and merge it with database configuration */
- clicon_xml2cbuf(cb, x2, 0, 0);
+ clicon_xml2cbuf(cb, x2, 0, 0, -1);
if (clicon_rpc_edit_config(h, db, OP_MERGE, cbuf_get(cb)) < 0)
goto done;
retval = 0;
diff --git a/apps/cli/cli_show.c b/apps/cli/cli_show.c
index 51285bba..43e22237 100644
--- a/apps/cli/cli_show.c
+++ b/apps/cli/cli_show.c
@@ -472,7 +472,7 @@ cli_show_config1(clicon_handle h,
clicon_err(OE_FATAL, 0, "Show state only for running database, not %s", db);
goto done;
}
- if (clicon_rpc_get(h, cbuf_get(cbxpath), namespace, CONTENT_ALL, &xt) < 0)
+ if (clicon_rpc_get(h, cbuf_get(cbxpath), namespace, CONTENT_ALL, -1, &xt) < 0)
goto done;
}
if ((xerr = xpath_first(xt, "/rpc-error")) != NULL){
@@ -723,7 +723,7 @@ cli_show_auto1(clicon_handle h,
clicon_err(OE_FATAL, 0, "Show state only for running database, not %s", db);
goto done;
}
- if (clicon_rpc_get(h, xpath, namespace, CONTENT_ALL, &xt) < 0)
+ if (clicon_rpc_get(h, xpath, namespace, CONTENT_ALL, -1, &xt) < 0)
goto done;
}
diff --git a/apps/netconf/netconf_main.c b/apps/netconf/netconf_main.c
index f1fadb92..fe46fa25 100644
--- a/apps/netconf/netconf_main.c
+++ b/apps/netconf/netconf_main.c
@@ -128,7 +128,7 @@ netconf_input_packet(clicon_handle h,
if ((ret = xml_yang_validate_rpc(h, xrpc, &xret)) < 0)
goto done;
if (ret == 0){
- clicon_xml2cbuf(cbret, xret, 0, 0);
+ clicon_xml2cbuf(cbret, xret, 0, 0, -1);
netconf_output_encap(1, cbret, "rpc-error");
goto ok;
}
@@ -170,7 +170,7 @@ netconf_input_packet(clicon_handle h,
if (xml_addsub(xc, xa2) < 0)
goto done;
}
- clicon_xml2cbuf(cbret, xml_child_i(xret,0), 0, 0);
+ clicon_xml2cbuf(cbret, xml_child_i(xret,0), 0, 0, -1);
if (netconf_output_encap(1, cbret, "rpc-reply") < 0){
cbuf_free(cbret);
goto done;
diff --git a/apps/netconf/netconf_rpc.c b/apps/netconf/netconf_rpc.c
index 7f09ea55..ad91b728 100644
--- a/apps/netconf/netconf_rpc.c
+++ b/apps/netconf/netconf_rpc.c
@@ -455,7 +455,7 @@ netconf_notification_cb(int s,
clicon_err(OE_PLUGIN, errno, "cbuf_new");
goto done;
}
- if (clicon_xml2cbuf(cb, xn, 0, 0) < 0)
+ if (clicon_xml2cbuf(cb, xn, 0, 0, -1) < 0)
goto done;
/* Send it to listening client on stdout */
if (netconf_output_encap(1, cb, "notification") < 0){
@@ -599,7 +599,7 @@ netconf_application_rpc(clicon_handle h,
if (ret > 0 && (ret = xml_yang_validate_add(h, xn, &xerr)) < 0)
goto done;
if (ret == 0){
- if (clicon_xml2cbuf(cbret, xerr, 0, 0) < 0)
+ if (clicon_xml2cbuf(cbret, xerr, 0, 0, -1) < 0)
goto done;
netconf_output_encap(1, cbret, "rpc-error");
goto ok;
@@ -632,7 +632,7 @@ netconf_application_rpc(clicon_handle h,
if (ret > 0 && (ret = xml_yang_validate_add(h, xoutput, &xerr)) < 0)
goto done;
if (ret == 0){
- if (clicon_xml2cbuf(cbret, xerr, 0, 0) < 0)
+ if (clicon_xml2cbuf(cbret, xerr, 0, 0, -1) < 0)
goto done;
clicon_log(LOG_WARNING, "Errors in output netconf %s", cbuf_get(cbret));
goto ok;
diff --git a/apps/restconf/restconf_lib.c b/apps/restconf/restconf_lib.c
index 82db21a9..2e14cf2d 100644
--- a/apps/restconf/restconf_lib.c
+++ b/apps/restconf/restconf_lib.c
@@ -496,7 +496,7 @@ api_return_err(clicon_handle h,
FCGX_FPrintF(r->out, "Content-Type: %s\r\n\r\n", restconf_media_int2str(media));
switch (media){
case YANG_DATA_XML:
- if (clicon_xml2cbuf(cb, xerr, 2, pretty) < 0)
+ if (clicon_xml2cbuf(cb, xerr, 2, pretty, -1) < 0)
goto done;
clicon_debug(1, "%s code:%d err:%s", __FUNCTION__, code, cbuf_get(cb));
if (pretty){
diff --git a/apps/restconf/restconf_main.c b/apps/restconf/restconf_main.c
index eb93c6eb..a5c4a41d 100644
--- a/apps/restconf/restconf_main.c
+++ b/apps/restconf/restconf_main.c
@@ -242,7 +242,7 @@ api_root(clicon_handle h,
goto done;
switch (media_out){
case YANG_DATA_XML:
- if (clicon_xml2cbuf(cb, xt, 0, pretty) < 0)
+ if (clicon_xml2cbuf(cb, xt, 0, pretty, -1) < 0)
goto done;
break;
case YANG_DATA_JSON:
@@ -292,7 +292,7 @@ api_yang_library_version(clicon_handle h,
}
switch (media_out){
case YANG_DATA_XML:
- if (clicon_xml2cbuf(cb, xt, 0, pretty) < 0)
+ if (clicon_xml2cbuf(cb, xt, 0, pretty, -1) < 0)
goto done;
break;
case YANG_DATA_JSON:
diff --git a/apps/restconf/restconf_methods.c b/apps/restconf/restconf_methods.c
index 85da9f5b..bf4c37db 100644
--- a/apps/restconf/restconf_methods.c
+++ b/apps/restconf/restconf_methods.c
@@ -326,7 +326,7 @@ api_data_write(clicon_handle h,
#if 0
if (debug){
cbuf *ccc=cbuf_new();
- if (clicon_xml2cbuf(ccc, xret, 0, 0) < 0)
+ if (clicon_xml2cbuf(ccc, xret, 0, 0, -1) < 0)
goto done;
clicon_debug(1, "%s XRET: %s", __FUNCTION__, cbuf_get(ccc));
cbuf_free(ccc);
@@ -457,7 +457,7 @@ api_data_write(clicon_handle h,
#if 0
if (debug){
cbuf *ccc=cbuf_new();
- if (clicon_xml2cbuf(ccc, xdata, 0, 0) < 0)
+ if (clicon_xml2cbuf(ccc, xdata, 0, 0, -1) < 0)
goto done;
clicon_debug(1, "%s DATA:%s", __FUNCTION__, cbuf_get(ccc));
cbuf_free(ccc);
@@ -620,7 +620,7 @@ api_data_write(clicon_handle h,
NETCONF_BASE_NAMESPACE); /* bind nc to netconf namespace */
cprintf(cbx, "");
cprintf(cbx, "none");
- if (clicon_xml2cbuf(cbx, xtop, 0, 0) < 0)
+ if (clicon_xml2cbuf(cbx, xtop, 0, 0, -1) < 0)
goto done;
cprintf(cbx, "");
clicon_debug(1, "%s xml: %s api_path:%s",__FUNCTION__, cbuf_get(cbx), api_path);
@@ -891,7 +891,7 @@ api_data_delete(clicon_handle h,
NETCONF_BASE_NAMESPACE); /* bind nc to netconf namespace */
cprintf(cbx, "");
cprintf(cbx, "none");
- if (clicon_xml2cbuf(cbx, xtop, 0, 0) < 0)
+ if (clicon_xml2cbuf(cbx, xtop, 0, 0, -1) < 0)
goto done;
cprintf(cbx, "");
if (clicon_rpc_netconf(h, cbuf_get(cbx), &xret, NULL) < 0)
diff --git a/apps/restconf/restconf_methods_get.c b/apps/restconf/restconf_methods_get.c
index 3cba9b47..36004540 100644
--- a/apps/restconf/restconf_methods_get.c
+++ b/apps/restconf/restconf_methods_get.c
@@ -114,8 +114,9 @@ api_data_get2(clicon_handle h,
int ret;
char *namespace = NULL;
cvec *nsc = NULL;
- char *str;
+ char *attr; /* attribute value string */
netconf_content content = CONTENT_ALL;
+ int32_t depth = -1; /* Nr of levels to print, -1 is all, 0 is none */
clicon_debug(1, "%s", __FUNCTION__);
if ((yspec = clicon_dbspec_yang(h)) == NULL){
@@ -123,9 +124,9 @@ api_data_get2(clicon_handle h,
goto done;
}
/* Check for content attribute */
- if ((str = cvec_find_str(qvec, "content")) != NULL){
- clicon_debug(1, "%s content=%s", __FUNCTION__, str);
- if ((content = netconf_content_str2int(str)) == -1){
+ if ((attr = cvec_find_str(qvec, "content")) != NULL){
+ clicon_debug(1, "%s content=%s", __FUNCTION__, attr);
+ if ((content = netconf_content_str2int(attr)) == -1){
if (netconf_bad_attribute_xml(&xerr, "application",
"content", "Unrecognized value of content attribute") < 0)
goto done;
@@ -138,7 +139,29 @@ api_data_get2(clicon_handle h,
goto ok;
}
}
-
+ /* Check for depth attribute */
+ if ((attr = cvec_find_str(qvec, "depth")) != NULL){
+ clicon_debug(1, "%s depth=%s", __FUNCTION__, attr);
+ if (strcmp(attr, "unbounded") != 0){
+ char *reason = NULL;
+ if ((ret = parse_int32(attr, &depth, &reason)) < 0){
+ clicon_err(OE_XML, errno, "parse_int32");
+ goto done;
+ }
+ if (ret==0){
+ if (netconf_bad_attribute_xml(&xerr, "application",
+ "depth", "Unrecognized value of depth attribute") < 0)
+ goto done;
+ if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
+ clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
+ goto done;
+ }
+ if (api_return_err(h, r, xe, pretty, media_out, 0) < 0)
+ goto done;
+ goto ok;
+ }
+ }
+ }
if ((cbpath = cbuf_new()) == NULL)
goto done;
cprintf(cbpath, "/");
@@ -165,13 +188,13 @@ api_data_get2(clicon_handle h,
goto done;
switch (content){
case CONTENT_CONFIG:
- ret = clicon_rpc_get_config(h, "running", xpath, namespace, &xret);
+ ret = clicon_rpc_get(h, xpath, namespace, CONTENT_CONFIG, depth, &xret);
break;
case CONTENT_NONCONFIG:
- ret = clicon_rpc_get(h, xpath, namespace, CONTENT_NONCONFIG, &xret);
+ ret = clicon_rpc_get(h, xpath, namespace, CONTENT_NONCONFIG, depth, &xret);
break;
case CONTENT_ALL:
- ret = clicon_rpc_get(h, xpath, namespace, CONTENT_ALL, &xret);
+ ret = clicon_rpc_get(h, xpath, namespace, CONTENT_ALL, depth, &xret);
break;
default:
clicon_err(OE_XML, EINVAL, "Invalid content attribute %d", content);
@@ -196,7 +219,7 @@ api_data_get2(clicon_handle h,
#if 0 /* DEBUG */
if (debug){
cbuf *cb = cbuf_new();
- clicon_xml2cbuf(cb, xret, 0, 0);
+ clicon_xml2cbuf(cb, xret, 0, 0, -1);
clicon_debug(1, "%s xret:%s", __FUNCTION__, cbuf_get(cb));
cbuf_free(cb);
}
@@ -219,7 +242,7 @@ api_data_get2(clicon_handle h,
if (xpath==NULL || strcmp(xpath,"/")==0){ /* Special case: data root */
switch (media_out){
case YANG_DATA_XML:
- if (clicon_xml2cbuf(cbx, xret, 0, pretty) < 0) /* Dont print top object? */
+ if (clicon_xml2cbuf(cbx, xret, 0, pretty, -1) < 0) /* Dont print top object? */
goto done;
break;
case YANG_DATA_JSON:
@@ -268,7 +291,7 @@ api_data_get2(clicon_handle h,
if (namespace2 && xmlns_set(x, prefix, namespace2) < 0)
goto done;
}
- if (clicon_xml2cbuf(cbx, x, 0, pretty) < 0) /* Dont print top object? */
+ if (clicon_xml2cbuf(cbx, x, 0, pretty, -1) < 0) /* Dont print top object? */
goto done;
}
break;
diff --git a/apps/restconf/restconf_methods_post.c b/apps/restconf/restconf_methods_post.c
index 55583eae..c30b9487 100644
--- a/apps/restconf/restconf_methods_post.c
+++ b/apps/restconf/restconf_methods_post.c
@@ -164,7 +164,7 @@ api_data_post(clicon_handle h,
#if 1
if (debug){
cbuf *ccc=cbuf_new();
- if (clicon_xml2cbuf(ccc, xtop, 0, 0) < 0)
+ if (clicon_xml2cbuf(ccc, xtop, 0, 0, -1) < 0)
goto done;
clicon_debug(1, "%s XURI:%s", __FUNCTION__, cbuf_get(ccc));
cbuf_free(ccc);
@@ -309,7 +309,7 @@ api_data_post(clicon_handle h,
#if 1
if (debug){
cbuf *ccc=cbuf_new();
- if (clicon_xml2cbuf(ccc, xdata, 0, 0) < 0)
+ if (clicon_xml2cbuf(ccc, xdata, 0, 0, -1) < 0)
goto done;
clicon_debug(1, "%s XDATA:%s", __FUNCTION__, cbuf_get(ccc));
cbuf_free(ccc);
@@ -330,7 +330,7 @@ api_data_post(clicon_handle h,
NETCONF_BASE_NAMESPACE); /* bind nc to netconf namespace */
cprintf(cbx, "");
cprintf(cbx, "none");
- if (clicon_xml2cbuf(cbx, xtop, 0, 0) < 0)
+ if (clicon_xml2cbuf(cbx, xtop, 0, 0, -1) < 0)
goto done;
cprintf(cbx, "");
clicon_debug(1, "%s xml: %s api_path:%s",__FUNCTION__, cbuf_get(cbx), api_path);
@@ -507,7 +507,7 @@ api_operations_post_input(clicon_handle h,
#if 1
if (debug){
cbuf *ccc=cbuf_new();
- if (clicon_xml2cbuf(ccc, xdata, 0, 0) < 0)
+ if (clicon_xml2cbuf(ccc, xdata, 0, 0, -1) < 0)
goto done;
clicon_debug(1, "%s DATA:%s", __FUNCTION__, cbuf_get(ccc));
cbuf_free(ccc);
@@ -614,7 +614,7 @@ api_operations_post_output(clicon_handle h,
#if 1
if (debug){
cbuf *ccc=cbuf_new();
- if (clicon_xml2cbuf(ccc, xoutput, 0, 0) < 0)
+ if (clicon_xml2cbuf(ccc, xoutput, 0, 0, -1) < 0)
goto done;
clicon_debug(1, "%s XOUTPUT:%s", __FUNCTION__, cbuf_get(ccc));
cbuf_free(ccc);
@@ -855,7 +855,7 @@ api_operations_post(clicon_handle h,
#if 1
if (debug){
cbuf *ccc=cbuf_new();
- if (clicon_xml2cbuf(ccc, xtop, 0, 0) < 0)
+ if (clicon_xml2cbuf(ccc, xtop, 0, 0, -1) < 0)
goto done;
clicon_debug(1, "%s 5. Translate input args: %s",
__FUNCTION__, cbuf_get(ccc));
@@ -882,7 +882,7 @@ api_operations_post(clicon_handle h,
#if 0
if (debug){
cbuf *ccc=cbuf_new();
- if (clicon_xml2cbuf(ccc, xtop, 0, 0) < 0)
+ if (clicon_xml2cbuf(ccc, xtop, 0, 0, -1) < 0)
goto done;
clicon_debug(1, "%s 6. Validate and defaults:%s", __FUNCTION__, cbuf_get(ccc));
cbuf_free(ccc);
@@ -922,7 +922,7 @@ api_operations_post(clicon_handle h,
#if 1
if (debug){
cbuf *ccc=cbuf_new();
- if (clicon_xml2cbuf(ccc, xret, 0, 0) < 0)
+ if (clicon_xml2cbuf(ccc, xret, 0, 0, -1) < 0)
goto done;
clicon_debug(1, "%s 8. Receive reply:%s", __FUNCTION__, cbuf_get(ccc));
cbuf_free(ccc);
@@ -942,7 +942,7 @@ api_operations_post(clicon_handle h,
cbuf_reset(cbret);
switch (media_out){
case YANG_DATA_XML:
- if (clicon_xml2cbuf(cbret, xoutput, 0, pretty) < 0)
+ if (clicon_xml2cbuf(cbret, xoutput, 0, pretty, -1) < 0)
goto done;
/* xoutput should now look: */
break;
diff --git a/apps/restconf/restconf_stream.c b/apps/restconf/restconf_stream.c
index a53db543..a75a63ea 100644
--- a/apps/restconf/restconf_stream.c
+++ b/apps/restconf/restconf_stream.c
@@ -201,7 +201,7 @@ restconf_stream_cb(int s,
FCGX_FPrintF(r->out, "M#id: %02d:0\r\n", tv.tv_sec);
}
#endif
- if (clicon_xml2cbuf(cb, xn, 0, pretty) < 0)
+ if (clicon_xml2cbuf(cb, xn, 0, pretty, -1) < 0)
goto done;
FCGX_FPrintF(r->out, "data: %s\r\n", cbuf_get(cb));
FCGX_FPrintF(r->out, "\r\n");
diff --git a/example/main/example_backend.c b/example/main/example_backend.c
index 234c8d92..25a38514 100644
--- a/example/main/example_backend.c
+++ b/example/main/example_backend.c
@@ -248,7 +248,7 @@ example_rpc(clicon_handle h, /* Clicon handle */
else while ((x = xml_child_each(xe, x, CX_ELMNT)) != NULL) {
if (xmlns_set(x, NULL, namespace) < 0)
goto done;
- if (clicon_xml2cbuf(cbret, x, 0, 0) < 0)
+ if (clicon_xml2cbuf(cbret, x, 0, 0, -1) < 0)
goto done;
}
cprintf(cbret, "");
diff --git a/example/main/example_netconf.c b/example/main/example_netconf.c
index acab6ef0..9d2dd32a 100644
--- a/example/main/example_netconf.c
+++ b/example/main/example_netconf.c
@@ -64,11 +64,12 @@ plugin_exit(clicon_handle h)
/*! Local example netconf rpc callback
*/
-int netconf_client_rpc(clicon_handle h,
- cxobj *xe,
- cbuf *cbret,
- void *arg,
- void *regarg)
+int
+netconf_client_rpc(clicon_handle h,
+ cxobj *xe,
+ cbuf *cbret,
+ void *arg,
+ void *regarg)
{
int retval = -1;
cxobj *x = NULL;
@@ -85,7 +86,7 @@ int netconf_client_rpc(clicon_handle h,
else while ((x = xml_child_each(xe, x, CX_ELMNT)) != NULL) {
if (xmlns_set(x, NULL, namespace) < 0)
goto done;
- if (clicon_xml2cbuf(cbret, x, 0, 0) < 0)
+ if (clicon_xml2cbuf(cbret, x, 0, 0, -1) < 0)
goto done;
}
cprintf(cbret, "");
diff --git a/example/main/example_restconf.c b/example/main/example_restconf.c
index 71bdd391..24db9d82 100644
--- a/example/main/example_restconf.c
+++ b/example/main/example_restconf.c
@@ -287,7 +287,7 @@ restconf_client_rpc(clicon_handle h,
else while ((x = xml_child_each(xe, x, CX_ELMNT)) != NULL) {
if (xmlns_set(x, NULL, namespace) < 0)
goto done;
- if (clicon_xml2cbuf(cbret, x, 0, 0) < 0)
+ if (clicon_xml2cbuf(cbret, x, 0, 0, -1) < 0)
goto done;
}
cprintf(cbret, "");
diff --git a/lib/clixon/clixon_proto_client.h b/lib/clixon/clixon_proto_client.h
index d16615bf..9bdbe204 100644
--- a/lib/clixon/clixon_proto_client.h
+++ b/lib/clixon/clixon_proto_client.h
@@ -52,7 +52,7 @@ int clicon_rpc_copy_config(clicon_handle h, char *db1, char *db2);
int clicon_rpc_delete_config(clicon_handle h, char *db);
int clicon_rpc_lock(clicon_handle h, char *db);
int clicon_rpc_unlock(clicon_handle h, char *db);
-int clicon_rpc_get(clicon_handle h, char *xpath, char *namespace, netconf_content content, cxobj **xret);
+int clicon_rpc_get(clicon_handle h, char *xpath, char *namespace, netconf_content content, int32_t depth, cxobj **xret);
int clicon_rpc_close_session(clicon_handle h);
int clicon_rpc_kill_session(clicon_handle h, int session_id);
int clicon_rpc_validate(clicon_handle h, char *db);
diff --git a/lib/clixon/clixon_xml.h b/lib/clixon/clixon_xml.h
index 0784869a..9c961581 100644
--- a/lib/clixon/clixon_xml.h
+++ b/lib/clixon/clixon_xml.h
@@ -170,7 +170,7 @@ int xml_free(cxobj *xn);
int xml_print(FILE *f, cxobj *xn);
int clicon_xml2file(FILE *f, cxobj *xn, int level, int prettyprint);
-int clicon_xml2cbuf(cbuf *xf, cxobj *xn, int level, int prettyprint);
+int clicon_xml2cbuf(cbuf *xf, cxobj *xn, int level, int prettyprint, int32_t depth);
int xml_parse_file(int fd, char *endtag, yang_stmt *yspec, cxobj **xt);
int xml_parse_string(const char *str, yang_stmt *yspec, cxobj **xml_top);
#if defined(__GNUC__) && __GNUC__ >= 3
diff --git a/lib/clixon/clixon_xpath.h b/lib/clixon/clixon_xpath.h
index c8a18b0e..dea6f832 100644
--- a/lib/clixon/clixon_xpath.h
+++ b/lib/clixon/clixon_xpath.h
@@ -113,7 +113,8 @@ typedef struct xpath_tree xpath_tree;
* Prototypes
*/
char* xpath_tree_int2str(int nodetype);
-int xpath_tree_print(cbuf *cb, xpath_tree *xs);
+int xpath_tree_print_cb(cbuf *cb, xpath_tree *xs);
+int xpath_tree_print(FILE *f, 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);
diff --git a/lib/src/clixon_netconf_lib.c b/lib/src/clixon_netconf_lib.c
index bf24e203..95c7a414 100644
--- a/lib/src/clixon_netconf_lib.c
+++ b/lib/src/clixon_netconf_lib.c
@@ -167,7 +167,7 @@ netconf_invalid_value(cbuf *cb,
if (netconf_invalid_value_xml(&xret, type, message) < 0)
goto done;
- if (clicon_xml2cbuf(cb, xret, 0, 0) < 0)
+ if (clicon_xml2cbuf(cb, xret, 0, 0, -1) < 0)
goto done;
retval = 0;
done:
@@ -276,7 +276,7 @@ netconf_bad_attribute(cbuf *cb,
if (netconf_bad_attribute_xml(&xret, type, info, message) < 0)
goto done;
- if (clicon_xml2cbuf(cb, xret, 0, 0) < 0)
+ if (clicon_xml2cbuf(cb, xret, 0, 0, -1) < 0)
goto done;
retval = 0;
done:
@@ -441,7 +441,7 @@ netconf_missing_element(cbuf *cb,
if (netconf_common_xml(&xret, type, "missing-element",
"bad-element", element, message) < 0)
goto done;
- if (clicon_xml2cbuf(cb, xret, 0, 0) < 0)
+ if (clicon_xml2cbuf(cb, xret, 0, 0, -1) < 0)
goto done;
retval = 0;
done:
@@ -487,7 +487,7 @@ netconf_bad_element(cbuf *cb,
if (netconf_common_xml(&xret, type, "bad-element",
"bad-element",element, message) < 0)
goto done;
- if (clicon_xml2cbuf(cb, xret, 0, 0) < 0)
+ if (clicon_xml2cbuf(cb, xret, 0, 0, -1) < 0)
goto done;
retval = 0;
done:
@@ -525,7 +525,7 @@ netconf_unknown_element(cbuf *cb,
if (netconf_common_xml(&xret, type, "unknown-element",
"bad-element", element, message) < 0)
goto done;
- if (clicon_xml2cbuf(cb, xret, 0, 0) < 0)
+ if (clicon_xml2cbuf(cb, xret, 0, 0, -1) < 0)
goto done;
retval = 0;
done:
@@ -572,7 +572,7 @@ netconf_unknown_namespace(cbuf *cb,
if (netconf_common_xml(&xret, type, "unknown-namespace",
"bad-namespace", namespace, message) < 0)
goto done;
- if (clicon_xml2cbuf(cb, xret, 0, 0) < 0)
+ if (clicon_xml2cbuf(cb, xret, 0, 0, -1) < 0)
goto done;
retval = 0;
done:
@@ -610,7 +610,7 @@ netconf_access_denied(cbuf *cb,
if (netconf_access_denied_xml(&xret, type, message) < 0)
goto done;
- if (clicon_xml2cbuf(cb, xret, 0, 0) < 0)
+ if (clicon_xml2cbuf(cb, xret, 0, 0, -1) < 0)
goto done;
retval = 0;
done:
@@ -846,7 +846,7 @@ netconf_data_missing(cbuf *cb,
if (netconf_data_missing_xml(&xret, missing_choice, message) < 0)
goto done;
- if (clicon_xml2cbuf(cb, xret, 0, 0) < 0)
+ if (clicon_xml2cbuf(cb, xret, 0, 0, -1) < 0)
goto done;
retval = 0;
done:
@@ -967,7 +967,7 @@ netconf_operation_failed(cbuf *cb,
if (netconf_operation_failed_xml(&xret, type, message) < 0)
goto done;
- if (clicon_xml2cbuf(cb, xret, 0, 0) < 0)
+ if (clicon_xml2cbuf(cb, xret, 0, 0, -1) < 0)
goto done;
retval = 0;
done:
@@ -1045,7 +1045,7 @@ netconf_malformed_message(cbuf *cb,
if (netconf_malformed_message_xml(&xret, message) < 0)
goto done;
- if (clicon_xml2cbuf(cb, xret, 0, 0) < 0)
+ if (clicon_xml2cbuf(cb, xret, 0, 0, -1) < 0)
goto done;
retval = 0;
done:
@@ -1148,7 +1148,7 @@ netconf_data_not_unique_xml(cxobj **xret,
while ((cvi = cvec_each(cvk, cvi)) != NULL){
if ((xi = xml_find(x, cv_string_get(cvi))) == NULL)
continue; /* ignore, shouldnt happen */
- clicon_xml2cbuf(cb, xi, 0, 0);
+ clicon_xml2cbuf(cb, xi, 0, 0, -1);
if (xml_parse_va(&xinfo, NULL, "%s", cbuf_get(cb)) < 0)
goto done;
cbuf_reset(cb);
@@ -1369,7 +1369,7 @@ netconf_err2cb(cxobj *xerr,
if ((x=xpath_first(xerr, "error-message"))!=NULL)
cprintf(cb, "%s ", xml_body(x));
if ((x=xpath_first(xerr, "error-info"))!=NULL)
- clicon_xml2cbuf(cb, xml_child_i(x,0), 0, 0);
+ clicon_xml2cbuf(cb, xml_child_i(x,0), 0, 0, -1);
*cberr = cb;
retval = 0;
done:
diff --git a/lib/src/clixon_proto.c b/lib/src/clixon_proto.c
index c357e300..e365738b 100644
--- a/lib/src/clixon_proto.c
+++ b/lib/src/clixon_proto.c
@@ -606,7 +606,7 @@ send_msg_notify_xml(int s,
clicon_err(OE_PLUGIN, errno, "cbuf_new");
goto done;
}
- if (clicon_xml2cbuf(cb, xev, 0, 0) < 0)
+ if (clicon_xml2cbuf(cb, xev, 0, 0, -1) < 0)
goto done;
if (send_msg_notify(s, cbuf_get(cb)) < 0)
goto done;
diff --git a/lib/src/clixon_proto_client.c b/lib/src/clixon_proto_client.c
index a7cfcf79..40a8ee89 100644
--- a/lib/src/clixon_proto_client.c
+++ b/lib/src/clixon_proto_client.c
@@ -213,7 +213,7 @@ clicon_rpc_netconf_xml(clicon_handle h,
clicon_err(OE_XML, errno, "cbuf_new");
goto done;
}
- if (clicon_xml2cbuf(cb, xml, 0, 0) < 0)
+ if (clicon_xml2cbuf(cb, xml, 0, 0, -1) < 0)
goto done;
if (clicon_rpc_netconf(h, cbuf_get(cb), xret, sp) < 0)
goto done;
@@ -541,7 +541,8 @@ 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] content CLixon extension: all, config, noconfig. -1 means all
+ * @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.
* Either or .
* @retval 0 OK
@@ -550,7 +551,7 @@ clicon_rpc_unlock(clicon_handle h,
* 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, &xt) < 0)
+ * 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);
@@ -563,11 +564,12 @@ clicon_rpc_unlock(clicon_handle h,
* @see clicon_rpc_generate_error
*/
int
-clicon_rpc_get(clicon_handle h,
- char *xpath,
- char *namespace,
+clicon_rpc_get(clicon_handle h,
+ char *xpath,
+ char *namespace,
netconf_content content,
- cxobj **xt)
+ int32_t depth,
+ cxobj **xt)
{
int retval = -1;
struct clicon_msg *msg = NULL;
@@ -584,11 +586,12 @@ clicon_rpc_get(clicon_handle h,
if (namespace)
cprintf(cb, " xmlns:nc=\"%s\"", NETCONF_BASE_NAMESPACE);
cprintf(cb, "> */
+ if (depth != -1)
+ cprintf(cb, " depth=\"%d\"", depth);
cprintf(cb, ">");
if (xpath && strlen(xpath)) {
if (namespace)
diff --git a/lib/src/clixon_stream.c b/lib/src/clixon_stream.c
index 7cc3b119..397b91db 100644
--- a/lib/src/clixon_stream.c
+++ b/lib/src/clixon_stream.c
@@ -984,7 +984,7 @@ stream_publish_cb(clicon_handle h,
clicon_err(OE_XML, errno, "cbuf_new");
goto done;
}
- if (clicon_xml2cbuf(d, event, 0, 0) < 0)
+ if (clicon_xml2cbuf(d, event, 0, 0, -1) < 0)
goto done;
if (url_post(cbuf_get(u), /* url+stream */
cbuf_get(d), /* postfields */
diff --git a/lib/src/clixon_xml.c b/lib/src/clixon_xml.c
index 2a860d0a..c5b1715f 100644
--- a/lib/src/clixon_xml.c
+++ b/lib/src/clixon_xml.c
@@ -1651,13 +1651,14 @@ xml_print(FILE *f,
*
* @param[in,out] cb Cligen buffer to write to
* @param[in] xn Clicon xml tree
- * @param[in] level Indentation level
+ * @param[in] level Indentation level for prettyprint
* @param[in] prettyprint insert \n and spaces tomake the xml more readable.
+ * @param[in] depth Limit levels of child resources: -1 is all, 0 is none, 1 is node itself
*
* @code
* cbuf *cb;
* cb = cbuf_new();
- * if (clicon_xml2cbuf(cb, xn, 0, 1) < 0)
+ * if (clicon_xml2cbuf(cb, xn, 0, 1, -1) < 0)
* goto err;
* fprintf(stderr, "%s", cbuf_get(cb));
* cbuf_free(cb);
@@ -1665,10 +1666,11 @@ xml_print(FILE *f,
* @see clicon_xml2file
*/
int
-clicon_xml2cbuf(cbuf *cb,
- cxobj *x,
- int level,
- int prettyprint)
+clicon_xml2cbuf(cbuf *cb,
+ cxobj *x,
+ int level,
+ int prettyprint,
+ int32_t depth)
{
int retval = -1;
cxobj *xc;
@@ -1679,6 +1681,8 @@ clicon_xml2cbuf(cbuf *cb,
char *encstr = NULL; /* xml encoded string */
char *val;
+ if (depth == 0)
+ goto ok;
name = xml_name(x);
namespace = xml_prefix(x);
switch(xml_type(x)){
@@ -1707,7 +1711,7 @@ clicon_xml2cbuf(cbuf *cb,
while ((xc = xml_child_each(x, xc, -1)) != NULL)
switch (xc->x_type){
case CX_ATTR:
- if (clicon_xml2cbuf(cb, xc, level+1, prettyprint) < 0)
+ if (clicon_xml2cbuf(cb, xc, level+1, prettyprint, -1) < 0)
goto done;
break;
case CX_BODY:
@@ -1729,7 +1733,7 @@ clicon_xml2cbuf(cbuf *cb,
xc = NULL;
while ((xc = xml_child_each(x, xc, -1)) != NULL)
if (xml_type(xc) != CX_ATTR)
- if (clicon_xml2cbuf(cb, xc, level+1, prettyprint) < 0)
+ if (clicon_xml2cbuf(cb, xc, level+1, prettyprint, depth-1) < 0)
goto done;
if (prettyprint && hasbody == 0)
cprintf(cb, "%*s", level*XML_INDENT, "");
@@ -1744,6 +1748,7 @@ clicon_xml2cbuf(cbuf *cb,
default:
break;
}/* switch */
+ ok:
retval = 0;
done:
if (encstr)
@@ -2522,7 +2527,7 @@ clicon_log_xml(int level,
/* Print xml as cbuf */
if ((cb = cbuf_new()) == NULL)
goto done;
- if (clicon_xml2cbuf(cb, x, 0, 0) < 0)
+ if (clicon_xml2cbuf(cb, x, 0, 0, -1) < 0)
goto done;
/* first round: compute length of debug message */
diff --git a/lib/src/clixon_xpath.c b/lib/src/clixon_xpath.c
index 7d62b39e..b9eb88b1 100644
--- a/lib/src/clixon_xpath.c
+++ b/lib/src/clixon_xpath.c
@@ -148,17 +148,40 @@ xpath_tree_print0(cbuf *cb,
return 0;
}
-/*! Print a xpath_tree
+/*! Print a xpath_tree to CLIgen buf
* @param[out] cb CLIgen buffer
* @param[in] xs XPATH tree
*/
int
-xpath_tree_print(cbuf *cb,
- xpath_tree *xs)
+xpath_tree_print_cb(cbuf *cb,
+ xpath_tree *xs)
{
xpath_tree_print0(cb, xs, 0);
return 0;
}
+
+/*! Print a xpath_tree
+ * @param[in] f UNIX output stream
+ * @param[in] xs XPATH tree
+ */
+int
+xpath_tree_print(FILE *f,
+ xpath_tree *xs)
+{
+ int retval = -1;
+ cbuf *cb = NULL;
+
+ if ((cb = cbuf_new()) == NULL){
+ clicon_err(OE_UNIX, errno, "cbuf_new");
+ goto done;
+ }
+ if (xpath_tree_print0(cb, xs, 0) < 0)
+ goto done;
+ fprintf(f, "%s", cbuf_get(cb));
+ retval = 0;
+ done:
+ return retval;
+}
/*! Free a xpath_tree
* @param[in] xs XPATH tree
@@ -203,7 +226,8 @@ xpath_parse(cvec *nsc,
{
int retval = -1;
struct clicon_xpath_yacc_arg xy = {0,};
-
+ cbuf *cb = NULL;
+
xy.xy_parse_string = xpath;
xy.xy_name = "xpath parser";
xy.xy_linenum = 1;
@@ -219,17 +243,20 @@ xpath_parse(cvec *nsc,
goto done;
}
if (debug > 1){
- cbuf *cb = cbuf_new();
- xpath_tree_print(cb, xy.xy_top);
+ if ((cb = cbuf_new()) == NULL){
+ clicon_err(OE_XML, errno, "cbuf_new");
+ goto done;
+ }
+ xpath_tree_print_cb(cb, xy.xy_top);
clicon_debug(2, "xpath parse tree:\n%s", cbuf_get(cb));
- cbuf_free(cb);
}
- /* done: */
xpath_parse_exit(&xy);
xpath_scan_exit(&xy);
*xptree = xy.xy_top;
retval = 0;
done:
+ if (cb)
+ cbuf_free(cb);
return retval;
}
diff --git a/test/test_restconf_jukebox.sh b/test/test_restconf_jukebox.sh
index d4b55b99..4b571781 100755
--- a/test/test_restconf_jukebox.sh
+++ b/test/test_restconf_jukebox.sh
@@ -100,7 +100,8 @@ new "B.1.2. Retrieve the Server Module Information"
expectpart "$(curl -si -X GET -H 'Accept: application/yang-data+json' http://localhost/restconf/data/ietf-yang-library:modules-state)" 0 "HTTP/1.1 200 OK" 'Cache-Control: no-cache' "Content-Type: application/yang-data+json" '{"ietf-yang-library:modules-state":{"module-set-id":' '"module":\[{"name":"example-events","revision":\[null\],"namespace":"urn:example:events","conformance-type":"implement"},{"name":"example-jukebox","revision":"2016-08-15","namespace":"http://example.com/ns/example-jukebox","conformance-type":"implement"}'
new "B.1.3. Retrieve the Server Capability Information"
-expectpart "$(curl -si -X GET -H 'Accept: application/yang-data+xml' http://localhost/restconf/data/ietf-restconf-monitoring:restconf-state/capabilities)" 0 "HTTP/1.1 200 OK" "Content-Type: application/yang-data+xml" 'Cache-Control: no-cache' 'urn:ietf:params:restconf:capability:defaults:1.0?basic-mode=explicit'
+expectpart "$(curl -si -X GET -H 'Accept: application/yang-data+xml' http://localhost/restconf/data/ietf-restconf-monitoring:restconf-state/capabilities)" 0 "HTTP/1.1 200 OK" "Content-Type: application/yang-data+xml" 'Cache-Control: no-cache' 'urn:ietf:params:restconf:capability:defaults:1.0?basic-mode=expliciturn:ietf:params:restconf:capability:depth
+'
new "B.2.1. Create New Data Resources (artist+json)"
expectpart "$(curl -si -X POST -H 'Content-Type: application/yang-data+json' http://localhost/restconf/data/example-jukebox:jukebox/library -d '{"example-jukebox:artist":[{"name":"Foo Fighters"}]}')" 0 "HTTP/1.1 201 Created" "Location: http://localhost/restconf/data/example-jukebox:jukebox/library/artist=Foo%20Fighters"
@@ -165,9 +166,28 @@ expectpart "$(curl -si -X GET http://localhost/restconf/data/example-events:even
new 'B.3.1. "content" Parameter example 3: content=nonconfig'
expectpart "$(curl -si -X GET http://localhost/restconf/data/example-events:events?content=nonconfig -H 'Accept: application/yang-data+json')" 0 'HTTP/1.1 200 OK' '{"example-events:events":{"event":\[{"name":"interface-down","event-count":90},{"name":"interface-up","event-count":77}\]}}'
+#new "restconf DELETE whole datastore"
+#expectfn 'curl -s -X DELETE http://localhost/restconf/data' 0 ""
+
+new 'B.3.2. "depth" Parameter example 1 unbound'
+expectpart "$(curl -si -X GET -H 'Accept: application/yang-data+json' http://localhost/restconf/data/example-jukebox:jukebox?depth=unbounded)" 0 "HTTP/1.1 200 OK" '{"example-jukebox:jukebox":{"library":{"artist":\[{"name":"Foo Fighters","album":\[{"name":"One by One","year":2012}\]},{"name":"Nick Cave and the Bad Seeds","album":\[{"name":"Tender Prey","year":1988},{"name":"The Good Son","year":1990}\]}\]}}}'
+
+new 'B.3.2. "depth" Parameter example 2 depth=1'
+expectpart "$(curl -si -X GET -H 'Accept: application/yang-data+json' http://localhost/restconf/data/example-jukebox:jukebox?depth=1)" 0 "HTTP/1.1 200 OK" '{"example-jukebox:jukebox":{}}'
+
+new 'B.3.2. "depth" Parameter depth=2'
+expectpart "$(curl -si -X GET -H 'Accept: application/yang-data+json' http://localhost/restconf/data/example-jukebox:jukebox?depth=2)" 0 "HTTP/1.1 200 OK" '{"example-jukebox:jukebox":{"library":{}}}'
+
+# Maybe this is not correct w [null,null]but I have no good examples
+new 'B.3.2. "depth" Parameter depth=3'
+expectpart "$(curl -si -X GET -H 'Accept: application/yang-data+json' http://localhost/restconf/data/example-jukebox:jukebox?depth=3)" 0 "HTTP/1.1 200 OK" '{"example-jukebox:jukebox":{"artist":\[null,null\]}}}
+
'
+
new "restconf DELETE whole datastore"
expectfn 'curl -s -X DELETE http://localhost/restconf/data' 0 ""
+#new 'B.3.3. "fields" Parameter'
+
new 'B.3.4. "insert" Parameter'
JSON="{\"example-jukebox:song\":[{\"index\":1,\"id\":\"/example-jukebox:jukebox/library/artist[name='Foo Fighters']/album[name='Wasting Light']/song[name='Rope']\"}]}"
expectpart "$(curl -si -X POST -H 'Content-Type: application/yang-data+json' http://localhost/restconf/data/example-jukebox:jukebox/playlist=Foo-One?insert=first -d "$JSON")" 0 "HTTP/1.1 201 Created" 'Location: http://localhost/restconf/data/example-jukebox:jukebox/playlist=Foo-One/song=1'
@@ -224,7 +244,6 @@ expectpart "$(curl -si -X GET http://localhost/restconf/data/example-jukebox:ext
if false; then # NYI
new "B.2.2. Detect Datastore Resource Entity-Tag Change" # XXX done except entity-changed
-new 'B.3.2. "depth" Parameter'
new 'B.3.3. "fields" Parameter'
new 'B.3.6. "filter" Parameter'
new 'B.3.7. "start-time" Parameter'
diff --git a/util/clixon_util_json.c b/util/clixon_util_json.c
index 5ad62f2a..c1083690 100644
--- a/util/clixon_util_json.c
+++ b/util/clixon_util_json.c
@@ -147,7 +147,7 @@ main(int argc,
if (json)
xml2json_cbuf(cb, xc, pretty); /* print xml */
else
- clicon_xml2cbuf(cb, xc, 0, pretty); /* print xml */
+ clicon_xml2cbuf(cb, xc, 0, pretty, -1); /* print xml */
fprintf(stdout, "%s", cbuf_get(cb));
fflush(stdout);
retval = 0;
diff --git a/util/clixon_util_xml.c b/util/clixon_util_xml.c
index 06504753..ea38cf23 100644
--- a/util/clixon_util_xml.c
+++ b/util/clixon_util_xml.c
@@ -256,7 +256,7 @@ main(int argc,
if (jsonout)
xml2json_cbuf(cb, xc, pretty); /* print xml */
else
- clicon_xml2cbuf(cb, xc, 0, pretty); /* print xml */
+ clicon_xml2cbuf(cb, xc, 0, pretty, -1); /* print xml */
fprintf(stdout, "%s", cbuf_get(cb));
fflush(stdout);
}
diff --git a/util/clixon_util_xpath.c b/util/clixon_util_xpath.c
index c5d5ce2c..d799c4bb 100644
--- a/util/clixon_util_xpath.c
+++ b/util/clixon_util_xpath.c
@@ -51,6 +51,7 @@ See https://www.w3.org/TR/xpath/
#include
#include
#include
+#include
/* cligen */
#include
@@ -68,6 +69,8 @@ usage(char *argv0)
"\t-f \tXML file\n"
"\t-p \tPrimary XPATH string\n"
"\t-i \t(optional) Initial XPATH string\n"
+ "\t-y \tYang filename or dir (load all files)\n"
+ "\t-Y \tYang dirs (can be several)\n"
"and the following extra rules:\n"
"\tif -f is not given, XML input is expected on stdin\n"
"\tif -p is not given, is expected as the first line on stdin\n"
@@ -88,7 +91,7 @@ ctx_print2(cbuf *cb,
case XT_NODESET:
for (i=0; ixc_size; i++){
cprintf(cb, "%d:", i);
- clicon_xml2cbuf(cb, xc->xc_nodeset[i], 0, 0);
+ clicon_xml2cbuf(cb, xc->xc_nodeset[i], 0, 0, -1);
}
break;
case XT_BOOL:
@@ -105,7 +108,8 @@ ctx_print2(cbuf *cb,
}
int
-main(int argc, char **argv)
+main(int argc,
+ char **argv)
{
int retval = -1;
char *argv0 = argv[0];
@@ -118,16 +122,24 @@ main(int argc, char **argv)
char *buf = NULL;
int ret;
int fd = 0; /* unless overriden by argv[1] */
+ char *yang_file_dir = NULL;
+ yang_stmt *yspec = NULL;
char *xpath = NULL;
char *xpath0 = NULL;
char *filename;
xp_ctx *xc = NULL;
cbuf *cb = NULL;
-
+ clicon_handle h;
+ struct stat st;
+
clicon_log_init("xpath", LOG_DEBUG, CLICON_LOG_STDERR);
+
+ if ((h = clicon_handle_init()) == NULL)
+ goto done;
+
optind = 1;
opterr = 0;
- while ((c = getopt(argc, argv, "hD:f:p:i:")) != -1)
+ while ((c = getopt(argc, argv, "hD:f:p:i:y:Y:")) != -1)
switch (c) {
case 'h':
usage(argv0);
@@ -149,10 +161,35 @@ main(int argc, char **argv)
case 'i': /* Optional initial XPATH string */
xpath0 = optarg;
break;
+ case 'y':
+ yang_file_dir = optarg;
+ break;
+ case 'Y':
+ if (clicon_option_add(h, "CLICON_YANG_DIR", optarg) < 0)
+ goto done;
+ break;
default:
usage(argv[0]);
break;
}
+ /* Parse yang */
+ if (yang_file_dir){
+ if ((yspec = yspec_new()) == NULL)
+ goto done;
+ if (stat(yang_file_dir, &st) < 0){
+ clicon_err(OE_YANG, errno, "%s not found", yang_file_dir);
+ goto done;
+ }
+ if (S_ISDIR(st.st_mode)){
+ if (yang_spec_load_dir(h, yang_file_dir, yspec) < 0)
+ goto done;
+ }
+ else{
+ if (yang_spec_parse_file(h, yang_file_dir, yspec) < 0)
+ goto done;
+ }
+ }
+
if (xpath==NULL){
/* First read xpath */
len = 1024; /* any number is fine */
@@ -192,7 +229,37 @@ main(int argc, char **argv)
return -1;
}
- /* If xpath0 given, position current x */
+ /* Validate XML as well */
+ if (yang_file_dir){
+ cbuf *cbret = NULL;
+ cxobj *x1;
+ cxobj *xerr = NULL; /* malloced must be freed */
+
+ x1 = xml_child_i(x0, 0);
+ /* Populate */
+ if (xml_apply0(x1, CX_ELMNT, xml_spec_populate, yspec) < 0)
+ goto done;
+ /* Sort */
+ if (xml_apply0(x1, CX_ELMNT, xml_sort, h) < 0)
+ goto done;
+ /* Add default values */
+ if (xml_apply(x1, CX_ELMNT, xml_default, h) < 0)
+ goto done;
+ if (xml_apply0(x1, -1, xml_sort_verify, h) < 0)
+ clicon_log(LOG_NOTICE, "%s: sort verify failed", __FUNCTION__);
+ if ((ret = xml_yang_validate_all_top(h, x1, &xerr)) < 0)
+ goto done;
+ if (ret > 0 && (ret = xml_yang_validate_add(h, x1, &xerr)) < 0)
+ goto done;
+ if (ret == 0){
+ if (netconf_err2cb(xerr, &cbret) < 0)
+ goto done;
+ fprintf(stderr, "xml validation error: %s\n", cbuf_get(cbret));
+ goto done;
+ }
+ }
+
+ /* If xpath0 given, position current x (ie somewhere else than root) */
if (xpath0){
if ((x = xpath_first(x0, "%s", xpath0)) == NULL){
fprintf(stderr, "Error: xpath0 returned NULL\n");
@@ -202,7 +269,7 @@ main(int argc, char **argv)
else
x = x0;
- /* Parse XML (use nsc == NULL to indicate dont use) */
+ /* Parse XPATH (use nsc == NULL to indicate dont use) */
if (xpath_vec_ctx(x, NULL, xpath, &xc) < 0)
return -1;
/* Print results */