YAZ_EXPORT
const char *json_parser_get_errmsg(json_parser_t p);
+/** \brief parses JSON string
+ \param json_str JSON string
+ \param errmsg pointer to error message string
+ \returns JSON tree or NULL if parse error occurred.
+
+ The resulting tree should be removed with a call to json_remove_node.
+ The errmsg may be NULL in which case the error message is not returned.
+*/
+YAZ_EXPORT
+struct json_node *json_parse(const char *json_str, const char **errmsg);
+
/** \brief destroys JSON tree node and its children
\param n JSON node
*/
YAZ_EXPORT
void json_remove_node(struct json_node *n);
+/** \brief gets object pair value for some name
+ \param n JSON node (presumably object node)
+ \param name name to match
+ \returns node or NULL if not found
+*/
+YAZ_EXPORT
+struct json_node *json_get_object(struct json_node *n, const char *name);
+
+/** \brief gets object value and detaches from existing tree
+ \param n JSON node (presumably object node)
+ \param name name to match
+ \returns node or NULL if not found
+*/
+YAZ_EXPORT
+struct json_node *json_detach_object(struct json_node *n, const char *name);
+
+/** \brief gets array element
+ \param n JSON node (presumably array node)
+ \param idx (0=first, 1=second, ..)
+ \returns node or NULL if not found
+*/
+YAZ_EXPORT
+struct json_node *json_get_elem(struct json_node *n, int idx);
+
+/** \brief returns number of children (array or object)
+ \param n JSON node (presumably array node or object node)
+ \returns number of children
+*/
+YAZ_EXPORT
+int json_count_children(struct json_node *n);
+
+/** \brief appends array to another
+ \param dst original array and resulting array
+ \param src array to be appended to dst
+ \retval -1 not arrays
+ \retval 0 array appended OK
+*/
+YAZ_EXPORT
+int json_append_array(struct json_node *dst, struct json_node *src);
+
+/** \brief configure subst rule
+ \param p JSON parser
+ \param idx (%id)
+ \param node node to be substituted for idx (%idx)
+*/
+YAZ_EXPORT
+void json_parser_subst(json_parser_t p, int idx, struct json_node *n);
+
/** \brief converts JSON tree to JSON string
\param node JSON tree
\param result resulting JSON string buffer
#include <yaz/xmalloc.h>
+struct json_subst_info {
+ int idx;
+ struct json_subst_info *next;
+ struct json_node *node;
+};
+
struct json_parser_s {
const char *buf;
const char *cp;
const char *err_msg;
+ struct json_subst_info *subst;
};
json_parser_t json_parser_create(void)
p->buf = 0;
p->cp = 0;
p->err_msg = 0;
+ p->subst = 0;
return p;
}
+void json_parser_subst(json_parser_t p, int idx, struct json_node *n)
+{
+ struct json_subst_info **sb = &p->subst;
+ for (; *sb; sb = &(*sb)->next)
+ if ((*sb)->idx == idx)
+ {
+ (*sb)->node = n;
+ return;
+ }
+ *sb = xmalloc(sizeof(**sb));
+ (*sb)->next = 0;
+ (*sb)->node = n;
+ (*sb)->idx = idx;
+}
+
void json_parser_destroy(json_parser_t p)
{
+ struct json_subst_info *sb = p->subst;
+ while (sb)
+ {
+ struct json_subst_info *sb_next = sb->next;
+ xfree(sb);
+ sb = sb_next;
+ }
xfree(p);
}
return json_parse_object(p);
else if (c == '[')
return json_parse_array(p);
+ else if (c == '%')
+ {
+ struct json_subst_info *sb;
+ int idx = 0;
+ p->cp++;
+ c = *p->cp;
+ while (c >= '0' && c <= '9')
+ {
+ idx = idx*10 + (c - '0');
+ p->cp++;
+ c = *p->cp;
+ }
+ for (sb = p->subst; sb; sb = sb->next)
+ if (sb->idx == idx)
+ return sb->node;
+ }
else
{
char tok[8];
return json_new_node(p, json_node_false);
else if (!strcmp(tok, "null"))
return json_new_node(p, json_node_null);
- else
- {
- p->err_msg = "bad value";
- return 0;
- }
}
+ p->err_msg = "bad token";
+ return 0;
}
static struct json_node *json_parse_elements(json_parser_t p)
return 0;
if (look_ch(p) != ':')
{
+ p->err_msg = "missing :";
json_remove_node(s);
return 0;
}
p->cp = p->buf;
n = json_parse_object(p);
+ if (!n)
+ return 0;
c = look_ch(p);
if (c != 0)
{
return n;
}
+struct json_node *json_parse(const char *json_str, const char **errmsg)
+{
+ json_parser_t p = json_parser_create();
+ struct json_node *n = 0;
+ if (!p)
+ {
+ if (errmsg)
+ *errmsg = "could not create parser";
+ }
+ else
+ {
+ n = json_parser_parse(p, json_str);
+ if (!n && errmsg)
+ *errmsg = json_parser_get_errmsg(p);
+ json_parser_destroy(p);
+ }
+ return n;
+}
+
void json_write_wrbuf(struct json_node *node, WRBUF result)
{
switch (node->type)
}
}
+static struct json_node **json_get_objectp(struct json_node *n,
+ const char *name)
+{
+ if (n && n->type == json_node_object)
+ {
+ for (n = n->u.link[0]; n; n = n->u.link[1])
+ {
+ struct json_node *c = n->u.link[0];
+ if (c && c->type == json_node_pair &&
+ c->u.link[0] && c->u.link[0]->type == json_node_string)
+ if (!strcmp(name, c->u.link[0]->u.string))
+ return &c->u.link[1];
+ }
+ }
+ return 0;
+}
+
+struct json_node *json_get_object(struct json_node *n, const char *name)
+{
+ struct json_node **np = json_get_objectp(n, name);
+
+ if (np)
+ return *np;
+ return 0;
+}
+
+struct json_node *json_detach_object(struct json_node *n, const char *name)
+{
+ struct json_node **np = json_get_objectp(n, name);
+
+ if (np)
+ {
+ struct json_node *n = *np;
+ *np = 0;
+ return n;
+ }
+ return 0;
+}
+
+struct json_node *json_get_elem(struct json_node *n, int idx)
+{
+ if (n && n->type == json_node_array)
+ {
+ for (n = n->u.link[0]; n; n = n->u.link[1])
+ {
+ if (--idx < 0)
+ return n->u.link[0];
+ }
+ }
+ return 0;
+}
+
+int json_count_children(struct json_node *n)
+{
+ int i = 0;
+
+ if (n && (n->type == json_node_array || n->type == json_node_object))
+ {
+ for (n = n->u.link[0]; n; n = n->u.link[1])
+ i++;
+ }
+ return i;
+}
+
+int json_append_array(struct json_node *dst, struct json_node *src)
+{
+ if (dst && src &&
+ dst->type == json_node_array && src->type == json_node_array)
+ {
+ struct json_node **np = &dst->u.link[0];
+ while (*np)
+ np = &(*np)->u.link[1];
+ *np = src->u.link[0];
+ src->u.link[0] = 0;
+ json_remove_node(src);
+ return 0;
+ }
+ return -1;
+}
+
const char *json_parser_get_errmsg(json_parser_t p)
{
return p->err_msg;
json_parser_destroy(p);
}
+static void tst2(void)
+{
+ struct json_node *n, *n1;
+
+ n = json_parse("{\"a\":1,\"b\":2,\"c\":[true,false,null]}", 0);
+ YAZ_CHECK(n);
+ if (!n)
+ return;
+
+ YAZ_CHECK_EQ(json_count_children(n), 3);
+
+ n1 = json_get_object(n, "a");
+ YAZ_CHECK(n1 && n1->type == json_node_number && n1->u.number == 1.0);
+ YAZ_CHECK_EQ(json_count_children(n1), 0);
+
+ n1 = json_get_object(n, "b");
+ YAZ_CHECK(n1 && n1->type == json_node_number && n1->u.number == 2.0);
+ YAZ_CHECK_EQ(json_count_children(n1), 0);
+
+ n1 = json_get_object(n, "b");
+ YAZ_CHECK(n1 && n1->type == json_node_number && n1->u.number == 2.0);
+ YAZ_CHECK_EQ(json_count_children(n1), 0);
+
+ n1 = json_get_object(n, "c");
+ YAZ_CHECK(n1 && n1->type == json_node_array);
+ YAZ_CHECK_EQ(json_count_children(n1), 3);
+
+ n1 = json_get_elem(json_get_object(n, "c"), 0);
+ YAZ_CHECK(n1 && n1->type == json_node_true);
+
+ n1 = json_get_elem(json_get_object(n, "c"), 1);
+ YAZ_CHECK(n1 && n1->type == json_node_false);
+
+ n1 = json_get_elem(json_get_object(n, "c"), 2);
+ YAZ_CHECK(n1 && n1->type == json_node_null);
+
+ n1 = json_get_elem(json_get_object(n, "c"), 3);
+ YAZ_CHECK(n1 == 0);
+
+ json_remove_node(n);
+}
+
+static int append_check(const char *a, const char *b, const char *exp)
+{
+ WRBUF w = wrbuf_alloc();
+ struct json_node *n_a, *n_b;
+ int ret = 0;
+
+ n_a = json_parse(a, 0);
+ n_b = json_parse(b, 0);
+ json_append_array(json_get_object(n_a, "a"),
+ json_detach_object(n_b, "b"));
+
+ json_write_wrbuf(n_a, w);
+
+ if (!strcmp(wrbuf_cstr(w), exp))
+ ret = 1;
+ wrbuf_destroy(w);
+ json_remove_node(n_a);
+ json_remove_node(n_b);
+ return ret;
+}
+
+static void tst3(void)
+{
+ YAZ_CHECK(append_check("{\"a\":[1,2,3]}", "{\"b\":[5,6,7]}",
+ "{\"a\":[1,2,3,5,6,7]}"));
+
+ YAZ_CHECK(append_check("{\"a\":[]}", "{\"b\":[5,6,7]}",
+ "{\"a\":[5,6,7]}"));
+
+ YAZ_CHECK(append_check("{\"a\":[1,2,3]}", "{\"b\":[]}",
+ "{\"a\":[1,2,3]}"));
+}
+
int main (int argc, char **argv)
{
YAZ_CHECK_INIT(argc, argv);
tst1();
+ tst2();
+ tst3();
YAZ_CHECK_TERM;
}