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

@ -44,10 +44,9 @@
* Prototypes
*/
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(FILE *f, cxobj *x, int pretty);
int xml2json_cb(FILE *f, cxobj *x, int pretty, clicon_output_cb *fn);
int xml2json_file(FILE *f, cxobj *x, int pretty, clicon_output_cb *fn, int skiptop);
int json_print(FILE *f, cxobj *x);
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);

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 xml_print(FILE *f, cxobj *xn);
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);
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");
if (strcmp(format,"json")==0){
if (xml2json(f, x0, pretty) < 0)
if (xml2json_file(f, x0, pretty, fprintf, 0) < 0)
goto done;
}
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");
if (strcmp(format,"json")==0){
if (xml2json(f, xt, pretty) < 0)
if (xml2json_file(f, xt, pretty, fprintf, 0) < 0)
goto done;
}
else if (clicon_xml2file(f, xt, 0, pretty) < 0)

View file

@ -1043,24 +1043,23 @@ xml2json1_cbuf(cbuf *cb,
* @param[in,out] cb Cligen buffer to write to
* @param[in] x XML tree to translate from
* @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 -1 Error
*
* @code
* cbuf *cb;
* cb = cbuf_new();
* if (xml2json_cbuf(cb, xn, 0, 1) < 0)
* if (xml2json_cbuf(cb, xn, 0, 0) < 0)
* goto err;
* cbuf_free(cb);
* @endcode
* @see clicon_xml2cbuf XML corresponding function
* @see xml2json_cbuf_vec Top symbol is list
*/
int
xml2json_cbuf(cbuf *cb,
cxobj *x,
int pretty)
static int
xml2json_cbuf1(cbuf *cb,
cxobj *x,
int pretty)
{
int retval = 1;
int level = 0;
@ -1100,6 +1099,44 @@ xml2json_cbuf(cbuf *cb,
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.
* 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.
@ -1166,24 +1203,26 @@ xml2json_cbuf_vec(cbuf *cb,
}
/*! Translate from xml tree to JSON and print to file using a callback
* @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
* @param[in] f File to print to
* @param[in] x XML tree to translate from
* @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
*
* @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)
* if (xml2json_file(stderr, xn, 0, fprintf, 0) < 0)
* goto err;
* @endcode
*/
int
xml2json_cb(FILE *f,
cxobj *x,
int pretty,
clicon_output_cb *fn)
xml2json_file(FILE *f,
cxobj *x,
int pretty,
clicon_output_cb *fn,
int skiptop)
{
int retval = 1;
cbuf *cb = NULL;
@ -1192,7 +1231,7 @@ xml2json_cb(FILE *f,
clicon_err(OE_XML, errno, "cbuf_new");
goto done;
}
if (xml2json_cbuf(cb, x, pretty) < 0)
if (xml2json_cbuf(cb, x, pretty, skiptop) < 0)
goto done;
(*fn)(f, "%s", cbuf_get(cb));
retval = 0;
@ -1202,29 +1241,6 @@ xml2json_cb(FILE *f,
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
*
* @param[in] f UNIX output stream
@ -1234,7 +1250,7 @@ int
json_print(FILE *f,
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.

View file

@ -186,7 +186,7 @@ netconf_invalid_value(cbuf *cb,
if (netconf_invalid_value_xml(&xret, type, message) < 0)
goto done;
if (clicon_xml2cbuf(cb, xret, 0, 0, -1) < 0)
if (clicon_xml2cbuf(cb, xret, 0, 0, -1, 0) < 0)
goto done;
retval = 0;
done:
@ -309,7 +309,7 @@ netconf_missing_attribute(cbuf *cb,
if (netconf_missing_attribute_xml(&xret, type, attr, message) < 0)
goto done;
if (clicon_xml2cbuf(cb, xret, 0, 0, -1) < 0)
if (clicon_xml2cbuf(cb, xret, 0, 0, -1, 0) < 0)
goto done;
retval = 0;
done:
@ -338,7 +338,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, -1) < 0)
if (clicon_xml2cbuf(cb, xret, 0, 0, -1, 0) < 0)
goto done;
retval = 0;
done:
@ -521,7 +521,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, -1) < 0)
if (clicon_xml2cbuf(cb, xret, 0, 0, -1, 0) < 0)
goto done;
retval = 0;
done:
@ -567,7 +567,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, -1) < 0)
if (clicon_xml2cbuf(cb, xret, 0, 0, -1, 0) < 0)
goto done;
retval = 0;
done:
@ -605,7 +605,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, -1) < 0)
if (clicon_xml2cbuf(cb, xret, 0, 0, -1, 0) < 0)
goto done;
retval = 0;
done:
@ -652,7 +652,7 @@ netconf_unknown_namespace(cbuf *cb,
if (netconf_common_xml(&xret, type, "unknown-namespace",
"bad-namespace", ns, message) < 0)
goto done;
if (clicon_xml2cbuf(cb, xret, 0, 0, -1) < 0)
if (clicon_xml2cbuf(cb, xret, 0, 0, -1, 0) < 0)
goto done;
retval = 0;
done:
@ -690,7 +690,7 @@ netconf_access_denied(cbuf *cb,
if (netconf_access_denied_xml(&xret, type, message) < 0)
goto done;
if (clicon_xml2cbuf(cb, xret, 0, 0, -1) < 0)
if (clicon_xml2cbuf(cb, xret, 0, 0, -1, 0) < 0)
goto done;
retval = 0;
done:
@ -936,7 +936,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, -1) < 0)
if (clicon_xml2cbuf(cb, xret, 0, 0, -1, 0) < 0)
goto done;
retval = 0;
done:
@ -1085,7 +1085,7 @@ netconf_operation_not_supported(cbuf *cb,
if (netconf_operation_not_supported_xml(&xret, type, message) < 0)
goto done;
if (clicon_xml2cbuf(cb, xret, 0, 0, -1) < 0)
if (clicon_xml2cbuf(cb, xret, 0, 0, -1, 0) < 0)
goto done;
retval = 0;
done:
@ -1113,7 +1113,7 @@ netconf_operation_failed(cbuf *cb,
if (netconf_operation_failed_xml(&xret, type, message) < 0)
goto done;
if (clicon_xml2cbuf(cb, xret, 0, 0, -1) < 0)
if (clicon_xml2cbuf(cb, xret, 0, 0, -1, 0) < 0)
goto done;
retval = 0;
done:
@ -1201,7 +1201,7 @@ netconf_malformed_message(cbuf *cb,
if (netconf_malformed_message_xml(&xret, message) < 0)
goto done;
if (clicon_xml2cbuf(cb, xret, 0, 0, -1) < 0)
if (clicon_xml2cbuf(cb, xret, 0, 0, -1, 0) < 0)
goto done;
retval = 0;
done:
@ -1606,7 +1606,7 @@ netconf_err2cb(cxobj *xerr,
cprintf(cberr, "%s ", xml_body(x));
if ((x=xpath_first(xerr, NULL, "//error-info")) != NULL &&
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)
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");
goto done;
}
if (clicon_xml2cbuf(cb, xev, 0, 0, -1) < 0)
if (clicon_xml2cbuf(cb, xev, 0, 0, -1, 0) < 0)
goto done;
if (send_msg_notify(s, cbuf_get(cb)) < 0)
goto done;

View file

@ -420,7 +420,7 @@ clicon_rpc_netconf_xml(clicon_handle h,
goto done;
}
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;
if (clicon_rpc_netconf(h, cbuf_get(cb), xret, sp) < 0)
goto done;

View file

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

View file

@ -1680,7 +1680,7 @@ rpc_reply_check(clicon_handle h,
if (ret == 0){
clicon_debug(1, "%s failure when validating:%s", __FUNCTION__, cbuf_get(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 fail;
}
@ -1689,7 +1689,7 @@ rpc_reply_check(clicon_handle h,
if (ret == 0){
clicon_debug(1, "%s failure when validating:%s", __FUNCTION__, cbuf_get(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 fail;
}

View file

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

View file

@ -288,30 +288,20 @@ xml_dump(FILE *f,
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] xn Clicon xml tree
* @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, -1) < 0)
* goto err;
* fprintf(stderr, "%s", cbuf_get(cb));
* cbuf_free(cb);
* @endcode
* @see clicon_xml2file
*/
int
clicon_xml2cbuf(cbuf *cb,
cxobj *x,
int level,
int prettyprint,
int32_t depth)
static int
clicon_xml2cbuf1(cbuf *cb,
cxobj *x,
int level,
int prettyprint,
int32_t depth)
{
int retval = -1;
cxobj *xc;
@ -357,7 +347,7 @@ clicon_xml2cbuf(cbuf *cb,
while ((xc = xml_child_each(x, xc, -1)) != NULL)
switch (xml_type(xc)){
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;
break;
case CX_BODY:
@ -379,7 +369,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, depth-1) < 0)
if (clicon_xml2cbuf1(cb, xc, level+1, prettyprint, depth-1) < 0)
goto done;
if (prettyprint && hasbody == 0)
cprintf(cb, "%*s", level*XML_INDENT, "");
@ -403,6 +393,53 @@ clicon_xml2cbuf(cbuf *cb,
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.
* @param[in] x XML tree
* @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");
return NULL;
}
if (clicon_xml2cbuf(cb, x, 0, 1, -1) < 0)
if (clicon_xml2cbuf(cb, x, 0, 1, -1, 0) < 0)
return NULL;
if ((str = strdup(cbuf_get(cb))) == NULL){
clicon_err(OE_XML, errno, "strdup");