rm xml index; added xml util functions; further xmldb development

This commit is contained in:
Olof hagsand 2017-04-23 22:32:53 +02:00
parent d02015f456
commit c2f52845f8
11 changed files with 653 additions and 187 deletions

View file

@ -75,7 +75,6 @@ struct xml{
int x_childvec_len; /* length of vector */
enum cxobj_type x_type; /* type of node: element, attribute, body */
char *x_value; /* attribute and body nodes have values */
int x_index; /* key node, cf sql index */
int _x_vector_i; /* internal use: xml_child_each */
int x_flags; /* Flags according to XML_FLAG_* above */
void *x_spec; /* Pointer to specification, eg yang, by
@ -83,6 +82,36 @@ struct xml{
cg_var *x_cv; /* If body this contains the typed value */
};
/* Type to string conversion */
struct map_str2int{
char *ms_str;
enum cxobj_type ms_type;
};
/* Mapping between xml type <--> string */
static const struct map_str2int xsmap[] = {
{"error", CX_ERROR},
{"element", CX_ELMNT},
{"attr", CX_ATTR},
{"body", CX_BODY},
{NULL, -1}
};
/*! Translate from xml type in enum form to string keyword
* @param[in] type Xml type
* @retval str String keyword
*/
char *
xml_type2str(enum cxobj_type type)
{
const struct map_str2int *xs;
for (xs = &xsmap[0]; xs->ms_str; xs++)
if (xs->ms_type == type)
return xs->ms_str;
return NULL;
}
/*
* Access functions
*/
@ -222,7 +251,7 @@ xml_value(cxobj *xn)
/*! Set value of xml node, value is copied
* @param[in] xn xml node
* @param[in] val new value, null-terminated string, copied by function
* @param[in] val new value, null-terminated string, copied by function
* @retval -1 on error with clicon-err set
* @retval 0 OK
*/
@ -293,33 +322,6 @@ xml_type_set(cxobj *xn,
return old;
}
/*! Get index/key of xnode
* @param[in] xn xml node
* @retval index of xml node
* index/key is used in case of yang list constructs where one element is key
*/
int
xml_index(cxobj *xn)
{
return xn->x_index;
}
/*! Set index of xnode
* @param[in] xn xml node
* @param[in] index new index
* @retval index old index
* index/key is used in case of yang list constructs where one element is key
*/
int
xml_index_set(cxobj *xn,
int index)
{
int old = xn->x_index;
xn->x_index = index;
return old;
}
/*! Get cligen variable associated with node
* @param[in] xn xml node
* @retval cv Cligen variable if set
@ -757,6 +759,16 @@ xml_body(cxobj *xn)
return NULL;
}
cxobj *
xml_body_get(cxobj *xn)
{
cxobj *xb = NULL;
while ((xb = xml_child_each(xn, xb, CX_BODY)) != NULL)
return xb;
return NULL;
}
/*! Find and return the value of a sub xml node
*
* The value can be of an attribute or body.
@ -881,8 +893,8 @@ xml_print(FILE *f,
/*! Print an XML tree structure to a cligen buffer
*
* @param[in,out] cb Cligen buffer to write to
* @param[in] xn clicon xml tree
* @param[in] level how many spaces to insert before each line
* @param[in] xn Clicon xml tree
* @param[in] level Indentation level
* @param[in] prettyprint insert \n and spaces tomake the xml more readable.
*
* @code
@ -896,47 +908,50 @@ xml_print(FILE *f,
*/
int
clicon_xml2cbuf(cbuf *cb,
cxobj *cx,
cxobj *x,
int level,
int prettyprint)
{
cxobj *xc;
char *name;
switch(xml_type(cx)){
name = xml_name(x);
switch(xml_type(x)){
case CX_BODY:
cprintf(cb, "%s", xml_value(cx));
cprintf(cb, "%s", xml_value(x));
break;
case CX_ATTR:
cprintf(cb, " ");
if (xml_namespace(cx))
cprintf(cb, "%s:", xml_namespace(cx));
cprintf(cb, "%s=\"%s\"", xml_name(cx), xml_value(cx));
if (xml_namespace(x))
cprintf(cb, "%s:", xml_namespace(x));
cprintf(cb, "%s=\"%s\"", name, xml_value(x));
break;
case CX_ELMNT:
cprintf(cb, "%*s<", prettyprint?(level*XML_INDENT):0, "");
if (xml_namespace(cx))
cprintf(cb, "%s:", xml_namespace(cx));
cprintf(cb, "%s", xml_name(cx));
if (xml_namespace(x))
cprintf(cb, "%s:", xml_namespace(x));
cprintf(cb, "%s", name);
xc = NULL;
while ((xc = xml_child_each(cx, xc, CX_ATTR)) != NULL)
/* print attributes only */
while ((xc = xml_child_each(x, xc, CX_ATTR)) != NULL)
clicon_xml2cbuf(cb, xc, level+1, prettyprint);
/* Check for special case <a/> instead of <a></a> */
if (xml_body(cx)==NULL && xml_child_nr(cx)==0)
if (xml_body(x)==NULL && xml_child_nr(x)==0)
cprintf(cb, "/>");
else{
cprintf(cb, ">");
if (prettyprint && xml_body(cx)==NULL)
if (prettyprint && xml_body(x)==NULL)
cprintf(cb, "\n");
xc = NULL;
while ((xc = xml_child_each(cx, xc, -1)) != NULL) {
while ((xc = xml_child_each(x, xc, -1)) != NULL) {
if (xml_type(xc) == CX_ATTR)
continue;
else
clicon_xml2cbuf(cb, xc, level+1, prettyprint);
}
if (prettyprint && xml_body(cx)==NULL)
if (prettyprint && xml_body(x)==NULL)
cprintf(cb, "%*s", level*XML_INDENT, "");
cprintf(cb, "</%s>", xml_name(cx));
cprintf(cb, "</%s>", name);
}
if (prettyprint)
cprintf(cb, "\n");
@ -975,6 +990,44 @@ xml_parse(char *str,
return retval;
}
/*! Print actual xml tree datastructures (not xml), mainly for debugging
* @param[in,out] cb Cligen buffer to write to
* @param[in] xn Clicon xml tree
* @param[in] level Indentation level
*/
int
xmltree2cbuf(cbuf *cb,
cxobj *x,
int level)
{
cxobj *xc;
int i;
for (i=0; i<level*XML_INDENT; i++)
cprintf(cb, " ");
cprintf(cb, "%s", xml_type2str(xml_type(x)));
if (xml_namespace(x)==NULL)
cprintf(cb, " %s", xml_name(x));
else
cprintf(cb, " %s:%s", xml_namespace(x), xml_name(x));
if (xml_value(x))
cprintf(cb, " value:\"%s\"", xml_value(x));
if (x->x_flags)
cprintf(cb, " flags:0x%x", x->x_flags);
if (xml_child_nr(x))
cprintf(cb, " {");
cprintf(cb, "\n");
xc = NULL;
while ((xc = xml_child_each(x, xc, -1)) != NULL)
xmltree2cbuf(cb, xc, level+1);
if (xml_child_nr(x)){
for (i=0; i<level*XML_INDENT; i++)
cprintf(cb, " ");
cprintf(cb, "}\n");
}
return 0;
}
/*
* FSM to detect a substring
*/
@ -1534,3 +1587,51 @@ xml_operation2str(enum operation_type op)
}
}
/*
* Turn this on to get a xml parse and pretty print test program
* Usage: xpath
* read xml from input
* Example compile:
gcc -g -o xml -I. -I../clixon ./clixon_xml.c -lclixon -lcligen
* Example run:
echo "<a><b/></a>" | xml
*/
#if 0 /* Test program */
static int
usage(char *argv0)
{
fprintf(stderr, "usage:%s.\n\tInput on stdin\n", argv0);
exit(0);
}
int
main(int argc, char **argv)
{
cxobj *xt;
cxobj *xc;
cbuf *cb = cbuf_new();
if (argc != 1){
usage(argv[0]);
return 0;
}
if (clicon_xml_parse_file(0, &xt, "</config>") < 0){
fprintf(stderr, "parsing 2\n");
return -1;
}
xc = NULL;
while ((xc = xml_child_each(xt, xc, -1)) != NULL) {
xmltree2cbuf(cb, xc, 0); /* dump data structures */
//clicon_xml2cbuf(cb, xc, 0, 1); /* print xml */
}
fprintf(stdout, "%s", cbuf_get(cb));
if (xt)
xml_free(xt);
if (cb)
cbuf_free(cb);
return 0;
}
#endif /* Test program */

View file

@ -67,7 +67,7 @@
* If init function fails (not found, wrong version, etc) print a log and dont
* add it.
* @param[in] h CLicon handle
* @param[in] filename Actual filename with path
* @param[in] filename Actual filename including path
*/
int
xmldb_plugin_load(clicon_handle h,
@ -125,7 +125,11 @@ xmldb_plugin_load(clicon_handle h,
goto done;
}
/*! Unload the xmldb storage plugin */
/*! Unload the xmldb storage plugin
* @param[in] h Clicon handle
* @retval 0 OK
* @retval -1 Error
*/
int
xmldb_plugin_unload(clicon_handle h)
{
@ -162,9 +166,10 @@ xmldb_plugin_unload(clicon_handle h)
return retval;
}
/*! Connect to a datastore plugin
* @retval handle Use this handle for other API calls
* @retval NULL Error
/*! Connect to a datastore plugin, allocate handle to be used in API calls
* @param[in] h Clicon handle
* @retval 0 OK
* @retval -1 Error
* @note You can do several connects, and have multiple connections to the same
* datastore. Note also that the xmldb handle is hidden in the clicon
* handle, the clixon user does not need to handle it. Note also that
@ -196,7 +201,8 @@ xmldb_connect(clicon_handle h)
/*! Disconnect from a datastore plugin and deallocate handle
* @param[in] handle Disconect and deallocate from this handle
* @retval 0 OK
*/
* @retval -1 Error
*/
int
xmldb_disconnect(clicon_handle h)
{
@ -225,7 +231,7 @@ xmldb_disconnect(clicon_handle h)
}
/*! Get value of generic plugin option. Type of value is givenby context
* @param[in] xh XMLDB handle
* @param[in] h Clicon handle
* @param[in] optname Option name
* @param[out] value Pointer to Value of option
* @retval 0 OK
@ -258,7 +264,7 @@ xmldb_getopt(clicon_handle h,
}
/*! Set value of generic plugin option. Type of value is givenby context
* @param[in] xh XMLDB handle
* @param[in] h Clicon handle
* @param[in] optname Option name
* @param[in] value Value of option
* @retval 0 OK
@ -404,8 +410,9 @@ xmldb_put(clicon_handle h,
#if 0 /* XXX DEBUG */
{
cbuf *cb = cbuf_new();
if (clicon_xml2cbuf(cb, xt, 0, 0) < 0)
goto done;
if (xt)
if (clicon_xml2cbuf(cb, xt, 0, 0) < 0)
goto done;
clicon_log(LOG_WARNING, "%s: db:%s op:%d api_path:%s xml:%s", __FUNCTION__,
db, op, api_path, cbuf_get(cb));

View file

@ -241,7 +241,7 @@ xml2cli(FILE *f,
!index GT_VARS T
!index GT_ALL T
*/
bool = !leaf(x) || gt == GT_ALL || (gt == GT_VARS && !xml_index(x));
bool = !leaf(x) || gt == GT_ALL || (gt == GT_VARS);
// bool = (!x->xn_index || gt == GT_ALL);
if (bool){
if (cbuf_len(cbpre))
@ -253,12 +253,12 @@ xml2cli(FILE *f,
i = 0;
while ((xe = xml_child_each(x, xe, -1)) != NULL){
/* Dont call this if it is index and there are other following */
if (xml_index(xe) && i < nr-1)
if (0 && i < nr-1)
;
else
if (xml2cli(f, xe, cbuf_get(cbpre), gt) < 0)
goto done;
if (xml_index(xe)){ /* assume index is first, otherwise need one more while */
if (0){ /* assume index is first, otherwise need one more while */
if (gt == GT_ALL)
cprintf(cbpre, " %s", xml_name(xe));
cprintf(cbpre, " %s", xml_value(xml_child_i(xe, 0)));

View file

@ -175,8 +175,10 @@ xml_parse_endslash_post(struct xml_parse_yacc_arg *ya)
return 0;
}
/*! Called at </name> */
static int
xml_parse_bslash1(struct xml_parse_yacc_arg *ya, char *name)
xml_parse_bslash1(struct xml_parse_yacc_arg *ya,
char *name)
{
int retval = -1;
cxobj *x = ya->ya_xelement;
@ -199,8 +201,10 @@ xml_parse_bslash1(struct xml_parse_yacc_arg *ya, char *name)
;
else{
xc = NULL;
while ((xc = xml_child_each(x, xc, CX_BODY)) != NULL)
xml_value_set(xc, ""); /* XXX remove */
while ((xc = xml_child_each(x, xc, CX_BODY)) != NULL) {
xml_purge(xc);
xc = NULL; /* reset iterator */
}
}
}
retval = 0;
@ -209,8 +213,11 @@ xml_parse_bslash1(struct xml_parse_yacc_arg *ya, char *name)
return retval;
}
/*! Called at </namespace:name> */
static int
xml_parse_bslash2(struct xml_parse_yacc_arg *ya, char *namespace, char *name)
xml_parse_bslash2(struct xml_parse_yacc_arg *ya,
char *namespace,
char *name)
{
int retval = -1;
cxobj *x = ya->ya_xelement;

View file

@ -160,6 +160,10 @@ static const struct map_str2int ykmap[] = {
{NULL, -1}
};
/*! Create new yang specification
* @retval yspec Free with yspec_free()
* @retval NULL Error
*/
yang_spec *
yspec_new(void)
{
@ -174,6 +178,10 @@ yspec_new(void)
return yspec;
}
/*! Create new yang node/statement
* @retval ys Free with ys_free()
* @retval NULL Error
*/
yang_stmt *
ys_new(enum rfc_6020 keyw)
{