rm xml index; added xml util functions; further xmldb development
This commit is contained in:
parent
d02015f456
commit
c2f52845f8
11 changed files with 653 additions and 187 deletions
|
|
@ -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 */
|
||||
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -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)));
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue