strbuf_json_atom() supports JSON objects and arrays

This commit is contained in:
Andrew Bettison 2015-08-31 19:03:40 +09:30
parent edc8aba100
commit 71c7a4f870
3 changed files with 113 additions and 4 deletions

View File

@ -1937,7 +1937,7 @@ static strbuf strbuf_status_body(strbuf sb, struct http_response *hr, const char
strbuf_puts(sb, "\r\n");
strbuf_puts(sb, hr->result_extra[i].label);
strbuf_puts(sb, "=");
strbuf_json_atom_as_text(sb, &hr->result_extra[i].value);
strbuf_json_atom_as_text(sb, &hr->result_extra[i].value, "\r\n");
}
strbuf_puts(sb, "\r\n");
}

View File

@ -777,11 +777,43 @@ strbuf strbuf_json_atom(strbuf sb, const struct json_atom *atom)
return strbuf_json_string(sb, atom->u.string.content);
case JSON_STRING_LENGTH:
return strbuf_json_string_len(sb, atom->u.string.content, atom->u.string.length);
case JSON_OBJECT: {
strbuf_putc(sb, '{');
size_t i;
for (i = 0; i != atom->u.object.itemc; ++i) {
if (i)
strbuf_putc(sb, ',');
strbuf_json_string(sb, atom->u.object.itemv[i].key);
strbuf_putc(sb, ':');
strbuf_json_atom(sb, atom->u.object.itemv[i].value);
}
strbuf_putc(sb, '}');
return sb;
}
case JSON_ARRAY: {
strbuf_putc(sb, '[');
size_t i;
for (i = 0; i != atom->u.array.itemc; ++i) {
if (i)
strbuf_putc(sb, ',');
strbuf_json_atom(sb, atom->u.array.itemv[i]);
}
strbuf_putc(sb, ']');
return sb;
}
}
abort();
}
strbuf strbuf_json_atom_as_text(strbuf sb, const struct json_atom *atom)
static strbuf strbuf_puts_repeat(strbuf sb, const char *text, size_t repeat)
{
size_t i;
for (i = 0; i != repeat; ++i)
strbuf_puts(sb, text);
return sb;
}
static strbuf strbuf_json_atom_as_text_indented(strbuf sb, const struct json_atom *atom, const char *eol, const char *tab, unsigned indent)
{
switch (atom->type) {
case JSON_NULL:
@ -795,10 +827,43 @@ strbuf strbuf_json_atom_as_text(strbuf sb, const struct json_atom *atom)
return strbuf_puts(sb, atom->u.string.content);
case JSON_STRING_LENGTH:
return strbuf_ncat(sb, atom->u.string.content, atom->u.string.length);
case JSON_OBJECT: {
strbuf_puts(sb, "{");
size_t i;
for (i = 0; i != atom->u.object.itemc; ++i) {
strbuf_puts(sb, eol);
strbuf_puts_repeat(sb, tab, indent);
strbuf_puts(sb, atom->u.object.itemv[i].key);
strbuf_puts(sb, ": ");
strbuf_json_atom_as_text_indented(sb, atom->u.object.itemv[i].value, eol, tab, indent + 1);
}
if (i) {
strbuf_puts(sb, eol);
strbuf_puts_repeat(sb, tab, indent);
}
strbuf_puts(sb, "}");
return sb;
}
case JSON_ARRAY: {
strbuf_puts(sb, "[");
size_t i;
for (i = 0; i != atom->u.array.itemc; ++i) {
if (i)
strbuf_puts(sb, ", ");
strbuf_json_atom_as_text_indented(sb, atom->u.array.itemv[i], eol, tab, indent + 1);
}
strbuf_puts(sb, "]");
return sb;
}
}
abort();
}
strbuf strbuf_json_atom_as_text(strbuf sb, const struct json_atom *atom, const char *eol)
{
return strbuf_json_atom_as_text_indented(sb, atom, eol, " ", 0);
}
strbuf strbuf_json_atom_as_html(strbuf sb, const struct json_atom *atom)
{
switch (atom->type) {
@ -813,6 +878,30 @@ strbuf strbuf_json_atom_as_html(strbuf sb, const struct json_atom *atom)
return strbuf_html_escape(sb, atom->u.string.content, strlen(atom->u.string.content));
case JSON_STRING_LENGTH:
return strbuf_html_escape(sb, atom->u.string.content, atom->u.string.length);
case JSON_OBJECT: {
strbuf_puts(sb, "<dl>");
size_t i;
for (i = 0; i != atom->u.object.itemc; ++i) {
strbuf_puts(sb, "\n<dt>");
strbuf_html_escape(sb, atom->u.object.itemv[i].key, strlen(atom->u.object.itemv[i].key));
strbuf_puts(sb, "</dt><dd>");
strbuf_json_atom_as_html(sb, atom->u.object.itemv[i].value);
strbuf_puts(sb, "</dd>");
}
strbuf_puts(sb, "\n</dl>");
return sb;
}
case JSON_ARRAY: {
strbuf_puts(sb, "<ol>");
size_t i;
for (i = 0; i != atom->u.array.itemc; ++i) {
strbuf_puts(sb, "\n<li>");
strbuf_json_atom_as_html(sb, atom->u.array.itemv[i]);
strbuf_puts(sb, "</li>");
}
strbuf_puts(sb, "\n</ol>");
return sb;
}
}
abort();
}

View File

@ -226,8 +226,20 @@ strbuf strbuf_json_boolean(strbuf sb, int boolean);
strbuf strbuf_json_string(strbuf sb, const char *str); // str can be NULL
strbuf strbuf_json_string_len(strbuf sb, const char *str, size_t strlen); // str cannot be NULL
strbuf strbuf_json_hex(strbuf sb, const unsigned char *buf, size_t len);
struct json_key_value {
const char *key;
struct json_atom *value;
};
struct json_atom {
enum json_atomic_type { JSON_NULL, JSON_BOOLEAN, JSON_INTEGER, JSON_STRING_NULTERM, JSON_STRING_LENGTH } type;
enum json_atomic_type {
JSON_NULL,
JSON_BOOLEAN, // u.boolean
JSON_INTEGER, // u.integer
JSON_STRING_NULTERM, // u.string.content (nul terminated)
JSON_STRING_LENGTH, // u.string.content[0 .. u.string.length-1]
JSON_OBJECT, // u.object.itemv[0 .. u.object.itemc].key .value
JSON_ARRAY, // u.array.itemv[0 .. u.object.itemc]
} type;
union {
int boolean;
int64_t integer;
@ -235,11 +247,19 @@ struct json_atom {
const char *content;
size_t length;
} string;
struct {
size_t itemc;
struct json_key_value *itemv;
} object;
struct {
size_t itemc;
struct json_atom **itemv;
} array;
} u;
};
strbuf strbuf_json_atom(strbuf sb, const struct json_atom *);
strbuf strbuf_json_atom_as_html(strbuf sb, const struct json_atom *);
strbuf strbuf_json_atom_as_text(strbuf sb, const struct json_atom *);
strbuf strbuf_json_atom_as_text(strbuf sb, const struct json_atom *, const char *eol);
/* Append a representation of a struct http_range[] array.
* @author Andrew Bettison <andrew@servalproject.com>