Added top-level namespaces when pruning XML tree for client rpc calls and restconf GET

Added new xmlns_set_all()
This commit is contained in:
Olof hagsand 2022-08-26 13:29:06 +02:00
parent 9be83d6c7e
commit ad7232d1ad
13 changed files with 83 additions and 23 deletions

View file

@ -525,7 +525,6 @@ with_defaults(cxobj *xe, cxobj *xret) {
}
}
}
ok:
retval = 0;
done:
return retval;

View file

@ -116,7 +116,6 @@ api_data_get2(clicon_handle h,
int i;
cxobj *x;
int ret;
char *namespace = NULL;
cvec *nsc = NULL;
char *attr; /* attribute value string */
netconf_content content = CONTENT_ALL;
@ -124,7 +123,8 @@ api_data_get2(clicon_handle h,
cxobj *xtop = NULL;
cxobj *xbot = NULL;
yang_stmt *y = NULL;
char *defaults = NULL;
char *defaults = NULL;
cvec *nscd = NULL;
clicon_debug(1, "%s", __FUNCTION__);
if ((yspec = clicon_dbspec_yang(h)) == NULL){
@ -266,16 +266,11 @@ api_data_get2(clicon_handle h,
switch (media_out){
case YANG_DATA_XML:
for (i=0; i<xlen; i++){
char *prefix;
x = xvec[i];
/* Some complexities in grafting namespace in existing trees to new */
prefix = xml_prefix(x);
if (xml_find_type_value(x, prefix, "xmlns", CX_ATTR) == NULL){
if (xml2ns(x, prefix, &namespace) < 0)
goto done;
if (namespace && xmlns_set(x, prefix, namespace) < 0)
goto done;
}
if (xml_nsctx_node(x, &nscd) < 0)
goto done;
if (xmlns_set_all(x, nscd) < 0)
goto done;
if (clixon_xml2cbuf(cbx, x, 0, pretty, -1, 0) < 0) /* Dont print top object? */
goto done;
}
@ -305,6 +300,8 @@ api_data_get2(clicon_handle h,
clicon_debug(1, "%s retval:%d", __FUNCTION__, retval);
if (xpath)
free(xpath);
if (nscd)
xml_nsctx_free(nscd);
if (nsc)
xml_nsctx_free(nsc);
if (xtop)

View file

@ -194,8 +194,6 @@ cvec *nscache_get_all(cxobj *x);
int nscache_set(cxobj *x, char *prefix, char *ns);
int nscache_clear(cxobj *x);
int nscache_replace(cxobj *x, cvec *ns);
int xmlns_set(cxobj *x, char *prefix, char *ns);
cxobj *xml_parent(cxobj *xn);
int xml_parent_set(cxobj *xn, cxobj *parent);
#ifdef XML_PARENT_CANDIDATE

View file

@ -63,6 +63,8 @@ int xml_nsctx_cbuf(cbuf *cb, cvec *nsc);
int xml2ns(cxobj *x, char *localname, char **ns);
int xml2ns_recurse(cxobj *x);
int xmlns_set(cxobj *x, char *prefix, char *ns);
int xmlns_set_all(cxobj *x, cvec *nsc);
int xml2prefix(cxobj *xn, char *ns, char **prefixp);
#endif /* _CLIXON_XML_NSCTX_H */

View file

@ -500,6 +500,7 @@ clicon_rpc_get_config(clicon_handle h,
uint32_t session_id;
int ret;
yang_stmt *yspec;
cvec *nscd = NULL;
if (session_id_check(h, &session_id) < 0)
goto done;
@ -554,12 +555,20 @@ clicon_rpc_get_config(clicon_handle h,
}
}
if (xt && xd){
/* Sync namespaces, ie explicitly set all xmlns attributes to xd */
if (xml_nsctx_node(xd, &nscd) < 0)
goto done;
if (xml_rm(xd) < 0)
goto done;
if (xmlns_set_all(xd, nscd) < 0)
goto done;
xml_sort(xd); /* Ensure attr is first */
*xt = xd;
}
retval = 0;
done:
if (nscd)
cvec_free(nscd);
if (cb)
cbuf_free(cb);
if (xerr)
@ -858,7 +867,7 @@ clicon_rpc_get(clicon_handle h,
cvec *nsc, /* namespace context for filter */
netconf_content content,
int32_t depth,
char *defaults,
char *defaults,
cxobj **xt)
{
int retval = -1;
@ -871,6 +880,7 @@ clicon_rpc_get(clicon_handle h,
uint32_t session_id;
int ret;
yang_stmt *yspec;
cvec *nscd = NULL;
if (session_id_check(h, &session_id) < 0)
goto done;
@ -932,12 +942,20 @@ clicon_rpc_get(clicon_handle h,
}
}
if (xt && xd){
/* Sync namespaces, ie explicitly set all xmlns attributes to xd */
if (xml_nsctx_node(xd, &nscd) < 0)
goto done;
if (xml_rm(xd) < 0)
goto done;
if (xmlns_set_all(xd, nscd) < 0)
goto done;
xml_sort(xd); /* Ensure attr is first */
*xt = xd;
}
retval = 0;
done:
if (nscd)
cvec_free(nscd);
if (cb)
cbuf_free(cb);
if (xerr)
@ -993,6 +1011,7 @@ clicon_rpc_get_pageable_list(clicon_handle h,
uint32_t session_id;
int ret;
yang_stmt *yspec;
cvec *nscd = NULL;
if (datastore == NULL){
clicon_err(OE_XML, EINVAL, "datastore not given");
@ -1072,12 +1091,20 @@ clicon_rpc_get_pageable_list(clicon_handle h,
}
}
if (xt && xd){
/* Sync namespaces, ie explicitly set all xmlns attributes to xd */
if (xml_nsctx_node(xd, &nscd) < 0)
goto done;
if (xml_rm(xd) < 0)
goto done;
if (xmlns_set_all(xd, nscd) < 0)
goto done;
xml_sort(xd); /* Ensure attr is first */
*xt = xd;
}
retval = 0;
done:
if (nscd)
cvec_free(nscd);
if (cb)
cbuf_free(cb);
if (xerr)

View file

@ -77,6 +77,7 @@
#include "clixon_handle.h"
#include "clixon_yang.h"
#include "clixon_xml.h"
#include "clixon_xml_nsctx.h"
#include "clixon_xml_vec.h"
#include "clixon_data.h"
#include "clixon_text_syntax_parse.h"

View file

@ -597,6 +597,42 @@ xmlns_set(cxobj *x,
return retval;
}
/*! Given an xml node x and a namespace context, add namespace xmlns attributes to x
*
* As a side-effect, the namespace cache is set
* Check if already there
* @param[in] x XML tree
* @param[in] nsc Namespace context
* @note you need to do an xml_sort(x) after the call
*/
int
xmlns_set_all(cxobj *x,
cvec *nsc)
{
int retval = -1;
char *ns;
char *pf;
cg_var *cv = NULL;
while ((cv = cvec_each(nsc, cv)) != NULL){
pf = cv_name_get(cv);
/* Check already added */
if (pf != NULL) /* xmlns:<prefix>="<uri>" */
ns = xml_find_type_value(x, "xmlns", pf, CX_ATTR);
else{ /* xmlns="<uri>" */
ns = xml_find_type_value(x, NULL, "xmlns", CX_ATTR);
}
if (ns)
continue;
ns = cv_string_get(cv);
if (ns && xmlns_set(x, pf, ns) < 0)
goto done;
}
retval = 0;
done:
return retval;
}
/*! Get prefix of given namespace recursively
* @param[in] xn XML node
* @param[in] namespace Namespace

View file

@ -89,7 +89,7 @@ expectpart "$($clixon_cli -1 -f $cfg -l o debug backend 1)" 0 "^$"
# Exercise debug code
new "get and put config using restconf"
expectpart "$(curl $CURLOPTS -H "Accept: application/yang-data+xml" -X GET $RCPROTO://localhost/restconf/data?content=config --next $CURLOPTS -H "Content-Type: application/yang-data+json" -X POST $RCPROTO://localhost/restconf/data -d '{"example:table":{"parameter":{"name":"local0","value":"foo"}}}')" 0 "HTTP/$HVER 200" '<data/>' "HTTP/$HVER 201"
expectpart "$(curl $CURLOPTS -H "Accept: application/yang-data+xml" -X GET $RCPROTO://localhost/restconf/data?content=config --next $CURLOPTS -H "Content-Type: application/yang-data+json" -X POST $RCPROTO://localhost/restconf/data -d '{"example:table":{"parameter":{"name":"local0","value":"foo"}}}')" 0 "HTTP/$HVER 200" "<data $DEFAULTONLY/>" "HTTP/$HVER 201"
# In freebsd, backend dies in stop_restconf below unless sleep
sleep $DEMSLEEP

View file

@ -146,11 +146,11 @@ fi
# XXX ftest har \n
# Only compare relevant data line
echo -n "<data>">> $ftest
echo -n "<data $DEFAULTONLY>">> $ftest
cat $fdataxml >> $ftest
echo -n "</data>" >> $ftest
# -i (ignore case) dont always work properly
sed '/<data>/!d' $foutput > $foutput2
sed "/<data $DEFAULTONLY>/!d" $foutput > $foutput2
# Strip potential newlines, curl seems to leave trailing newlines on some platforms/versions
tr -d "\n\r" < $foutput2 > $foutput

View file

@ -161,11 +161,11 @@ if [ $r -ne 0 ]; then
fi
# Only compare relevant data line
echo -n "<data>">> $ftest
echo -n "<data $DEFAULTONLY>">> $ftest
cat $fdataxml >> $ftest
#echo "</data> " >> $ftest
echo -n "</data>" >> $ftest
sed '/<data>/!d' $foutput > $foutput2
sed "/<data $DEFAULTONLY>/!d" $foutput > $foutput2
mv $foutput2 $foutput
ret=$(diff -i $ftest $foutput)

View file

@ -206,7 +206,7 @@ expectpart "$(curl $CURLOPTS -X DELETE $RCPROTO://localhost/restconf/data)" 0 "H
#--------------- Multiple request in single TCP tests
new "Multiple requests: GET + POST using --next"
expectpart "$(curl $CURLOPTS -H "Accept: application/yang-data+xml" -X GET $RCPROTO://localhost/restconf/data?content=config --next $CURLOPTS -H "Content-Type: application/yang-data+json" -X POST $RCPROTO://localhost/restconf/data -d '{"example:cont1":{"interface":{"name":"local0","type":"regular"}}}')" 0 "HTTP/$HVER 200" '<data/>' "HTTP/$HVER 201"
expectpart "$(curl $CURLOPTS -H "Accept: application/yang-data+xml" -X GET $RCPROTO://localhost/restconf/data?content=config --next $CURLOPTS -H "Content-Type: application/yang-data+json" -X POST $RCPROTO://localhost/restconf/data -d '{"example:cont1":{"interface":{"name":"local0","type":"regular"}}}')" 0 "HTTP/$HVER 200" "<data $DEFAULTONLY/>" "HTTP/$HVER 201"
new "Multiple requests: POST + POST" # XXX Do for HTTP/1 ALSO
expectpart "$(curl $CURLOPTS -H "Content-Type: application/yang-data+json" -X POST $RCPROTO://localhost/restconf/data/example:cont1 -d '{"example:interface":{"name":"local1","type":"regular"}}' --next $CURLOPTS -H "Content-Type: application/yang-data+json" -X POST $RCPROTO://localhost/restconf/data/example:cont1 -d '{"example:interface":{"name":"local2","type":"regular"}}')" 0 "HTTP/$HVER 201" "localhost/restconf/data/example:cont1/interface=local1" "localhost/restconf/data/example:cont1/interface=local2"

View file

@ -252,7 +252,7 @@ new "PATCH on root resource extra c" # merge extra/c
expectpart "$(curl -u andy:bar $CURLOPTS -X PATCH -H "Content-Type: application/yang-data+json" $RCPROTO://localhost/restconf/data -d '{"ietf-restconf:data":{"example-jukebox:extra":"c"}}')" 0 "HTTP/$HVER 204"
new "GET check" # XXX: "data" should probably be namespaced?
expectpart "$(curl -u andy:bar $CURLOPTS -X GET $RCPROTO://localhost/restconf/data?content=config -H 'Accept: application/yang-data+xml')" 0 "HTTP/$HVER 200" '<extra xmlns="http://example.com/ns/example-jukebox">c</extra>' '<data>'
expectpart "$(curl -u andy:bar $CURLOPTS -X GET $RCPROTO://localhost/restconf/data?content=config -H 'Accept: application/yang-data+xml')" 0 "HTTP/$HVER 200" '<extra xmlns="http://example.com/ns/example-jukebox">c</extra>' "<data $DEFAULTONLY>"
new "Add empty leaf"
expectpart "$(curl -u andy:bar $CURLOPTS -X POST $RCPROTO://localhost/restconf/data -H 'Content-Type: application/yang-data+json' -d '{"example-system:system":{"extraleaf":""}}')" 0 "HTTP/$HVER 201"

View file

@ -479,7 +479,7 @@ expectpart "$(curl $CURLOPTS -X GET -H 'Accept: application/yang-data+xml' $RCPR
"HTTP/$HVER 200" \
"Content-Type: application/yang-data+xml" \
"Cache-Control: no-cache" \
'<interface xmlns="http://example.com/ns/interfaces"><name>eth1</name><mtu wd:default="true">1500</mtu><status wd:default="true">ok</status></interface>'
'<interface xmlns="http://example.com/ns/interfaces" xmlns:wd="urn:ietf:params:xml:ns:netconf:default:1.0"><name>eth1</name><mtu wd:default="true">1500</mtu><status wd:default="true">ok</status></interface>'
if [ $RC -ne 0 ]; then