json list->array

This commit is contained in:
Olof hagsand 2016-09-30 18:49:14 +02:00
parent a0b7d28bd1
commit 831ab1be30

View file

@ -18,8 +18,9 @@
along with CLIXON; see the file LICENSE. If not, see along with CLIXON; see the file LICENSE. If not, see
<http://www.gnu.org/licenses/>. <http://www.gnu.org/licenses/>.
* JSON support functions. * JSON support functions.
* JSON syntax is according to:
* http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf
*/ */
#include <stdio.h> #include <stdio.h>
@ -46,12 +47,17 @@
#define JSON_INDENT 2 /* maybe we should set this programmatically? */ #define JSON_INDENT 2 /* maybe we should set this programmatically? */
enum list_element_type{ /* Let xml2json_cbuf_vec() return json array: [a,b].
NO_LIST=0, ALternative is to create a pseudo-object and return that: {top:{a,b}}
FIRST_LIST, */
MIDDLE_LIST, #define VEC_ARRAY 1
LAST_LIST,
BODY_LIST enum array_element_type{
NO_ARRAY=0,
FIRST_ARRAY,
MIDDLE_ARRAY,
LAST_ARRAY,
BODY_ARRAY
}; };
enum childtype{ enum childtype{
@ -99,39 +105,39 @@ childtype2str(enum childtype lt)
} }
static char* static char*
listtype2str(enum list_element_type lt) arraytype2str(enum array_element_type lt)
{ {
switch(lt){ switch(lt){
case NO_LIST: case NO_ARRAY:
return "no"; return "no";
break; break;
case FIRST_LIST: case FIRST_ARRAY:
return "first"; return "first";
break; break;
case MIDDLE_LIST: case MIDDLE_ARRAY:
return "middle"; return "middle";
break; break;
case LAST_LIST: case LAST_ARRAY:
return "last"; return "last";
break; break;
case BODY_LIST: case BODY_ARRAY:
return "body"; return "body";
break; break;
} }
return ""; return "";
} }
static enum list_element_type static enum array_element_type
list_eval(cxobj *xprev, array_eval(cxobj *xprev,
cxobj *x, cxobj *x,
cxobj *xnext) cxobj *xnext)
{ {
enum list_element_type list = NO_LIST; enum array_element_type array = NO_ARRAY;
int eqprev=0; int eqprev=0;
int eqnext=0; int eqnext=0;
if (xml_type(x)!=CX_ELMNT){ if (xml_type(x)!=CX_ELMNT){
list=BODY_LIST; array=BODY_ARRAY;
goto done; goto done;
} }
if (xnext && if (xnext &&
@ -143,29 +149,29 @@ list_eval(cxobj *xprev,
strcmp(xml_name(x),xml_name(xprev))==0) strcmp(xml_name(x),xml_name(xprev))==0)
eqprev++; eqprev++;
if (eqprev && eqnext) if (eqprev && eqnext)
list = MIDDLE_LIST; array = MIDDLE_ARRAY;
else if (eqprev) else if (eqprev)
list = LAST_LIST; array = LAST_ARRAY;
else if (eqnext) else if (eqnext)
list = FIRST_LIST; array = FIRST_ARRAY;
else else
list = NO_LIST; array = NO_ARRAY;
done: done:
return list; return array;
} }
/*! Do the actual work of translating XML to JSON /*! Do the actual work of translating XML to JSON
* @param[out] cb Cligen text buffer containing json on exit * @param[out] cb Cligen text buffer containing json on exit
* @param[in] x XML tree structure containing XML to translate * @param[in] x XML tree structure containing XML to translate
* @param[in] listtype Does x occur in a list (of its parent) and how? * @param[in] arraytype Does x occur in a array (of its parent) and how?
* @param[in] level Indentation level * @param[in] level Indentation level
* @param[in] pretty Pretty-print output (2 means debug) * @param[in] pretty Pretty-print output (2 means debug)
* *
* The following matrix explains how the mapping is done. * The following matrix explains how the mapping is done.
* You need to understand what listtype means (no/first/middle/last) * You need to understand what arraytype means (no/first/middle/last)
* and what childtype is (null,body,any) * and what childtype is (null,body,any)
+---------+--------------+--------------+--------------+ +---------+--------------+--------------+--------------+
|list,leaf| null | body | any | |array,leaf| null | body | any |
+---------+--------------+--------------+--------------+ +---------+--------------+--------------+--------------+
|no | <a/> |<a>1</a> |<a><b/></a> | |no | <a/> |<a>1</a> |<a><b/></a> |
| | | | | | | | | |
@ -191,7 +197,7 @@ list_eval(cxobj *xprev,
static int static int
xml2json1_cbuf(cbuf *cb, xml2json1_cbuf(cbuf *cb,
cxobj *x, cxobj *x,
enum list_element_type listtype, enum array_element_type arraytype,
int level, int level,
int pretty) int pretty)
{ {
@ -202,15 +208,15 @@ xml2json1_cbuf(cbuf *cb,
childt = childtype(x); childt = childtype(x);
if (pretty==2) if (pretty==2)
cprintf(cb, "#%s_list, %s_child ", cprintf(cb, "#%s_array, %s_child ",
listtype2str(listtype), arraytype2str(arraytype),
childtype2str(childt)); childtype2str(childt));
switch(listtype){ switch(arraytype){
case BODY_LIST: case BODY_ARRAY:
assert(xml_value(x)); assert(xml_value(x));
cprintf(cb, "\"%s\"", xml_value(x)); cprintf(cb, "\"%s\"", xml_value(x));
break; break;
case NO_LIST: case NO_ARRAY:
cprintf(cb, "%*s\"%s\": ", cprintf(cb, "%*s\"%s\": ",
pretty?(level*JSON_INDENT):0, "", pretty?(level*JSON_INDENT):0, "",
xml_name(x)); xml_name(x));
@ -227,7 +233,7 @@ xml2json1_cbuf(cbuf *cb,
break; break;
} }
break; break;
case FIRST_LIST: case FIRST_ARRAY:
cprintf(cb, "%*s\"%s\": ", cprintf(cb, "%*s\"%s\": ",
pretty?(level*JSON_INDENT):0, "", pretty?(level*JSON_INDENT):0, "",
xml_name(x)); xml_name(x));
@ -248,8 +254,8 @@ xml2json1_cbuf(cbuf *cb,
break; break;
} }
break; break;
case MIDDLE_LIST: case MIDDLE_ARRAY:
case LAST_LIST: case LAST_ARRAY:
level++; level++;
cprintf(cb, "%*s", cprintf(cb, "%*s",
pretty?(level*JSON_INDENT):0, ""); pretty?(level*JSON_INDENT):0, "");
@ -270,23 +276,23 @@ xml2json1_cbuf(cbuf *cb,
break; break;
} }
for (i=0; i<xml_child_nr(x); i++){ for (i=0; i<xml_child_nr(x); i++){
enum list_element_type xc_listtype; enum array_element_type xc_arraytype;
xc = xml_child_i(x, i); xc = xml_child_i(x, i);
xc_listtype = list_eval(i?xml_child_i(x,i-1):NULL, xc_arraytype = array_eval(i?xml_child_i(x,i-1):NULL,
xc, xc,
xml_child_i(x, i+1)); xml_child_i(x, i+1));
if (xml2json1_cbuf(cb, if (xml2json1_cbuf(cb,
xc, xc,
xc_listtype, xc_arraytype,
level+1, pretty) < 0) level+1, pretty) < 0)
goto done; goto done;
if (i<xml_child_nr(x)-1) if (i<xml_child_nr(x)-1)
cprintf(cb, ",%s", pretty?"\n":""); cprintf(cb, ",%s", pretty?"\n":"");
} }
switch (listtype){ switch (arraytype){
case BODY_LIST: case BODY_ARRAY:
break; break;
case NO_LIST: case NO_ARRAY:
switch (childt){ switch (childt){
case NULL_CHILD: case NULL_CHILD:
case BODY_CHILD: case BODY_CHILD:
@ -301,8 +307,8 @@ xml2json1_cbuf(cbuf *cb,
} }
level--; level--;
break; break;
case FIRST_LIST: case FIRST_ARRAY:
case MIDDLE_LIST: case MIDDLE_ARRAY:
switch (childt){ switch (childt){
case NULL_CHILD: case NULL_CHILD:
case BODY_CHILD: case BODY_CHILD:
@ -317,7 +323,7 @@ xml2json1_cbuf(cbuf *cb,
break; break;
} }
break; break;
case LAST_LIST: case LAST_ARRAY:
switch (childt){ switch (childt){
case NULL_CHILD: case NULL_CHILD:
case BODY_CHILD: case BODY_CHILD:
@ -376,7 +382,7 @@ xml2json_cbuf(cbuf *cb,
cprintf(cb, "{"); cprintf(cb, "{");
if (xml2json1_cbuf(cb, if (xml2json1_cbuf(cb,
x, x,
NO_LIST, NO_ARRAY,
level+1, pretty) < 0) level+1, pretty) < 0)
goto done; goto done;
if (pretty) if (pretty)
@ -401,26 +407,31 @@ xml2json_cbuf_vec(cbuf *cb,
int level = 0; int level = 0;
int i; int i;
cxobj *xc; cxobj *xc;
enum list_element_type listtype; enum array_element_type arraytype;
#ifdef VEC_ARRAY
cprintf(cb, "[%s", pretty?"\n":" ");
level++;
#else /* pseudo object */
/* Note: We add a pseudo-object on top of the vector. /* Note: We add a pseudo-object on top of the vector.
* This object is list_element_type == NO_LIST in xml2json1_cbuf * This object is array_element_type == NO_ARRAY in xml2json1_cbuf
* and child_type == ANY_CHILD * and child_type == ANY_CHILD
*/ */
cprintf(cb, "{%s", cprintf(cb, "{%s",
pretty?"\n":" "); pretty?"\n":" ");
level++; level++;
cprintf(cb, "%*s\"top\": ", /* NO_LIST */ cprintf(cb, "%*s\"top\": ", /* NO_ARRAY */
pretty?(level*JSON_INDENT):0, ""); pretty?(level*JSON_INDENT):0, "");
cprintf(cb, "{%s", pretty?"\n":""); /* ANY_CHILD */ cprintf(cb, "{%s", pretty?"\n":""); /* ANY_CHILD */
#endif
for (i=0; i<veclen; i++){ for (i=0; i<veclen; i++){
xc = vec[i]; xc = vec[i];
listtype = list_eval(i?vec[i-1]:NULL, arraytype = array_eval(i?vec[i-1]:NULL,
xc, xc,
i<veclen-1?vec[i+1]:NULL); i<veclen-1?vec[i+1]:NULL);
if (xml2json1_cbuf(cb, if (xml2json1_cbuf(cb,
xc, xc,
listtype, arraytype,
level, pretty) < 0) level, pretty) < 0)
goto done; goto done;
if (i<veclen-1){ if (i<veclen-1){
@ -430,12 +441,18 @@ xml2json_cbuf_vec(cbuf *cb,
} }
} }
level--; level--;
#ifdef VEC_ARRAY
cprintf(cb, "%s]%s",
pretty?"\n":"",
pretty?"\n":""); /* top object */
#else /* pseudo object */
cprintf(cb, "%s%*s}", cprintf(cb, "%s%*s}",
pretty?"\n":"", pretty?"\n":"",
pretty?(level*JSON_INDENT):0, ""); pretty?(level*JSON_INDENT):0, "");
cprintf(cb, "%s}%s", cprintf(cb, "%s}%s",
pretty?"\n":"", pretty?"\n":"",
pretty?"\n":""); /* top object */ pretty?"\n":""); /* top object */
#endif
retval = 0; retval = 0;
done: done:
return retval; return retval;