Changed C-API for xml translation/print to other formats.

* Added `skiptop` parameter, if set only apply to children of a node, skip top node
    * default is 0
* Functions are merged, ie removed and replaced with more generic functions
* `xml2json_cbuf()`: Added `skiptop` parameter: `xml2json_cbuf(..., int skiptop)`
* `xml2json()` and `xml2json_cb()` merged into `xml2json_file()` with `skiptop`
    * Replace `xml2json(...)` with `xml2json_file(..., stdout, 0)`
    * Replace `xml2json_cb(...)` with `xml2json_file(..., 0)`
* `clicon_xml2cbuf()`: Added `skiptop` parameter: `clicon_xml2cbuf(..., int skiptop)`
* `xml2cli()`: Added `skiptop` parameter: `xml2cli(..., int skiptop)`
This commit is contained in:
Olof hagsand 2022-06-01 10:48:39 +02:00
parent 724b94137f
commit 43a57dad79
39 changed files with 306 additions and 481 deletions

View file

@ -38,6 +38,21 @@
## 5.8.0 ## 5.8.0
Planned: July 2022 Planned: July 2022
### C/CLI-API changes on existing features
Developers may need to change their code
* Changed C-API for xml translation/print to other formats.
* Added `skiptop` parameter, if set only apply to children of a node, skip top node
* default is 0
* Functions are merged, ie removed and replaced with more generic functions
* `xml2json_cbuf()`: Added `skiptop` parameter: `xml2json_cbuf(..., int skiptop)`
* `xml2json()` and `xml2json_cb()` merged into `xml2json_file()` with `skiptop`
* Replace `xml2json(...)` with `xml2json_file(..., stdout, 0)`
* Replace `xml2json_cb(...)` with `xml2json_file(..., 0)`
* `clicon_xml2cbuf()`: Added `skiptop` parameter: `clicon_xml2cbuf(..., int skiptop)`
* `xml2cli()`: Added `skiptop` parameter: `xml2cli(..., int skiptop)`
## 5.7.0 ## 5.7.0
17 May 2022 17 May 2022

View file

@ -366,7 +366,7 @@ from_client_edit_config(clicon_handle h,
if ((ret = xml_bind_yang(xc, YB_MODULE, yspec, &xret)) < 0) if ((ret = xml_bind_yang(xc, YB_MODULE, yspec, &xret)) < 0)
goto done; goto done;
if (ret == 0){ if (ret == 0){
if (clicon_xml2cbuf(cbret, xret, 0, 0, -1) < 0) if (clicon_xml2cbuf(cbret, xret, 0, 0, -1, 0) < 0)
goto done; goto done;
goto ok; goto ok;
} }
@ -374,7 +374,7 @@ from_client_edit_config(clicon_handle h,
if ((ret = xml_non_config_data(xc, &xret)) < 0) if ((ret = xml_non_config_data(xc, &xret)) < 0)
goto done; goto done;
if (ret == 0){ if (ret == 0){
if (clicon_xml2cbuf(cbret, xret, 0, 0, -1) < 0) if (clicon_xml2cbuf(cbret, xret, 0, 0, -1, 0) < 0)
goto done; goto done;
goto ok; goto ok;
} }
@ -387,7 +387,7 @@ from_client_edit_config(clicon_handle h,
if ((ret = xml_yang_validate_list_key_only(xc, &xret)) < 0) if ((ret = xml_yang_validate_list_key_only(xc, &xret)) < 0)
goto done; goto done;
if (ret == 0){ if (ret == 0){
if (clicon_xml2cbuf(cbret, xret, 0, 0, -1) < 0) if (clicon_xml2cbuf(cbret, xret, 0, 0, -1, 0) < 0)
goto done; goto done;
goto ok; goto ok;
} }
@ -1241,7 +1241,7 @@ from_client_msg(clicon_handle h,
goto reply; goto reply;
} }
if (ret == 0){ if (ret == 0){
if (clicon_xml2cbuf(cbret, xret, 0, 0, -1) < 0) if (clicon_xml2cbuf(cbret, xret, 0, 0, -1, 0) < 0)
goto done; goto done;
goto reply; goto reply;
} }
@ -1303,7 +1303,7 @@ from_client_msg(clicon_handle h,
if ((ret = xml_yang_validate_rpc(h, x, &xret)) < 0) if ((ret = xml_yang_validate_rpc(h, x, &xret)) < 0)
goto done; goto done;
if (ret == 0){ if (ret == 0){
if (clicon_xml2cbuf(cbret, xret, 0, 0, -1) < 0) if (clicon_xml2cbuf(cbret, xret, 0, 0, -1, 0) < 0)
goto done; goto done;
goto reply; goto reply;
} }

View file

@ -216,7 +216,7 @@ startup_common(clicon_handle h,
* See similar clause below * See similar clause below
*/ */
} }
if (clicon_xml2cbuf(cbret, xerr, 0, 0, -1) < 0) if (clicon_xml2cbuf(cbret, xerr, 0, 0, -1, 0) < 0)
goto done; goto done;
goto fail; goto fail;
} }
@ -276,7 +276,7 @@ startup_common(clicon_handle h,
if ((ret = xml_bind_yang(xt, YB_MODULE, yspec, &xret)) < 0) if ((ret = xml_bind_yang(xt, YB_MODULE, yspec, &xret)) < 0)
goto done; goto done;
if (ret == 0){ if (ret == 0){
if (clicon_xml2cbuf(cbret, xret, 0, 0, -1) < 0) if (clicon_xml2cbuf(cbret, xret, 0, 0, -1, 0) < 0)
goto done; goto done;
goto fail; goto fail;
} }
@ -284,7 +284,7 @@ startup_common(clicon_handle h,
if ((ret = xml_non_config_data(xt, &xret)) < 0) if ((ret = xml_non_config_data(xt, &xret)) < 0)
goto done; goto done;
if (ret == 0){ if (ret == 0){
if (clicon_xml2cbuf(cbret, xret, 0, 0, -1) < 0) if (clicon_xml2cbuf(cbret, xret, 0, 0, -1, 0) < 0)
goto done; goto done;
goto fail; goto fail;
} }
@ -319,7 +319,7 @@ startup_common(clicon_handle h,
if ((ret = generic_validate(h, yspec, td, &xret)) < 0) if ((ret = generic_validate(h, yspec, td, &xret)) < 0)
goto done; goto done;
if (ret == 0){ if (ret == 0){
if (clicon_xml2cbuf(cbret, xret, 0, 0, -1) < 0) if (clicon_xml2cbuf(cbret, xret, 0, 0, -1, 0) < 0)
goto done; goto done;
goto fail; /* STARTUP_INVALID */ goto fail; /* STARTUP_INVALID */
} }
@ -625,7 +625,7 @@ candidate_validate(clicon_handle h,
clicon_err(OE_CFG, EINVAL, "xret is NULL"); clicon_err(OE_CFG, EINVAL, "xret is NULL");
goto done; goto done;
} }
if (clicon_xml2cbuf(cbret, xret, 0, 0, -1) < 0) if (clicon_xml2cbuf(cbret, xret, 0, 0, -1, 0) < 0)
goto done; goto done;
if (!cbuf_len(cbret) && if (!cbuf_len(cbret) &&
netconf_operation_failed(cbret, "application", clicon_err_reason)< 0) netconf_operation_failed(cbret, "application", clicon_err_reason)< 0)
@ -685,7 +685,7 @@ candidate_commit(clicon_handle h,
if ((ret = validate_common(h, db, td, &xret)) < 0) if ((ret = validate_common(h, db, td, &xret)) < 0)
goto done; goto done;
if (ret == 0){ if (ret == 0){
if (clicon_xml2cbuf(cbret, xret, 0, 0, -1) < 0) if (clicon_xml2cbuf(cbret, xret, 0, 0, -1, 0) < 0)
goto done; goto done;
goto fail; goto fail;
} }
@ -957,7 +957,7 @@ from_client_restart_one(clicon_handle h,
if ((ret = xml_yang_validate_all_top(h, td->td_target, &xerr)) < 0) if ((ret = xml_yang_validate_all_top(h, td->td_target, &xerr)) < 0)
goto done; goto done;
if (ret == 0){ if (ret == 0){
if (clicon_xml2cbuf(cbret, xerr, 0, 0, -1) < 0) if (clicon_xml2cbuf(cbret, xerr, 0, 0, -1, 0) < 0)
goto done; goto done;
goto fail; goto fail;
} }
@ -1007,7 +1007,7 @@ from_client_restart_one(clicon_handle h,
if ((ret = generic_validate(h, yspec, td, &xerr)) < 0) if ((ret = generic_validate(h, yspec, td, &xerr)) < 0)
goto done; goto done;
if (ret == 0){ if (ret == 0){
if (clicon_xml2cbuf(cbret, xerr, 0, 0, -1) < 0) if (clicon_xml2cbuf(cbret, xerr, 0, 0, -1, 0) < 0)
goto done; goto done;
goto fail; goto fail;
} }

View file

@ -365,7 +365,7 @@ get_nacm_and_reply(clicon_handle h,
if (xml_name_set(xret, NETCONF_OUTPUT_DATA) < 0) if (xml_name_set(xret, NETCONF_OUTPUT_DATA) < 0)
goto done; goto done;
/* Top level is data, so add 1 to depth if significant */ /* Top level is data, so add 1 to depth if significant */
if (clicon_xml2cbuf(cbret, xret, 0, 0, depth>0?depth+1:depth) < 0) if (clicon_xml2cbuf(cbret, xret, 0, 0, depth>0?depth+1:depth, 0) < 0)
goto done; goto done;
} }
cprintf(cbret, "</rpc-reply>"); cprintf(cbret, "</rpc-reply>");
@ -605,7 +605,7 @@ get_list_pagination(clicon_handle h,
clicon_err_reason); clicon_err_reason);
if (netconf_operation_failed_xml(&xerr, "application", cbuf_get(cberr)) < 0) if (netconf_operation_failed_xml(&xerr, "application", cbuf_get(cberr)) < 0)
goto done; goto done;
if (clicon_xml2cbuf(cbret, xerr, 0, 0, -1) < 0) if (clicon_xml2cbuf(cbret, xerr, 0, 0, -1, 0) < 0)
goto done; goto done;
goto ok; goto ok;
} }
@ -620,7 +620,7 @@ get_list_pagination(clicon_handle h,
". Internal error, state callback returned invalid XML", ". Internal error, state callback returned invalid XML",
NULL) < 0) NULL) < 0)
goto done; goto done;
if (clicon_xml2cbuf(cbret, xerr, 0, 0, -1) < 0) if (clicon_xml2cbuf(cbret, xerr, 0, 0, -1, 0) < 0)
goto done; goto done;
goto ok; goto ok;
} }
@ -832,7 +832,7 @@ get_common(clicon_handle h,
if ((ret = get_client_statedata(h, xpath?xpath:"/", nsc, &xret)) < 0) if ((ret = get_client_statedata(h, xpath?xpath:"/", nsc, &xret)) < 0)
goto done; goto done;
if (ret == 0){ /* Error from callback (error in xret) */ if (ret == 0){ /* Error from callback (error in xret) */
if (clicon_xml2cbuf(cbret, xret, 0, 0, -1) < 0) if (clicon_xml2cbuf(cbret, xret, 0, 0, -1, 0) < 0)
goto done; goto done;
goto ok; goto ok;
} }
@ -857,7 +857,7 @@ get_common(clicon_handle h,
". Internal error, state callback returned invalid XML", ". Internal error, state callback returned invalid XML",
NULL) < 0) NULL) < 0)
goto done; goto done;
if (clicon_xml2cbuf(cbret, xerr, 0, 0, -1) < 0) if (clicon_xml2cbuf(cbret, xerr, 0, 0, -1, 0) < 0)
goto done; goto done;
goto ok; goto ok;
} }

