* JSON encoding of YANG metadata according to RFC 7952

* XML -> JSON translation
This commit is contained in:
Olof hagsand 2021-08-17 15:15:37 +02:00
parent 76e59873c2
commit 6bf3112fe7
8 changed files with 145 additions and 29 deletions

View file

@ -688,6 +688,39 @@ nullchild(cbuf *cb,
return retval;
}
/*!
{
"example-social:uint8-numbers": [17],
"@example-social:uint8-numbers": [
{
"ietf-list-pagination:remaining": 5
}
]
}
*/
static int
json_metadata_encoding(cbuf *cb,
cxobj *x,
int level,
int pretty,
char *modname,
char *name,
char *modname2,
char *name2,
char *val)
{
int retval = -1;
cprintf(cb, ",\"@%s:%s\": [", modname, name);
cprintf(cb, "%*s", pretty?((level+1)*JSON_INDENT):0, "{");
cprintf(cb, "\"%s:%s\": %s", modname2, name2, val);
cprintf(cb, "%*s", pretty?((level+1)*JSON_INDENT):0, "}");
cprintf(cb, "%*s", pretty?(level*JSON_INDENT):0, "]");
retval = 0;
// done:
return retval;
}
/*! Do the actual work of translating XML to JSON
* @param[out] cb Cligen text buffer containing json on exit
* @param[in] x XML tree structure containing XML to translate
@ -840,13 +873,8 @@ xml2json1_cbuf(cbuf *cb,
commas = xml_child_nr_notype(x, CX_ATTR) - 1;
for (i=0; i<xml_child_nr(x); i++){
xc = xml_child_i(x, i);
if (xml_type(xc) == CX_ATTR){
#if 1 /* Work in progress, identify md:annotations */
continue;
#else
if (xml_type(xc) == CX_ATTR)
continue; /* XXX Only xmlns attributes mapped */
#endif
}
xc_arraytype = array_eval(i?xml_child_i(x,i-1):NULL,
xc,
xml_child_i(x, i+1));
@ -860,6 +888,35 @@ xml2json1_cbuf(cbuf *cb,
--commas;
}
}
#ifdef LIST_PAGINATION /* identify md:annotations as RFC 7952 Sec 5.2.1*/
for (i=0; i<xml_child_nr(x); i++){
xc = xml_child_i(x, i);
if (xml_type(xc) == CX_ATTR){
int ismeta = 0;
char *namespace = NULL;
yang_stmt *ymod;
if (xml2ns(xc, xml_prefix(xc), &namespace) < 0)
goto done;
if (namespace == NULL)
continue;
if ((ymod = yang_find_module_by_namespace(ys_spec(ys), namespace)) == NULL)
continue;
if (xml2ns(xc, xml_prefix(xc), &namespace) < 0)
goto done;
if (yang_metadata_annotation_check(xc, ymod, &ismeta) < 0)
goto done;
if (!ismeta)
continue;
if (json_metadata_encoding(cb, x, level, pretty,
modname, xml_name(x),
yang_argument_get(ymod),
xml_name(xc),
xml_value(xc)) < 0)
goto done;
}
}
#endif
switch (arraytype){
case BODY_ARRAY:
break;

View file

@ -935,7 +935,7 @@ clicon_rpc_get_pageable_list(clicon_handle h,
goto done;
if ((cb = cbuf_new()) == NULL)
goto done;
cprintf(cb, "<rpc xmlns=\"%s\" ", NETCONF_BASE_NAMESPACE);
cprintf(cb, "<rpc xmlns=\"%s\"", NETCONF_BASE_NAMESPACE);
if ((username = clicon_username_get(h)) != NULL)
cprintf(cb, " username=\"%s\"", username);
cprintf(cb, " xmlns:%s=\"%s\"",

View file

@ -879,7 +879,7 @@ yn_each(yang_stmt *yparent,
/*! Find first child yang_stmt with matching keyword and argument
*
* @param[in] yn Yang node, current context node.
* @param[in] keyword if 0 match any keyword
* @param[in] keyword if 0 match any keyword. Actual type: enum rfc_6020
* @param[in] argument String compare w argument. if NULL, match any.
* @retval ys Yang statement, if any
* This however means that if you actually want to match only a yang-stmt with

View file

@ -690,6 +690,7 @@ yang_find_module_by_name(yang_stmt *yspec,
* as described in Section 3.
* Note this is called by the module using the extension md:annotate, not by
* ietf-yang-metadata.yang
* @see yang_metadata_annotation_check
*/
static int
ietf_yang_metadata_extension_cb(clicon_handle h,
@ -700,13 +701,15 @@ ietf_yang_metadata_extension_cb(clicon_handle h,
char *extname;
char *modname;
yang_stmt *ymod;
char *name;
ymod = ys_module(yext);
modname = yang_argument_get(ymod);
extname = yang_argument_get(yext);
if (strcmp(modname, "ietf-yang-metadata") != 0 || strcmp(extname, "annotation") != 0)
goto ok;
clicon_debug(1, "%s Enabled extension:%s:%s", __FUNCTION__, modname, extname);
name = cv_string_get(yang_cv_get(ys));
clicon_debug(1, "%s Enabled extension:%s:%s:%s", __FUNCTION__, modname, extname, name);
/* XXX Nothing yet - this should signal that xml attribute annotations are allowed
* Possibly, add an "annotation" YANG node.
*/
@ -716,6 +719,48 @@ ietf_yang_metadata_extension_cb(clicon_handle h,
return retval;
}
/*! Check annotation extension
*
* @param[in] xa XML attribute
* @param[in] ys YANG something
* @param[out] ismeta Set to 1 if this is an annotation
* @retval 0 OK
* @retval -1 Error
* @see ietf_yang_metadata_extension_cb
* XXX maybe a cache would be appropriate?
* XXX: return type?
*/
int
yang_metadata_annotation_check(cxobj *xa,
yang_stmt *ymod,
int *ismeta)
{
int retval = -1;
yang_stmt *yma = NULL;
char *name;
cg_var *cv;
/* Loop through annotations */
while ((yma = yn_each(ymod, yma)) != NULL){
/* Assume here md:annotation is written using canonical prefix */
if (yang_keyword_get(yma) != Y_UNKNOWN)
continue;
if (strcmp(yang_argument_get(yma), "md:annotation") != 0)
continue;
if ((cv = yang_cv_get(yma)) != NULL &&
(name = cv_string_get(cv)) != NULL){
if (strcmp(name, xml_name(xa)) == 0){
/* XXX: yang_find(yma,Y_TYPE,0) */
*ismeta = 1;
break;
}
}
}
retval = 0;
// done:
return retval;
}
/*! In case ietf-yang-metadata is loaded by application, handle annotation extension
* Consider moving fn
*/