View file

@ -163,7 +163,7 @@ restconf_pseudo_set_inline(clicon_handle h,
clicon_err(OE_XML, errno, "cbuf_new"); clicon_err(OE_XML, errno, "cbuf_new");
goto done; goto done;
} }
if (clicon_xml2cbuf(cb, xrestconf, 0, 0, -1) < 0) if (clicon_xml2cbuf(cb, xrestconf, 0, 0, -1, 0) < 0)
goto done; goto done;
if ((str = strdup(cbuf_get(cb))) == NULL){ if ((str = strdup(cbuf_get(cb))) == NULL){
clicon_err(OE_XML, errno, "stdup"); clicon_err(OE_XML, errno, "stdup");

View file

@ -256,7 +256,7 @@ transaction_log(clicon_handle h,
} }
for (i=0; i<td->td_dlen; i++){ for (i=0; i<td->td_dlen; i++){
xn = td->td_dvec[i]; xn = td->td_dvec[i];
clicon_xml2cbuf(cb, xn, 0, 0, -1); clicon_xml2cbuf(cb, xn, 0, 0, -1, 0);
} }
if (i) if (i)
clicon_log(level, "%s %" PRIu64 " %s del: %s", clicon_log(level, "%s %" PRIu64 " %s del: %s",
@ -264,7 +264,7 @@ transaction_log(clicon_handle h,
cbuf_reset(cb); cbuf_reset(cb);
for (i=0; i<td->td_alen; i++){ for (i=0; i<td->td_alen; i++){
xn = td->td_avec[i]; xn = td->td_avec[i];
clicon_xml2cbuf(cb, xn, 0, 0, -1); clicon_xml2cbuf(cb, xn, 0, 0, -1, 0);
} }
if (i) if (i)
clicon_log(level, "%s %" PRIu64 " %s add: %s", __FUNCTION__, td->td_id, op, cbuf_get(cb)); clicon_log(level, "%s %" PRIu64 " %s add: %s", __FUNCTION__, td->td_id, op, cbuf_get(cb));
@ -272,10 +272,10 @@ transaction_log(clicon_handle h,
for (i=0; i<td->td_clen; i++){ for (i=0; i<td->td_clen; i++){
if (td->td_scvec){ if (td->td_scvec){
xn = td->td_scvec[i]; xn = td->td_scvec[i];
clicon_xml2cbuf(cb, xn, 0, 0, -1); clicon_xml2cbuf(cb, xn, 0, 0, -1, 0);
} }
xn = td->td_tcvec[i]; xn = td->td_tcvec[i];
clicon_xml2cbuf(cb, xn, 0, 0, -1); clicon_xml2cbuf(cb, xn, 0, 0, -1, 0);
} }
if (i) if (i)
clicon_log(level, "%s %" PRIu64 " %s change: %s", __FUNCTION__, td->td_id, op, cbuf_get(cb)); clicon_log(level, "%s %" PRIu64 " %s change: %s", __FUNCTION__, td->td_id, op, cbuf_get(cb));

View file

@ -651,12 +651,8 @@ cli_auto_show(clicon_handle h,
fprintf(stdout, "\n"); fprintf(stdout, "\n");
break; break;
case FORMAT_JSON: case FORMAT_JSON:
if (isroot) if (xml2json_file(stdout, xp, pretty, cligen_output, !isroot) < 0)
xml2json_cb(stdout, xp, pretty, cligen_output); goto done;
else{
while ((xc = xml_child_each(xp, xc, CX_ELMNT)) != NULL)
xml2json_cb(stdout, xc, pretty, cligen_output);
}
fprintf(stdout, "\n"); fprintf(stdout, "\n");
break; break;
case FORMAT_TEXT: case FORMAT_TEXT:
@ -667,11 +663,8 @@ cli_auto_show(clicon_handle h,
cli_xml2txt(xc, cligen_output, 0); /* tree-formed text */ cli_xml2txt(xc, cligen_output, 0); /* tree-formed text */
break; break;
case FORMAT_CLI: case FORMAT_CLI:
if (isroot) if (xml2cli(h, stdout, xp, prefix, cligen_output, !isroot) < 0)
xml2cli(h, stdout, xp, prefix, cligen_output); goto done;
else
while ((xc = xml_child_each(xp, xc, CX_ELMNT)) != NULL)
xml2cli(h, stdout, xc, prefix, cligen_output);
break; break;
case FORMAT_NETCONF: case FORMAT_NETCONF:
fprintf(stdout, "<rpc xmlns=\"%s\" %s><edit-config><target><candidate/></target><config>", fprintf(stdout, "<rpc xmlns=\"%s\" %s><edit-config><target><candidate/></target><config>",

View file

@ -325,7 +325,7 @@ cli_dbxml(clicon_handle h,
clicon_err(OE_XML, errno, "cbuf_new"); clicon_err(OE_XML, errno, "cbuf_new");
goto done; goto done;
} }
if (clicon_xml2cbuf(cb, xtop, 0, 0, -1) < 0) if (clicon_xml2cbuf(cb, xtop, 0, 0, -1, 0) < 0)
goto done; goto done;
if (clicon_rpc_edit_config(h, "candidate", OP_NONE, cbuf_get(cb)) < 0) if (clicon_rpc_edit_config(h, "candidate", OP_NONE, cbuf_get(cb)) < 0)
goto done; goto done;
@ -925,9 +925,9 @@ load_config_file(clicon_handle h,
while ((x = xml_child_each(xt, x, -1)) != NULL) { while ((x = xml_child_each(xt, x, -1)) != NULL) {
/* Read as datastore-top but transformed into an edit-config "config" */ /* Read as datastore-top but transformed into an edit-config "config" */
xml_name_set(x, NETCONF_INPUT_CONFIG); xml_name_set(x, NETCONF_INPUT_CONFIG);
if (clicon_xml2cbuf(cbxml, x, 0, 0, -1) < 0)
goto done;
} }
if (clicon_xml2cbuf(cbxml, xt, 0, 0, -1, 1) < 0)
goto done;
if (clicon_rpc_edit_config(h, "candidate", if (clicon_rpc_edit_config(h, "candidate",
replace?OP_REPLACE:OP_MERGE, replace?OP_REPLACE:OP_MERGE,
cbuf_get(cbxml)) < 0) cbuf_get(cbxml)) < 0)
@ -973,7 +973,6 @@ save_config_file(clicon_handle h,
char *dbstr; char *dbstr;
char *varstr; char *varstr;
cxobj *xt = NULL; cxobj *xt = NULL;
cxobj *x;
cxobj *xerr; cxobj *xerr;
FILE *f = NULL; FILE *f = NULL;
char *formatstr; char *formatstr;
@ -1031,7 +1030,7 @@ save_config_file(clicon_handle h,
goto done; goto done;
break; break;
case FORMAT_JSON: case FORMAT_JSON:
if (xml2json(f, xt, pretty) < 0) if (xml2json_file(f, xt, pretty, fprintf, 0) < 0)
goto done; goto done;
break; break;
case FORMAT_TEXT: case FORMAT_TEXT:
@ -1039,11 +1038,8 @@ save_config_file(clicon_handle h,
goto done; goto done;
break; break;
case FORMAT_CLI: case FORMAT_CLI:
x = NULL; if (xml2cli(h, f, xt, prefix, fprintf, 1) < 0)
while ((x = xml_child_each(xt, x, CX_ELMNT)) != NULL) {
if (xml2cli(h, f, x, prefix, fprintf) < 0)
goto done; goto done;
}
break; break;
case FORMAT_NETCONF: case FORMAT_NETCONF:
fprintf(f, "<rpc xmlns=\"%s\" %s><edit-config><target><candidate/></target>", fprintf(f, "<rpc xmlns=\"%s\" %s><edit-config><target><candidate/></target>",
@ -1153,6 +1149,13 @@ cli_notification_cb(int s,
clicon_err(OE_NETCONF, EFAULT, "Notification malformed"); clicon_err(OE_NETCONF, EFAULT, "Notification malformed");
goto done; goto done;
} }
switch (format){
case FORMAT_JSON:
if (xml2json_file(stdout, xt, 1, cligen_output, 1) < 0)
goto done;
default:
break;
}
if ((xe = xpath_first(xt, NULL, "//event")) != NULL){ if ((xe = xpath_first(xt, NULL, "//event")) != NULL){
x = NULL; x = NULL;
while ((x = xml_child_each(xe, x, -1)) != NULL) { while ((x = xml_child_each(xe, x, -1)) != NULL) {
@ -1165,10 +1168,6 @@ cli_notification_cb(int s,
if (xml2txt_cb(stdout, x, cligen_output) < 0) if (xml2txt_cb(stdout, x, cligen_output) < 0)
goto done; goto done;
break; break;
case FORMAT_JSON:
if (xml2json_cb(stdout, x, 1, cligen_output) < 0)
goto done;
break;
default: default:
break; break;
} }
@ -1417,7 +1416,7 @@ cli_copy_config(clicon_handle h,
/* resuse cb */ /* resuse cb */
cbuf_reset(cb); cbuf_reset(cb);
/* create xml copy tree and merge it with database configuration */ /* create xml copy tree and merge it with database configuration */
clicon_xml2cbuf(cb, x2, 0, 0, -1); clicon_xml2cbuf(cb, x2, 0, 0, -1, 0);
if (clicon_rpc_edit_config(h, db, OP_MERGE, cbuf_get(cb)) < 0) if (clicon_rpc_edit_config(h, db, OP_MERGE, cbuf_get(cb)) < 0)
goto done; goto done;
retval = 0; retval = 0;

View file

@ -500,7 +500,7 @@ cli_show_config1(clicon_handle h,
cli_xml2file(xc, 0, 1, cligen_output); cli_xml2file(xc, 0, 1, cligen_output);
break; break;
case FORMAT_JSON: case FORMAT_JSON:
xml2json_cb(stdout, xt, 1, cligen_output); xml2json_file(stdout, xt, 1, cligen_output, 0);
break; break;
case FORMAT_TEXT: case FORMAT_TEXT:
xc = NULL; /* Dont print xt itself */ xc = NULL; /* Dont print xt itself */
@ -508,9 +508,7 @@ cli_show_config1(clicon_handle h,
cli_xml2txt(xc, cligen_output, 0); /* tree-formed text */ cli_xml2txt(xc, cligen_output, 0); /* tree-formed text */
break; break;
case FORMAT_CLI: case FORMAT_CLI:
xc = NULL; /* Dont print xt itself */ if (xml2cli(h, stdout, xt, prefix, cligen_output, 1) < 0)
while ((xc = xml_child_each(xt, xc, CX_ELMNT)) != NULL)
if (xml2cli(h, stdout, xc, prefix, cligen_output) < 0)
goto done; goto done;
break; break;
case FORMAT_NETCONF: case FORMAT_NETCONF:
@ -773,7 +771,7 @@ cli_show_generated(clicon_handle h,
switch (format){ switch (format){
case FORMAT_CLI: case FORMAT_CLI:
if (xml2cli(h, stdout, xp, prefix, cligen_output) < 0) /* cli syntax */ if (xml2cli(h, stdout, xp, prefix, cligen_output, 0) < 0) /* cli syntax */
goto done; goto done;
break; break;
case FORMAT_NETCONF: case FORMAT_NETCONF:
@ -781,15 +779,15 @@ cli_show_generated(clicon_handle h,
cli_xml2file(xp, 2, 1, fprintf); cli_xml2file(xp, 2, 1, fprintf);
fprintf(stdout, "</config></edit-config></rpc>]]>]]>\n"); fprintf(stdout, "</config></edit-config></rpc>]]>]]>\n");
break; break;
case FORMAT_JSON:
xml2json_file(stdout, xp_helper, 1, cligen_output, 1);
break;
default: default:
for (; i < xml_child_nr(xml_parent(xp)) ; ++i, xp_helper = xml_child_i(xml_parent(xp), i)) { for (; i < xml_child_nr(xml_parent(xp)) ; ++i, xp_helper = xml_child_i(xml_parent(xp), i)) {
switch (format){ switch (format){
case FORMAT_XML: case FORMAT_XML:
cli_xml2file(xp_helper, 0, 1, fprintf); cli_xml2file(xp_helper, 0, 1, fprintf);
break; break;
case FORMAT_JSON:
xml2json_cb(stdout, xp_helper, 1, cligen_output);
break;
case FORMAT_TEXT: case FORMAT_TEXT:
cli_xml2txt(xp_helper, cligen_output, 0); /* tree-formed text */ cli_xml2txt(xp_helper, cligen_output, 0); /* tree-formed text */
break; break;
@ -985,14 +983,14 @@ cli_pagination(clicon_handle h,
clicon_xml2file_cb(stdout, xc, 0, 1, cligen_output); clicon_xml2file_cb(stdout, xc, 0, 1, cligen_output);
break; break;
case FORMAT_JSON: case FORMAT_JSON:
xml2json_cb(stdout, xc, 1, cligen_output); xml2json_file(stdout, xc, 1, cligen_output, 0);
break; break;
case FORMAT_TEXT: case FORMAT_TEXT:
xml2txt_cb(stdout, xc, cligen_output); /* tree-formed text */ xml2txt_cb(stdout, xc, cligen_output); /* tree-formed text */
break; break;
case FORMAT_CLI: case FORMAT_CLI:
/* hardcoded to compress and list-keyword = nokey */ /* hardcoded to compress and list-keyword = nokey */
xml2cli(h, stdout, xc, NULL, cligen_output); xml2cli(h, stdout, xc, NULL, cligen_output, 0);
break; break;
default: default:
break; break;
@ -1028,7 +1026,7 @@ cli_pagination(clicon_handle h,
return retval; return retval;
} }
/*! Translate from XML to CLI commands /*! Translate from XML to CLI commands, internal
* *
* Howto: join strings and pass them down. * Howto: join strings and pass them down.
* Identify unique/index keywords for correct set syntax. * Identify unique/index keywords for correct set syntax.
@ -1037,10 +1035,9 @@ cli_pagination(clicon_handle h,
* @param[in] xn XML Parse-tree (to translate) * @param[in] xn XML Parse-tree (to translate)
* @param[in] prepend Print this text in front of all commands. * @param[in] prepend Print this text in front of all commands.
* @param[in] fn Callback to make print function * @param[in] fn Callback to make print function
* @see xml2cli XXX should probably use the generic function
*/ */
int static int
xml2cli(clicon_handle h, xml2cli1(clicon_handle h,
FILE *f, FILE *f,
cxobj *xn, cxobj *xn,
char *prepend, char *prepend,
@ -1139,7 +1136,7 @@ xml2cli(clicon_handle h,
if (match) if (match)
continue; /* Not key itself */ continue; /* Not key itself */
} }
if (xml2cli(h, f, xe, cbuf_get(cbpre), fn) < 0) if (xml2cli1(h, f, xe, cbuf_get(cbpre), fn) < 0)
goto done; goto done;
} }
ok: ok:
@ -1149,3 +1146,41 @@ xml2cli(clicon_handle h,
cbuf_free(cbpre); cbuf_free(cbpre);
return retval; return retval;
} }
/*! Translate from XML to CLI commands
*
* Howto: join strings and pass them down.
* Identify unique/index keywords for correct set syntax.
* @param[in] h Clicon handle
* @param[in] f Output FILE (eg stdout)
* @param[in] xn XML Parse-tree (to translate)
* @param[in] prepend Print this text in front of all commands.
* @param[in] fn Callback to make print function
* @param[in] skiptop 0: Include top object 1: Skip top-object, only children,
*/
int
xml2cli(clicon_handle h,
FILE *f,
cxobj *xn,
char *prepend,
clicon_output_cb *fn,
int skiptop)
{
int retval = 1;
cxobj *xc;
if (skiptop){
xc = NULL;
while ((xc = xml_child_each(xn, xc, CX_ELMNT)) != NULL)
if (xml2cli1(h, f, xc, prepend, fn) < 0)
goto done;
}
else {
if (xml2cli1(h, f, xn, prepend, fn) < 0)
goto done;
}
retval = 0;
done:
return retval;
}

View file

@ -137,7 +137,7 @@ int expand_dbvar(void *h, char *name, cvec *cvv, cvec *argv,
cvec *commands, cvec *helptexts); cvec *commands, cvec *helptexts);
int cli_xml2file (cxobj *xn, int level, int prettyprint, clicon_output_cb *fn); int cli_xml2file (cxobj *xn, int level, int prettyprint, clicon_output_cb *fn);
int cli_xml2txt(cxobj *xn, clicon_output_cb *fn, int level); int cli_xml2txt(cxobj *xn, clicon_output_cb *fn, int level);
int xml2cli(clicon_handle h, FILE *f, cxobj *xn, char *prepend, clicon_output_cb *fn); int xml2cli(clicon_handle h, FILE *f, cxobj *xn, char *prepend, clicon_output_cb *fn, int skiptop);
/* cli_show.c: CLIgen new vector arg callbacks */ /* cli_show.c: CLIgen new vector arg callbacks */
int show_yang(clicon_handle h, cvec *vars, cvec *argv); int show_yang(clicon_handle h, cvec *vars, cvec *argv);

View file

@ -211,7 +211,7 @@ netconf_rpc_message(clicon_handle h,
clicon_err(OE_XML, errno, "cbuf_new"); clicon_err(OE_XML, errno, "cbuf_new");
goto done; goto done;
} }
clicon_xml2cbuf(cbret, xret, 0, 0, -1); clicon_xml2cbuf(cbret, xret, 0, 0, -1, 0);
if (netconf_output_encap(framing, cbret) < 0) if (netconf_output_encap(framing, cbret) < 0)
goto done; goto done;
if (netconf_output(1, cbret, "rpc-error") < 0) if (netconf_output(1, cbret, "rpc-error") < 0)
@ -231,7 +231,7 @@ netconf_rpc_message(clicon_handle h,
clicon_err(OE_XML, errno, "cbuf_new"); clicon_err(OE_XML, errno, "cbuf_new");
goto done; goto done;
} }
clicon_xml2cbuf(cbret, xret, 0, 0, -1); clicon_xml2cbuf(cbret, xret, 0, 0, -1, 0);
if (netconf_output_encap(framing, cbret) < 0) if (netconf_output_encap(framing, cbret) < 0)
goto done; goto done;
if (netconf_output(1, cbret, "rpc-error") < 0) if (netconf_output(1, cbret, "rpc-error") < 0)
@ -251,7 +251,7 @@ netconf_rpc_message(clicon_handle h,
clicon_err(OE_XML, errno, "cbuf_new"); clicon_err(OE_XML, errno, "cbuf_new");
goto done; goto done;
} }
clicon_xml2cbuf(cbret, xret, 0, 0, -1); clicon_xml2cbuf(cbret, xret, 0, 0, -1, 0);
if (netconf_output_encap(framing, cbret) < 0) if (netconf_output_encap(framing, cbret) < 0)
goto done; goto done;
if (netconf_output(1, cbret, "rpc-error") < 0) if (netconf_output(1, cbret, "rpc-error") < 0)
@ -266,7 +266,7 @@ netconf_rpc_message(clicon_handle h,
clicon_err(OE_XML, errno, "cbuf_new"); clicon_err(OE_XML, errno, "cbuf_new");
goto done; goto done;
} }
clicon_xml2cbuf(cbret, xml_child_i(xret,0), 0, 0, -1); clicon_xml2cbuf(cbret, xml_child_i(xret,0), 0, 0, -1, 0);
if (netconf_output_encap(framing, cbret) < 0) if (netconf_output_encap(framing, cbret) < 0)
goto done; goto done;
if (netconf_output(1, cbret, "rpc-reply") < 0) if (netconf_output(1, cbret, "rpc-reply") < 0)
@ -322,7 +322,7 @@ netconf_input_packet(clicon_handle h,
clicon_err(OE_XML, errno, "cbuf_new"); clicon_err(OE_XML, errno, "cbuf_new");
goto done; goto done;
} }
clicon_xml2cbuf(cbret, xret, 0, 0, -1); clicon_xml2cbuf(cbret, xret, 0, 0, -1, 0);
if (netconf_output_encap(framing, cbret) < 0) if (netconf_output_encap(framing, cbret) < 0)
goto done; goto done;
if (netconf_output(1, cbret, "rpc-error") < 0) if (netconf_output(1, cbret, "rpc-error") < 0)
@ -435,7 +435,7 @@ netconf_input_frame(clicon_handle h,
clicon_err(OE_XML, errno, "cbuf_new"); clicon_err(OE_XML, errno, "cbuf_new");
goto done; goto done;
} }
clicon_xml2cbuf(cbret, xret, 0, 0, -1); clicon_xml2cbuf(cbret, xret, 0, 0, -1, 0);
if (netconf_output_encap(framing, cbret) < 0) if (netconf_output_encap(framing, cbret) < 0)
goto done; goto done;
if (netconf_output(1, cbret, "rpc-error") < 0) if (netconf_output(1, cbret, "rpc-error") < 0)

View file

@ -481,7 +481,7 @@ netconf_notification_cb(int s,
clicon_err(OE_PLUGIN, errno, "cbuf_new"); clicon_err(OE_PLUGIN, errno, "cbuf_new");
goto done; goto done;
} }
if (clicon_xml2cbuf(cb, xn, 0, 0, -1) < 0) if (clicon_xml2cbuf(cb, xn, 0, 0, -1, 0) < 0)
goto done; goto done;
/* Send it to listening client on stdout */ /* Send it to listening client on stdout */
if (netconf_output_encap(clicon_option_int(h, "netconf-framing"), cb) < 0){ if (netconf_output_encap(clicon_option_int(h, "netconf-framing"), cb) < 0){
@ -659,7 +659,7 @@ netconf_application_rpc(clicon_handle h,
if (ret > 0 && (ret = xml_yang_validate_add(h, xoutput, &xerr)) < 0) if (ret > 0 && (ret = xml_yang_validate_add(h, xoutput, &xerr)) < 0)
goto done; goto done;
if (ret == 0){ if (ret == 0){
if (clicon_xml2cbuf(cbret, xerr, 0, 0, -1) < 0) if (clicon_xml2cbuf(cbret, xerr, 0, 0, -1, 0) < 0)
goto done; goto done;
clicon_log(LOG_WARNING, "Errors in output netconf %s", cbuf_get(cbret)); clicon_log(LOG_WARNING, "Errors in output netconf %s", cbuf_get(cbret));
goto ok; goto ok;

View file

@ -279,13 +279,13 @@ api_return_err(clicon_handle h,
clicon_debug(1, "%s code:%d", __FUNCTION__, code); clicon_debug(1, "%s code:%d", __FUNCTION__, code);
if (pretty){ if (pretty){
cprintf(cb, " <errors xmlns=\"urn:ietf:params:xml:ns:yang:ietf-restconf\">\n"); cprintf(cb, " <errors xmlns=\"urn:ietf:params:xml:ns:yang:ietf-restconf\">\n");
if (clicon_xml2cbuf(cb, xerr, 2, pretty, -1) < 0) if (clicon_xml2cbuf(cb, xerr, 2, pretty, -1, 0) < 0)
goto done; goto done;
cprintf(cb, " </errors>\r\n"); cprintf(cb, " </errors>\r\n");
} }
else { else {
cprintf(cb, "<errors xmlns=\"urn:ietf:params:xml:ns:yang:ietf-restconf\">"); cprintf(cb, "<errors xmlns=\"urn:ietf:params:xml:ns:yang:ietf-restconf\">");
if (clicon_xml2cbuf(cb, xerr, 2, pretty, -1) < 0) if (clicon_xml2cbuf(cb, xerr, 2, pretty, -1, 0) < 0)
goto done; goto done;
cprintf(cb, "</errors>\r\n"); cprintf(cb, "</errors>\r\n");
} }
@ -295,14 +295,14 @@ api_return_err(clicon_handle h,
clicon_debug(1, "%s code:%d", __FUNCTION__, code); clicon_debug(1, "%s code:%d", __FUNCTION__, code);
if (pretty){ if (pretty){
cprintf(cb, "{\n\"ietf-restconf:errors\" : "); cprintf(cb, "{\n\"ietf-restconf:errors\" : ");
if (xml2json_cbuf(cb, xerr, pretty) < 0) if (xml2json_cbuf(cb, xerr, pretty, 0) < 0)
goto done; goto done;
cprintf(cb, "\n}\r\n"); cprintf(cb, "\n}\r\n");
} }
else{ else{
cprintf(cb, "{"); cprintf(cb, "{");
cprintf(cb, "\"ietf-restconf:errors\":"); cprintf(cb, "\"ietf-restconf:errors\":");
if (xml2json_cbuf(cb, xerr, pretty) < 0) if (xml2json_cbuf(cb, xerr, pretty, 0) < 0)
goto done; goto done;
cprintf(cb, "}\r\n"); cprintf(cb, "}\r\n");
} }

View file

@ -537,7 +537,7 @@ api_data_write(clicon_handle h,
cprintf(cbx, " autocommit=\"true\""); cprintf(cbx, " autocommit=\"true\"");
cprintf(cbx, "><target><candidate /></target>"); cprintf(cbx, "><target><candidate /></target>");
cprintf(cbx, "<default-operation>none</default-operation>"); cprintf(cbx, "<default-operation>none</default-operation>");
if (clicon_xml2cbuf(cbx, xtop, 0, 0, -1) < 0) if (clicon_xml2cbuf(cbx, xtop, 0, 0, -1, 0) < 0)
goto done; goto done;
cprintf(cbx, "</edit-config></rpc>"); cprintf(cbx, "</edit-config></rpc>");
clicon_debug(1, "%s xml: %s api_path:%s",__FUNCTION__, cbuf_get(cbx), api_path); clicon_debug(1, "%s xml: %s api_path:%s",__FUNCTION__, cbuf_get(cbx), api_path);
@ -782,7 +782,7 @@ api_data_delete(clicon_handle h,
cprintf(cbx, " autocommit=\"true\""); cprintf(cbx, " autocommit=\"true\"");
cprintf(cbx, "><target><candidate /></target>"); cprintf(cbx, "><target><candidate /></target>");
cprintf(cbx, "<default-operation>none</default-operation>"); cprintf(cbx, "<default-operation>none</default-operation>");
if (clicon_xml2cbuf(cbx, xtop, 0, 0, -1) < 0) if (clicon_xml2cbuf(cbx, xtop, 0, 0, -1, 0) < 0)
goto done; goto done;
cprintf(cbx, "</edit-config></rpc>"); cprintf(cbx, "</edit-config></rpc>");
if (clicon_rpc_netconf(h, cbuf_get(cbx), &xret, NULL) < 0) if (clicon_rpc_netconf(h, cbuf_get(cbx), &xret, NULL) < 0)

View file

@ -225,11 +225,11 @@ api_data_get2(clicon_handle h,
if (xpath==NULL || strcmp(xpath,"/")==0){ /* Special case: data root */ if (xpath==NULL || strcmp(xpath,"/")==0){ /* Special case: data root */
switch (media_out){ switch (media_out){
case YANG_DATA_XML: case YANG_DATA_XML:
if (clicon_xml2cbuf(cbx, xret, 0, pretty, -1) < 0) /* Dont print top object? */ if (clicon_xml2cbuf(cbx, xret, 0, pretty, -1, 0) < 0) /* Dont print top object? */
goto done; goto done;
break; break;
case YANG_DATA_JSON: case YANG_DATA_JSON:
if (xml2json_cbuf(cbx, xret, pretty) < 0) if (xml2json_cbuf(cbx, xret, pretty, 0) < 0)
goto done; goto done;
break; break;
default: default:
@ -270,7 +270,7 @@ api_data_get2(clicon_handle h,
if (namespace && xmlns_set(x, prefix, namespace) < 0) if (namespace && xmlns_set(x, prefix, namespace) < 0)
goto done; goto done;
} }
if (clicon_xml2cbuf(cbx, x, 0, pretty, -1) < 0) /* Dont print top object? */ if (clicon_xml2cbuf(cbx, x, 0, pretty, -1, 0) < 0) /* Dont print top object? */
goto done; goto done;
} }
break; break;
@ -535,7 +535,7 @@ api_data_pagination(clicon_handle h,
if (xml_insert(xpr, xp, INS_LAST, NULL, NULL) < 0) if (xml_insert(xpr, xp, INS_LAST, NULL, NULL) < 0)
goto done; goto done;
} }
if (clicon_xml2cbuf(cbx, xpr, 0, pretty, -1) < 0) /* Dont print top object? */ if (clicon_xml2cbuf(cbx, xpr, 0, pretty, -1, 0) < 0) /* Dont print top object? */
goto done; goto done;
break; break;
case YANG_DATA_JSON: case YANG_DATA_JSON:

View file

@ -119,7 +119,7 @@ yang_patch_xml2json_modified_cbuf(cxobj *x_simple_patch)
if (json_simple_patch == NULL) if (json_simple_patch == NULL)
return NULL; return NULL;
cb = cbuf_new(); cb = cbuf_new();
xml2json_cbuf(cb, x_simple_patch, 1); xml2json_cbuf(cb, x_simple_patch, 0);
// Insert a '[' after the first '{' to get the JSON to match what api_data_post/write() expect // Insert a '[' after the first '{' to get the JSON to match what api_data_post/write() expect
json_simple_patch_tmp = cbuf_get(cb); json_simple_patch_tmp = cbuf_get(cb);
@ -266,7 +266,7 @@ yang_patch_do_replace(clicon_handle h,
} }
} }
// Convert the data to json // Convert the data to json
xml2json_cbuf(json_simple_patch, x_simple_patch, 1); xml2json_cbuf(json_simple_patch, x_simple_patch, 0);
// Send the POST request // Send the POST request
if (api_data_post(h, req, cbuf_get(simple_patch_request_uri), pi, qvec, cbuf_get(json_simple_patch), pretty, YANG_DATA_JSON, media_out, ds ) < 0) if (api_data_post(h, req, cbuf_get(simple_patch_request_uri), pi, qvec, cbuf_get(json_simple_patch), pretty, YANG_DATA_JSON, media_out, ds ) < 0)
@ -327,7 +327,7 @@ yang_patch_do_create(clicon_handle h,
xml_addsub(x_simple_patch, value_vec_tmp); xml_addsub(x_simple_patch, value_vec_tmp);
} }
} }
if (xml2json_cbuf(cb, x_simple_patch, 1) < 0) if (xml2json_cbuf(cb, x_simple_patch, 0) < 0)
goto done; goto done;
if (api_data_post(h, req, cbuf_get(simple_patch_request_uri), if (api_data_post(h, req, cbuf_get(simple_patch_request_uri),
pi, qvec, pi, qvec,
@ -477,7 +477,7 @@ yang_patch_do_merge(clicon_handle h,
xml_addsub(x_simple_patch, value_vec_tmp); xml_addsub(x_simple_patch, value_vec_tmp);
} }
cbuf_reset(cb); /* reuse cb */ cbuf_reset(cb); /* reuse cb */
xml2json_cbuf(cb, x_simple_patch, 1); xml2json_cbuf(cb, x_simple_patch, 0);
if ((json_simple_patch = yang_patch_xml2json_modified_cbuf(x_simple_patch)) == NULL) if ((json_simple_patch = yang_patch_xml2json_modified_cbuf(x_simple_patch)) == NULL)
goto done; goto done;

View file

@ -360,7 +360,7 @@ api_data_post(clicon_handle h,
cprintf(cbx, " autocommit=\"true\""); cprintf(cbx, " autocommit=\"true\"");
cprintf(cbx, "><target><candidate /></target>"); cprintf(cbx, "><target><candidate /></target>");
cprintf(cbx, "<default-operation>none</default-operation>"); cprintf(cbx, "<default-operation>none</default-operation>");
if (clicon_xml2cbuf(cbx, xtop, 0, 0, -1) < 0) if (clicon_xml2cbuf(cbx, xtop, 0, 0, -1, 0) < 0)
goto done; goto done;
cprintf(cbx, "</edit-config></rpc>"); cprintf(cbx, "</edit-config></rpc>");
clicon_debug(1, "%s xml: %s api_path:%s",__FUNCTION__, cbuf_get(cbx), api_path); clicon_debug(1, "%s xml: %s api_path:%s",__FUNCTION__, cbuf_get(cbx), api_path);
@ -874,12 +874,12 @@ api_operations_post(clicon_handle h,
cbuf_reset(cbret); cbuf_reset(cbret);
switch (media_out){ switch (media_out){
case YANG_DATA_XML: case YANG_DATA_XML:
if (clicon_xml2cbuf(cbret, xoutput, 0, pretty, -1) < 0) if (clicon_xml2cbuf(cbret, xoutput, 0, pretty, -1, 0) < 0)
goto done; goto done;
/* xoutput should now look: <output xmlns="uri"><x>0</x></output> */ /* xoutput should now look: <output xmlns="uri"><x>0</x></output> */
break; break;
case YANG_DATA_JSON: case YANG_DATA_JSON:
if (xml2json_cbuf(cbret, xoutput, pretty) < 0) if (xml2json_cbuf(cbret, xoutput, pretty, 0) < 0)
goto done; goto done;
/* xoutput should now look: {"example:output": {"x":0,"y":42}} */ /* xoutput should now look: {"example:output": {"x":0,"y":42}} */
break; break;

View file

@ -204,12 +204,12 @@ api_root_restconf_exact(clicon_handle h,
switch (media_out){ switch (media_out){
case YANG_DATA_XML: case YANG_DATA_XML:
case YANG_PATCH_XML: case YANG_PATCH_XML:
if (clicon_xml2cbuf(cb, xt, 0, pretty, -1) < 0) if (clicon_xml2cbuf(cb, xt, 0, pretty, -1, 0) < 0)
goto done; goto done;
break; break;
case YANG_DATA_JSON: case YANG_DATA_JSON:
case YANG_PATCH_JSON: case YANG_PATCH_JSON:
if (xml2json_cbuf(cb, xt, pretty) < 0) if (xml2json_cbuf(cb, xt, pretty, 0) < 0)
goto done; goto done;
break; break;
default: default:
@ -288,12 +288,12 @@ api_yang_library_version(clicon_handle h,
switch (media_out){ switch (media_out){
case YANG_DATA_XML: case YANG_DATA_XML:
case YANG_PATCH_XML: case YANG_PATCH_XML:
if (clicon_xml2cbuf(cb, xt, 0, pretty, -1) < 0) if (clicon_xml2cbuf(cb, xt, 0, pretty, -1, 0) < 0)
goto done; goto done;
break; break;
case YANG_DATA_JSON: case YANG_DATA_JSON:
case YANG_PATCH_JSON: case YANG_PATCH_JSON:
if (xml2json_cbuf(cb, xt, pretty) < 0) if (xml2json_cbuf(cb, xt, pretty, 0) < 0)
goto done; goto done;
break; break;
default: default:

View file

@ -254,7 +254,7 @@ restconf_stream_cb(int s,
FCGX_FPrintF(r->out, "M#id: %02d:0\r\n", tv.tv_sec); FCGX_FPrintF(r->out, "M#id: %02d:0\r\n", tv.tv_sec);
} }
#endif #endif
if (clicon_xml2cbuf(cb, xn, 0, pretty, -1) < 0) if (clicon_xml2cbuf(cb, xn, 0, pretty, -1, 0) < 0)
goto done; goto done;
FCGX_FPrintF(r->out, "data: %s\r\n", cbuf_get(cb)); FCGX_FPrintF(r->out, "data: %s\r\n", cbuf_get(cb));
FCGX_FPrintF(r->out, "\r\n"); FCGX_FPrintF(r->out, "\r\n");

View file

@ -326,10 +326,12 @@ example_rpc(clicon_handle h, /* Clicon handle */
cprintf(cbret, ">"); cprintf(cbret, ">");
if (!xml_child_nr_type(xe, CX_ELMNT)) if (!xml_child_nr_type(xe, CX_ELMNT))
cprintf(cbret, "<ok/>"); cprintf(cbret, "<ok/>");
else while ((x = xml_child_each(xe, x, CX_ELMNT)) != NULL) { else {
while ((x = xml_child_each(xe, x, CX_ELMNT)) != NULL) {
if (xmlns_set(x, NULL, namespace) < 0) if (xmlns_set(x, NULL, namespace) < 0)
goto done; goto done;
if (clicon_xml2cbuf(cbret, x, 0, 0, -1) < 0) }
if (clicon_xml2cbuf(cbret, xe, 0, 0, -1, 1) < 0)
goto done; goto done;
} }
cprintf(cbret, "</rpc-reply>"); cprintf(cbret, "</rpc-reply>");

View file

@ -85,10 +85,12 @@ netconf_client_rpc(clicon_handle h,
cprintf(cbret, "<rpc-reply xmlns=\"%s\">", NETCONF_BASE_NAMESPACE); cprintf(cbret, "<rpc-reply xmlns=\"%s\">", NETCONF_BASE_NAMESPACE);
if (!xml_child_nr_type(xe, CX_ELMNT)) if (!xml_child_nr_type(xe, CX_ELMNT))
cprintf(cbret, "<ok/>"); cprintf(cbret, "<ok/>");
else while ((x = xml_child_each(xe, x, CX_ELMNT)) != NULL) { else{
while ((x = xml_child_each(xe, x, CX_ELMNT)) != NULL) {
if (xmlns_set(x, NULL, namespace) < 0) if (xmlns_set(x, NULL, namespace) < 0)
goto done; goto done;
if (clicon_xml2cbuf(cbret, x, 0, 0, -1) < 0) }
if (clicon_xml2cbuf(cbret, xe, 0, 0, -1, 1) < 0)
goto done; goto done;
} }
cprintf(cbret, "</rpc-reply>"); cprintf(cbret, "</rpc-reply>");

View file

@ -325,10 +325,12 @@ restconf_client_rpc(clicon_handle h,
cprintf(cbret, "<rpc-reply xmlns=\"%s\">", NETCONF_BASE_NAMESPACE); cprintf(cbret, "<rpc-reply xmlns=\"%s\">", NETCONF_BASE_NAMESPACE);
if (!xml_child_nr_type(xe, CX_ELMNT)) if (!xml_child_nr_type(xe, CX_ELMNT))
cprintf(cbret, "<ok/>"); cprintf(cbret, "<ok/>");
else while ((x = xml_child_each(xe, x, CX_ELMNT)) != NULL) { else {
while ((x = xml_child_each(xe, x, CX_ELMNT)) != NULL) {
if (xmlns_set(x, NULL, namespace) < 0) if (xmlns_set(x, NULL, namespace) < 0)
goto done; goto done;
if (clicon_xml2cbuf(cbret, x, 0, 0, -1) < 0) }
if (clicon_xml2cbuf(cbret, xe, 0, 0, -1, 1) < 0)
goto done; goto done;
} }
cprintf(cbret, "</rpc-reply>"); cprintf(cbret, "</rpc-reply>");

View file

@ -44,10 +44,9 @@
* Prototypes * Prototypes
*/ */
int json2xml_decode(cxobj *x, cxobj **xerr); int json2xml_decode(cxobj *x, cxobj **xerr);
int xml2json_cbuf(cbuf *cb, cxobj *x, int pretty); int xml2json_cbuf(cbuf *cb, cxobj *x, int pretty, int skiptop);
int xml2json_cbuf_vec(cbuf *cb, cxobj **vec, size_t veclen, int pretty); int xml2json_cbuf_vec(cbuf *cb, cxobj **vec, size_t veclen, int pretty);
int xml2json(FILE *f, cxobj *x, int pretty); int xml2json_file(FILE *f, cxobj *x, int pretty, clicon_output_cb *fn, int skiptop);
int xml2json_cb(FILE *f, cxobj *x, int pretty, clicon_output_cb *fn);
int json_print(FILE *f, cxobj *x); int json_print(FILE *f, cxobj *x);
int xml2json_vec(FILE *f, cxobj **vec, size_t veclen, int pretty); int xml2json_vec(FILE *f, cxobj **vec, size_t veclen, int pretty);
int clixon_json_parse_string(char *str, int rfc7951, yang_bind yb, yang_stmt *yspec, cxobj **xt, cxobj **xret); int clixon_json_parse_string(char *str, int rfc7951, yang_bind yb, yang_stmt *yspec, cxobj **xt, cxobj **xret);

View file

@ -47,7 +47,7 @@ int clicon_xml2file_cb(FILE *f, cxobj *x, int level, int prettyprint, clicon_out
int clicon_xml2file(FILE *f, cxobj *x, int level, int prettyprint); int clicon_xml2file(FILE *f, cxobj *x, int level, int prettyprint);
int xml_print(FILE *f, cxobj *xn); int xml_print(FILE *f, cxobj *xn);
int xml_dump(FILE *f, cxobj *x); int xml_dump(FILE *f, cxobj *x);
int clicon_xml2cbuf(cbuf *cb, cxobj *x, int level, int prettyprint, int32_t depth); int clicon_xml2cbuf(cbuf *cb, cxobj *x, int level, int prettyprint, int32_t depth, int skiptop);
char *clicon_xml2str(cxobj *x); char *clicon_xml2str(cxobj *x);
int xmltree2cbuf(cbuf *cb, cxobj *x, int level); int xmltree2cbuf(cbuf *cb, cxobj *x, int level);

View file

@ -1206,7 +1206,7 @@ xmldb_put(clicon_handle h,
} }
pretty = clicon_option_bool(h, "CLICON_XMLDB_PRETTY"); pretty = clicon_option_bool(h, "CLICON_XMLDB_PRETTY");
if (strcmp(format,"json")==0){ if (strcmp(format,"json")==0){
if (xml2json(f, x0, pretty) < 0) if (xml2json_file(f, x0, pretty, fprintf, 0) < 0)
goto done; goto done;
} }
else if (clicon_xml2file(f, x0, 0, pretty) < 0) else if (clicon_xml2file(f, x0, 0, pretty) < 0)
@ -1264,7 +1264,7 @@ xmldb_dump(clicon_handle h,
} }
pretty = clicon_option_bool(h, "CLICON_XMLDB_PRETTY"); pretty = clicon_option_bool(h, "CLICON_XMLDB_PRETTY");
if (strcmp(format,"json")==0){ if (strcmp(format,"json")==0){
if (xml2json(f, xt, pretty) < 0) if (xml2json_file(f, xt, pretty, fprintf, 0) < 0)
goto done; goto done;
} }
else if (clicon_xml2file(f, xt, 0, pretty) < 0) else if (clicon_xml2file(f, xt, 0, pretty) < 0)

View file

@ -1043,22 +1043,21 @@ xml2json1_cbuf(cbuf *cb,
* @param[in,out] cb Cligen buffer to write to * @param[in,out] cb Cligen buffer to write to
* @param[in] x XML tree to translate from * @param[in] x XML tree to translate from
* @param[in] pretty Set if output is pretty-printed * @param[in] pretty Set if output is pretty-printed
* @param[in] top By default only children are printed, set if include top
* @retval 0 OK * @retval 0 OK
* @retval -1 Error * @retval -1 Error
* *
* @code * @code
* cbuf *cb; * cbuf *cb;
* cb = cbuf_new(); * cb = cbuf_new();
* if (xml2json_cbuf(cb, xn, 0, 1) < 0) * if (xml2json_cbuf(cb, xn, 0, 0) < 0)
* goto err; * goto err;
* cbuf_free(cb); * cbuf_free(cb);
* @endcode * @endcode
* @see clicon_xml2cbuf XML corresponding function * @see clicon_xml2cbuf XML corresponding function
* @see xml2json_cbuf_vec Top symbol is list * @see xml2json_cbuf_vec Top symbol is list
*/ */
int static int
xml2json_cbuf(cbuf *cb, xml2json_cbuf1(cbuf *cb,
cxobj *x, cxobj *x,
int pretty) int pretty)
{ {
@ -1100,6 +1099,44 @@ xml2json_cbuf(cbuf *cb,
return retval; return retval;
} }
/*! Translate an XML tree to JSON in a CLIgen buffer skip top-level object
*
* XML-style namespace notation in tree, but RFC7951 in output assume yang
* populated
*
* @param[in,out] cb Cligen buffer to write to
* @param[in] xt Top-level xml object
* @param[in] pretty Set if output is pretty-printed
* @param[in] skiptop 0: Include top object 1: Skip top-object, only children,
* @retval 0 OK
* @retval -1 Error
* @see xml2json_cbuf where the top level object is included
*/
int
xml2json_cbuf(cbuf *cb,
cxobj *xt,
int pretty,
int skiptop)
{
int retval = -1;
cxobj *xc;
if (skiptop){
xc = NULL;
while ((xc = xml_child_each(xt, xc, CX_ELMNT)) != NULL)
if (xml2json_cbuf1(cb, xc, pretty) < 0)
goto done;
}
else {
if (xml2json_cbuf1(cb, xt, pretty) < 0)
goto done;
}
retval = 0;
done:
return retval;
}
/*! Translate a vector of xml objects to JSON Cligen buffer. /*! Translate a vector of xml objects to JSON Cligen buffer.
* This is done by adding a top pseudo-object, and add the vector as subs, * This is done by adding a top pseudo-object, and add the vector as subs,
* and then not printing the top pseudo-object using the 'flat' option. * and then not printing the top pseudo-object using the 'flat' option.
@ -1169,21 +1206,23 @@ xml2json_cbuf_vec(cbuf *cb,
* @param[in] f File to print to * @param[in] f File to print to
* @param[in] x XML tree to translate from * @param[in] x XML tree to translate from
* @param[in] pretty Set if output is pretty-printed * @param[in] pretty Set if output is pretty-printed
* @param[in] skiptop 0: Include top object 1: Skip top-object, only children,
* @retval 0 OK * @retval 0 OK
* @retval -1 Error * @retval -1 Error
* *
* @note yang is necessary to translate to one-member lists, * @note yang is necessary to translate to one-member lists,
* eg if a is a yang LIST <a>0</a> -> {"a":["0"]} and not {"a":"0"} * eg if a is a yang LIST <a>0</a> -> {"a":["0"]} and not {"a":"0"}
* @code * @code
* if (xml2json(stderr, xn, 0) < 0) * if (xml2json_file(stderr, xn, 0, fprintf, 0) < 0)
* goto err; * goto err;
* @endcode * @endcode
*/ */
int int
xml2json_cb(FILE *f, xml2json_file(FILE *f,
cxobj *x, cxobj *x,
int pretty, int pretty,
clicon_output_cb *fn) clicon_output_cb *fn,
int skiptop)
{ {
int retval = 1; int retval = 1;
cbuf *cb = NULL; cbuf *cb = NULL;
@ -1192,7 +1231,7 @@ xml2json_cb(FILE *f,
clicon_err(OE_XML, errno, "cbuf_new"); clicon_err(OE_XML, errno, "cbuf_new");
goto done; goto done;
} }
if (xml2json_cbuf(cb, x, pretty) < 0) if (xml2json_cbuf(cb, x, pretty, skiptop) < 0)
goto done; goto done;
(*fn)(f, "%s", cbuf_get(cb)); (*fn)(f, "%s", cbuf_get(cb));
retval = 0; retval = 0;
@ -1202,29 +1241,6 @@ xml2json_cb(FILE *f,
return retval; return retval;
} }
/*! Translate from xml tree to JSON and print to file
* @param[in] f File to print to
* @param[in] x XML tree to translate from
* @param[in] pretty Set if output is pretty-printed
* @retval 0 OK
* @retval -1 Error
*
* @note yang is necessary to translate to one-member lists,
* eg if a is a yang LIST <a>0</a> -> {"a":["0"]} and not {"a":"0"}
* @code
* if (xml2json(stderr, xn, 0) < 0)
* goto err;
* @endcode
*/
int
xml2json(FILE *f,
cxobj *x,
int pretty)
{
return xml2json_cb(f, x, pretty, fprintf);
}
/*! Print an XML tree structure to an output stream as JSON /*! Print an XML tree structure to an output stream as JSON
* *
* @param[in] f UNIX output stream * @param[in] f UNIX output stream
@ -1234,7 +1250,7 @@ int
json_print(FILE *f, json_print(FILE *f,
cxobj *x) cxobj *x)
{ {
return xml2json_cb(f, x, 1, fprintf); return xml2json_file(f, x, 1, fprintf, 0);
} }
/*! Translate a vector of xml objects to JSON File. /*! Translate a vector of xml objects to JSON File.

View file

@ -186,7 +186,7 @@ netconf_invalid_value(cbuf *cb,
if (netconf_invalid_value_xml(&xret, type, message) < 0) if (netconf_invalid_value_xml(&xret, type, message) < 0)
goto done; goto done;
if (clicon_xml2cbuf(cb, xret, 0, 0, -1) < 0) if (clicon_xml2cbuf(cb, xret, 0, 0, -1, 0) < 0)
goto done; goto done;
retval = 0; retval = 0;
done: done:
@ -309,7 +309,7 @@ netconf_missing_attribute(cbuf *cb,
if (netconf_missing_attribute_xml(&xret, type, attr, message) < 0) if (netconf_missing_attribute_xml(&xret, type, attr, message) < 0)
goto done; goto done;
if (clicon_xml2cbuf(cb, xret, 0, 0, -1) < 0) if (clicon_xml2cbuf(cb, xret, 0, 0, -1, 0) < 0)
goto done; goto done;
retval = 0; retval = 0;
done: done:
@ -338,7 +338,7 @@ netconf_bad_attribute(cbuf *cb,
if (netconf_bad_attribute_xml(&xret, type, info, message) < 0) if (netconf_bad_attribute_xml(&xret, type, info, message) < 0)
goto done; goto done;
if (clicon_xml2cbuf(cb, xret, 0, 0, -1) < 0) if (clicon_xml2cbuf(cb, xret, 0, 0, -1, 0) < 0)
goto done; goto done;
retval = 0; retval = 0;
done: done:
@ -521,7 +521,7 @@ netconf_missing_element(cbuf *cb,
if (netconf_common_xml(&xret, type, "missing-element", if (netconf_common_xml(&xret, type, "missing-element",
"bad-element", element, message) < 0) "bad-element", element, message) < 0)
goto done; goto done;
if (clicon_xml2cbuf(cb, xret, 0, 0, -1) < 0) if (clicon_xml2cbuf(cb, xret, 0, 0, -1, 0) < 0)
goto done; goto done;
retval = 0; retval = 0;
done: done:
@ -567,7 +567,7 @@ netconf_bad_element(cbuf *cb,
if (netconf_common_xml(&xret, type, "bad-element", if (netconf_common_xml(&xret, type, "bad-element",
"bad-element",element, message) < 0) "bad-element",element, message) < 0)
goto done; goto done;
if (clicon_xml2cbuf(cb, xret, 0, 0, -1) < 0) if (clicon_xml2cbuf(cb, xret, 0, 0, -1, 0) < 0)
goto done; goto done;
retval = 0; retval = 0;
done: done:
@ -605,7 +605,7 @@ netconf_unknown_element(cbuf *cb,
if (netconf_common_xml(&xret, type, "unknown-element", if (netconf_common_xml(&xret, type, "unknown-element",
"bad-element", element, message) < 0) "bad-element", element, message) < 0)
goto done; goto done;
if (clicon_xml2cbuf(cb, xret, 0, 0, -1) < 0) if (clicon_xml2cbuf(cb, xret, 0, 0, -1, 0) < 0)
goto done; goto done;
retval = 0; retval = 0;
done: done:
@ -652,7 +652,7 @@ netconf_unknown_namespace(cbuf *cb,
if (netconf_common_xml(&xret, type, "unknown-namespace", if (netconf_common_xml(&xret, type, "unknown-namespace",
"bad-namespace", ns, message) < 0) "bad-namespace", ns, message) < 0)
goto done; goto done;
if (clicon_xml2cbuf(cb, xret, 0, 0, -1) < 0) if (clicon_xml2cbuf(cb, xret, 0, 0, -1, 0) < 0)
goto done; goto done;
retval = 0; retval = 0;
done: done:
@ -690,7 +690,7 @@ netconf_access_denied(cbuf *cb,
if (netconf_access_denied_xml(&xret, type, message) < 0) if (netconf_access_denied_xml(&xret, type, message) < 0)
goto done; goto done;
if (clicon_xml2cbuf(cb, xret, 0, 0, -1) < 0) if (clicon_xml2cbuf(cb, xret, 0, 0, -1, 0) < 0)
goto done; goto done;
retval = 0; retval = 0;
done: done:
@ -936,7 +936,7 @@ netconf_data_missing(cbuf *cb,
if (netconf_data_missing_xml(&xret, missing_choice, message) < 0) if (netconf_data_missing_xml(&xret, missing_choice, message) < 0)
goto done; goto done;
if (clicon_xml2cbuf(cb, xret, 0, 0, -1) < 0) if (clicon_xml2cbuf(cb, xret, 0, 0, -1, 0) < 0)
goto done; goto done;
retval = 0; retval = 0;
done: done:
@ -1085,7 +1085,7 @@ netconf_operation_not_supported(cbuf *cb,
if (netconf_operation_not_supported_xml(&xret, type, message) < 0) if (netconf_operation_not_supported_xml(&xret, type, message) < 0)
goto done; goto done;
if (clicon_xml2cbuf(cb, xret, 0, 0, -1) < 0) if (clicon_xml2cbuf(cb, xret, 0, 0, -1, 0) < 0)
goto done; goto done;
retval = 0; retval = 0;
done: done:
@ -1113,7 +1113,7 @@ netconf_operation_failed(cbuf *cb,
if (netconf_operation_failed_xml(&xret, type, message) < 0) if (netconf_operation_failed_xml(&xret, type, message) < 0)
goto done; goto done;
if (clicon_xml2cbuf(cb, xret, 0, 0, -1) < 0) if (clicon_xml2cbuf(cb, xret, 0, 0, -1, 0) < 0)
goto done; goto done;
retval = 0; retval = 0;
done: done:
@ -1201,7 +1201,7 @@ netconf_malformed_message(cbuf *cb,
if (netconf_malformed_message_xml(&xret, message) < 0) if (netconf_malformed_message_xml(&xret, message) < 0)
goto done; goto done;
if (clicon_xml2cbuf(cb, xret, 0, 0, -1) < 0) if (clicon_xml2cbuf(cb, xret, 0, 0, -1, 0) < 0)
goto done; goto done;
retval = 0; retval = 0;
done: done:
@ -1606,7 +1606,7 @@ netconf_err2cb(cxobj *xerr,
cprintf(cberr, "%s ", xml_body(x)); cprintf(cberr, "%s ", xml_body(x));
if ((x=xpath_first(xerr, NULL, "//error-info")) != NULL && if ((x=xpath_first(xerr, NULL, "//error-info")) != NULL &&
xml_child_nr(x) > 0){ xml_child_nr(x) > 0){
clicon_xml2cbuf(cberr, xml_child_i(x, 0), 0, 0, -1); clicon_xml2cbuf(cberr, xml_child_i(x, 0), 0, 0, -1, 0);
} }
if ((x=xpath_first(xerr, NULL, "//error-app-tag"))!=NULL) if ((x=xpath_first(xerr, NULL, "//error-app-tag"))!=NULL)
cprintf(cberr, ": %s ", xml_body(x)); cprintf(cberr, ": %s ", xml_body(x));

View file

@ -763,7 +763,7 @@ send_msg_notify_xml(clicon_handle h,
clicon_err(OE_PLUGIN, errno, "cbuf_new"); clicon_err(OE_PLUGIN, errno, "cbuf_new");
goto done; goto done;
} }
if (clicon_xml2cbuf(cb, xev, 0, 0, -1) < 0) if (clicon_xml2cbuf(cb, xev, 0, 0, -1, 0) < 0)
goto done; goto done;
if (send_msg_notify(s, cbuf_get(cb)) < 0) if (send_msg_notify(s, cbuf_get(cb)) < 0)
goto done; goto done;

View file

@ -420,7 +420,7 @@ clicon_rpc_netconf_xml(clicon_handle h,
goto done; goto done;
} }
rpcname = xml_name(xname); /* Store rpc name and use in yang binding after reply */ rpcname = xml_name(xname); /* Store rpc name and use in yang binding after reply */
if (clicon_xml2cbuf(cb, xml, 0, 0, -1) < 0) if (clicon_xml2cbuf(cb, xml, 0, 0, -1, 0) < 0)
goto done; goto done;
if (clicon_rpc_netconf(h, cbuf_get(cb), xret, sp) < 0) if (clicon_rpc_netconf(h, cbuf_get(cb), xret, sp) < 0)
goto done; goto done;

View file

@ -990,7 +990,7 @@ stream_publish_cb(clicon_handle h,
clicon_err(OE_XML, errno, "cbuf_new"); clicon_err(OE_XML, errno, "cbuf_new");
goto done; goto done;
} }
if (clicon_xml2cbuf(d, event, 0, 0, -1) < 0) if (clicon_xml2cbuf(d, event, 0, 0, -1, 0) < 0)
goto done; goto done;
if (url_post(cbuf_get(u), /* url+stream */ if (url_post(cbuf_get(u), /* url+stream */
cbuf_get(d), /* postfields */ cbuf_get(d), /* postfields */

View file

@ -1680,7 +1680,7 @@ rpc_reply_check(clicon_handle h,
if (ret == 0){ if (ret == 0){
clicon_debug(1, "%s failure when validating:%s", __FUNCTION__, cbuf_get(cbret)); clicon_debug(1, "%s failure when validating:%s", __FUNCTION__, cbuf_get(cbret));
cbuf_reset(cbret); cbuf_reset(cbret);
if (clicon_xml2cbuf(cbret, xret, 0, 0, -1) < 0) if (clicon_xml2cbuf(cbret, xret, 0, 0, -1, 0) < 0)
goto done; goto done;
goto fail; goto fail;
} }
@ -1689,7 +1689,7 @@ rpc_reply_check(clicon_handle h,
if (ret == 0){ if (ret == 0){
clicon_debug(1, "%s failure when validating:%s", __FUNCTION__, cbuf_get(cbret)); clicon_debug(1, "%s failure when validating:%s", __FUNCTION__, cbuf_get(cbret));
cbuf_reset(cbret); cbuf_reset(cbret);
if (clicon_xml2cbuf(cbret, xret, 0, 0, -1) < 0) if (clicon_xml2cbuf(cbret, xret, 0, 0, -1, 0) < 0)
goto done; goto done;
goto fail; goto fail;
} }

View file

@ -2350,7 +2350,7 @@ clicon_log_xml(int level,
clicon_err(OE_XML, errno, "cbuf_new"); clicon_err(OE_XML, errno, "cbuf_new");
goto done; goto done;
} }
if (clicon_xml2cbuf(cb, x, 0, 0, -1) < 0) if (clicon_xml2cbuf(cb, x, 0, 0, -1, 0) < 0)
goto done; goto done;
/* first round: compute length of debug message */ /* first round: compute length of debug message */

View file

@ -288,26 +288,16 @@ xml_dump(FILE *f,
return xml_dump1(f, x, 0); return xml_dump1(f, x, 0);
} }
/*! Print an XML tree structure to a cligen buffer and encode chars "<>&" /*! Internal: print XML tree structure to a cligen buffer and encode chars "<>&"
* *
* @param[in,out] cb Cligen buffer to write to * @param[in,out] cb Cligen buffer to write to
* @param[in] xn Clicon xml tree * @param[in] xn Clicon xml tree
* @param[in] level Indentation level for prettyprint * @param[in] level Indentation level for prettyprint
* @param[in] prettyprint insert \n and spaces tomake the xml more readable. * @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 * @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, -1) < 0)
* goto err;
* fprintf(stderr, "%s", cbuf_get(cb));
* cbuf_free(cb);
* @endcode
* @see clicon_xml2file
*/ */
int static int
clicon_xml2cbuf(cbuf *cb, clicon_xml2cbuf1(cbuf *cb,
cxobj *x, cxobj *x,
int level, int level,
int prettyprint, int prettyprint,
@ -357,7 +347,7 @@ clicon_xml2cbuf(cbuf *cb,
while ((xc = xml_child_each(x, xc, -1)) != NULL) while ((xc = xml_child_each(x, xc, -1)) != NULL)
switch (xml_type(xc)){ switch (xml_type(xc)){
case CX_ATTR: case CX_ATTR:
if (clicon_xml2cbuf(cb, xc, level+1, prettyprint, -1) < 0) if (clicon_xml2cbuf1(cb, xc, level+1, prettyprint, -1) < 0)
goto done; goto done;
break; break;
case CX_BODY: case CX_BODY:
@ -379,7 +369,7 @@ clicon_xml2cbuf(cbuf *cb,
xc = NULL; xc = NULL;
while ((xc = xml_child_each(x, xc, -1)) != NULL) while ((xc = xml_child_each(x, xc, -1)) != NULL)
if (xml_type(xc) != CX_ATTR) if (xml_type(xc) != CX_ATTR)
if (clicon_xml2cbuf(cb, xc, level+1, prettyprint, depth-1) < 0) if (clicon_xml2cbuf1(cb, xc, level+1, prettyprint, depth-1) < 0)
goto done; goto done;
if (prettyprint && hasbody == 0) if (prettyprint && hasbody == 0)
cprintf(cb, "%*s", level*XML_INDENT, ""); cprintf(cb, "%*s", level*XML_INDENT, "");
@ -403,6 +393,53 @@ clicon_xml2cbuf(cbuf *cb,
return retval; return retval;
} }
/*! Print an XML tree structure to a cligen buffer and encode chars "<>&"
*
* @param[in,out] cb Cligen buffer to write to
* @param[in] xt Top-level xml object
* @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: all, 0: none, 1: node itself
* @param[in] skiptop 0: Include top object 1: Skip top-object, only children,
* @retval 0 OK
* @retval -1 Error
*
* @code
* cbuf *cb;
* cb = cbuf_new();
* if (clicon_xml2cbuf(cb, xn, 0, 1, -1, 0) < 0)
* goto err;
* fprintf(stderr, "%s", cbuf_get(cb));
* cbuf_free(cb);
* @endcode
* @see clicon_xml2file
*/
int
clicon_xml2cbuf(cbuf *cb,
cxobj *xt,
int level,
int pretty,
int32_t depth,
int skiptop)
{
int retval = -1;
cxobj *xc;
if (skiptop){
xc = NULL;
while ((xc = xml_child_each(xt, xc, CX_ELMNT)) != NULL)
if (clicon_xml2cbuf1(cb, xc, level, pretty, depth) < 0)
goto done;
}
else {
if (clicon_xml2cbuf1(cb, xt, level, pretty, depth) < 0)
goto done;
}
retval = 0;
done:
return retval;
}
/*! Return an xml tree as a pretty-printed malloced string. /*! Return an xml tree as a pretty-printed malloced string.
* @param[in] x XML tree * @param[in] x XML tree
* @retval str Malloced pretty-printed string (should be free:d after use) * @retval str Malloced pretty-printed string (should be free:d after use)
@ -418,7 +455,7 @@ clicon_xml2str(cxobj *x)
clicon_err(OE_XML, errno, "cbuf_new"); clicon_err(OE_XML, errno, "cbuf_new");
return NULL; return NULL;
} }
if (clicon_xml2cbuf(cb, x, 0, 1, -1) < 0) if (clicon_xml2cbuf(cb, x, 0, 1, -1, 0) < 0)
return NULL; return NULL;
if ((str = strdup(cbuf_get(cb))) == NULL){ if ((str = strdup(cbuf_get(cb))) == NULL){
clicon_err(OE_XML, errno, "strdup"); clicon_err(OE_XML, errno, "strdup");

View file

@ -140,12 +140,12 @@ int example_rpc(clicon_handle h,
cprintf(cbret, "<rpc-reply xmlns=\"%s\">", NETCONF_BASE_NAMESPACE); cprintf(cbret, "<rpc-reply xmlns=\"%s\">", NETCONF_BASE_NAMESPACE);
if (!xml_child_nr_type(xe, CX_ELMNT)) if (!xml_child_nr_type(xe, CX_ELMNT))
cprintf(cbret, "<ok/>"); cprintf(cbret, "<ok/>");
else else{
while ((x = xml_child_each(xe, x, CX_ELMNT)) != NULL) while ((x = xml_child_each(xe, x, CX_ELMNT)) != NULL) {
{
if (xmlns_set(x, NULL, ns) < 0) if (xmlns_set(x, NULL, ns) < 0)
goto done; goto done;
if (clicon_xml2cbuf(cbret, x, 0, 0, -1) < 0) }
if (clicon_xml2cbuf(cbret, xe, 0, 0, -1, 1) < 0)
goto done; goto done;
} }
cprintf(cbret, "</rpc-reply>"); cprintf(cbret, "</rpc-reply>");

View file

@ -88,7 +88,6 @@ main(int argc,
{ {
int retval = -1; int retval = -1;
cxobj *xt = NULL; cxobj *xt = NULL;
cxobj *xc;
cbuf *cb = cbuf_new(); cbuf *cb = cbuf_new();
int c; int c;
int logdst = CLICON_LOG_STDERR; int logdst = CLICON_LOG_STDERR;
@ -145,20 +144,10 @@ main(int argc,
xml_print(stderr, xerr); xml_print(stderr, xerr);
goto done; goto done;
} }
#if 0
if (json) if (json)
xml2json_cbuf(cb, xt, pretty); /* print json */ xml2json_cbuf(cb, xt, pretty, 1); /* print json */
else else
clicon_xml2cbuf(cb, xt, 0, pretty, -1); /* print xml */ clicon_xml2cbuf(cb, xt, 0, pretty, -1, 1); /* print xml */
#else
xc = NULL;
/* XXX This is troublesome for JSON top-level lists */
while ((xc = xml_child_each(xt, xc, -1)) != NULL)
if (json)
xml2json_cbuf(cb, xc, pretty); /* print json */
else
clicon_xml2cbuf(cb, xc, 0, pretty, -1); /* print xml */
#endif
fprintf(stdout, "%s", cbuf_get(cb)); fprintf(stdout, "%s", cbuf_get(cb));
fflush(stdout); fflush(stdout);
retval = 0; retval = 0;

View file

@ -167,7 +167,7 @@ main(int argc,
fprintf(stderr, "No xml\n"); fprintf(stderr, "No xml\n");
goto done; goto done;
} }
if (clicon_xml2cbuf(cb, xc, 0, 0, -1) < 0) if (clicon_xml2cbuf(cb, xc, 0, 0, -1, 0) < 0)
goto done; goto done;
if ((msg = clicon_msg_encode(getpid(), "%s", cbuf_get(cb))) < 0) if ((msg = clicon_msg_encode(getpid(), "%s", cbuf_get(cb))) < 0)
goto done; goto done;

View file

@ -139,7 +139,6 @@ main(int argc,
int retval = -1; int retval = -1;
int ret; int ret;
cxobj *xt = NULL; /* Base cxobj tree parsed from xml or json */ cxobj *xt = NULL; /* Base cxobj tree parsed from xml or json */
cxobj *xc;
cbuf *cb = cbuf_new(); cbuf *cb = cbuf_new();
int c; int c;
int logdst = CLICON_LOG_STDERR; int logdst = CLICON_LOG_STDERR;
@ -337,21 +336,10 @@ main(int argc,
} }
/* 4. Output data (xml/json) */ /* 4. Output data (xml/json) */
if (output){ if (output){
#if 0
if (jsonout) if (jsonout)
xml2json_cbuf(cb, xt, pretty); /* print json */ xml2json_cbuf(cb, xt, pretty, 1); /* print json */
else else
clicon_xml2cbuf(cb, xt, 0, pretty, -1); /* print xml */ clicon_xml2cbuf(cb, xt, 0, pretty, -1, 1); /* print xml */
#else
xc = NULL;
/* XXX This is troublesome for JSON top-level lists */
while ((xc = xml_child_each(xt, xc, -1)) != NULL){
if (jsonout)
xml2json_cbuf(cb, xc, pretty); /* print json */
else
clicon_xml2cbuf(cb, xc, 0, pretty, -1); /* print xml */
}
#endif
fprintf(stdout, "%s", cbuf_get(cb)); fprintf(stdout, "%s", cbuf_get(cb));
fflush(stdout); fflush(stdout);
} }

View file

@ -98,7 +98,7 @@ ctx_print2(cbuf *cb,
case XT_NODESET: case XT_NODESET:
for (i=0; i<xc->xc_size; i++){ for (i=0; i<xc->xc_size; i++){
cprintf(cb, "%d:", i); cprintf(cb, "%d:", i);
clicon_xml2cbuf(cb, xc->xc_nodeset[i], 0, 0, -1); clicon_xml2cbuf(cb, xc->xc_nodeset[i], 0, 0, -1, 0);
} }
break; break;
case XT_BOOL: case XT_BOOL:

View file

@ -1,252 +0,0 @@
module clixon-autocli{
yang-version 1.1;
namespace "http://clicon.org/autocli";
prefix autocli;
organization
"Clicon / Clixon";
contact
"Olof Hagsand <olof@hagsand.se>";
description
"Clixon CLIgen specification declarations, including autocli.
Design inspired by ietf-netconf-acm.yang
***** BEGIN LICENSE BLOCK *****
Copyright (C) 2020-2021 Olof Hagsand and Rubicon Communications, LLC(Netgate)
This file is part of CLIXON
Licensed under the Apache License, Version 2.0 (the \"License\");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an \"AS IS\" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Alternatively, the contents of this file may be used under the terms of
the GNU General Public License Version 3 or later (the \"GPL\"),
in which case the provisions of the GPL are applicable instead
of those above. If you wish to allow use of your version of this file only
under the terms of the GPL, and not to allow others to
use your version of this file under the terms of Apache License version 2,
indicate your decision by deleting the provisions above and replace them with
the notice and other provisions required by the GPL. If you do not delete
the provisions above, a recipient may use your version of this file under
the terms of any one of the Apache License version 2 or the GPL.
***** END LICENSE BLOCK *****";
revision 2022-05-30 {
description
"
Released in Clixon 5.8";
}
revision 2022-02-11 {
description
"Initial version
Released in Clixon 5.6";
}
revision 2021-12-05 {
description
"Initial version
Released in Clixon 5.5";
}
extension hide {
description
"Modify the autocli by hiding the command associated with a YANG node and its
sub-commands.
The command is active but not shown by ? or TAB. In other words, it hides the
auto-completion of commands";
}
extension hide-show {
description
"Modify the autocli by hiding the command associated with a YANG node and its
sub-commands in CLI show commands.";
}
extension strict-expand {
description
"Modify the autocli by only showing exactly the expanded values of a variable.
It should not be possible to add a new value that is not in the expanded list.";
}
typedef autocli-op {
description
"Autocli rule-type operation, each rule use different fields as
described in the individual enums below.";
type enumeration {
enum enable {
description
"Include a complete subtree to rendering of autocli.
Example:
<module-default>false</module-default>
<rule>
<name>wifi</name>
<operation>enable</operation>
<module-name>openconfig-wifi</module-name>
</rule>
Only on module-level and if module-default is false,
Rule fields used: module-name";
}
enum compress {
description
"Skip a keyword from a command.
Keep the command, only make it shorter by omitting a part.
Example: compress containers if single list child
<rule>
<name>container compress</name>
<operation>compress</operation>
<yang-keyword>container</yang-keyword>
<yang-keyword-child>list</yang-keyword-child>
</rule>
Rule fields used:
module-name, yang-keyword, schema-nodeid, yang-keyword-child, extension";
}
enum edit-mode {
description
"Autocli CLI edit modes for YANG symbols.
For example,
edit interface eth0<CR>
enters a new mode with local context.";
}
}
}
typedef list-keyword-type {
description
"Autocli CLI keyword behaviour in YANG lists.
With 'keyword' is meant CLIgen 'constants' rather than 'variables'.
Assume a YANG LIST: list a{ key x; leaf x; leaf y;} and how to generate
the autocli";
type enumeration {
enum kw-none{
description "No extra keywords, only variables: a <x> <y>";
}
enum kw-nokey{
description "Keywords on non-key variables: a <x> y <y>";
}
enum kw-all{
description "Keywords on all variables: a x <x> y <y>";
}
}
}
typedef yang-keywords {
type bits {
bit list;
bit listall{ /* NYI */
description
"Variant of list encompassing all list entries, not just an instance";
}
bit container;
bit leaf; /* Also leaf-list (NYI) */
}
}
grouping clixon-autocli{
/* options */
leaf module-default {
description
"Include YANG modules for generation of autocli.
If true, all modules with a top-level datanode are generated, ie
they get a top-level entry in the @basemodel tree.
If false, you need to explicitly enable modules for autocli generation
using 'enable' rules";
type boolean;
default true;
}
leaf list-keyword-default {
description
"Autocli CLI keyword behaviour in YANG lists.";
type list-keyword-type;
default kw-nokey;
}
leaf treeref-state-default {
description
"If 'true', generate CLI from YANG state/non-config statements as well, not only config data.
Many specs have very large state parts, for example openconfig has ca 10 times
larger state than config parts, see for example openconfig-isis.yang.";
type boolean;
default false;
}
leaf edit-mode-default {
description
"Open automatic edit-modes for some YANG keywords and do not allow others.
A CLI edit mode opens a carriage-return option and changes the context to be
in that local context.
For example:
cli> interfaces interface e0<cr>
eth0>
Default is to generate edit-modes for all containers and lists.";
type yang-keywords;
default "list container";
}
leaf completion-default {
description
"Generate code for CLI completion of existing db symbols.
That is, check existing configure database for completion options.
This is normally always enabled.";
type boolean;
default true;
}
/* rules */
list rule {
description
"Represents a modification rule of a clixon clispec.";
key name;
leaf name {
description
"Arbitrary name assigned for the rule, must be unique";
type string;
}
leaf description {
description
"Rule description";
type string;
}
leaf operation {
description "Rule operation";
type autocli-op;
}
leaf module-name {
description
"Name of the module associated with this rule.
Wildchars '*' and '?' can be used (glob pattern).
Revision and yang suffix are omitted
Example: 'openconfig-*'";
type string;
}
leaf yang-keyword {
description
"If present identifes a YANG keyword which the rule applies to
Example: 'container'
";
type string;
}
leaf schema-nodeid {
description
"path in the form of /<id>/<id> or just a single <id> identifying a YANG
schema-node identifier as defined in RFC 7950 Sec 6.5
Example: 'config', '/interfaces/interface'";
type string;
}
leaf yang-keyword-child {
description
"The YANG statement has a single child, and the yang type of the child is the
value of this option
A (maybe too) specific property to cover openconfig compressions
as defined here:
https://github.com/openconfig/ygot/blob/master/docs/design.md#openconfig-path-compression";
type string;
}
leaf extension {
/* Consider making this a container with name/module/value instead */
description
"The extension is set either in the node itself, or in this module
Extension prefix must be set
Example: oc-ext:openconfig-version";
type string;
}
}
}
}