diff options
author | Emmanuele Bassi <ebassi@openedhand.com> | 2007-10-01 12:57:46 +0100 |
---|---|---|
committer | Emmanuele Bassi <ebassi@openedhand.com> | 2007-10-01 12:57:46 +0100 |
commit | 88b11be5eec1da769328e93189bc2f3316c9cd0a (patch) | |
tree | 5ed59cecd38b1a51a8bbcf9964948d0e7e1fbc4b /json-glib/json-parser.c | |
parent | c11ebd32f73a1e21d6097bf9eba8e12f7e35497a (diff) | |
download | json-glib-88b11be5eec1da769328e93189bc2f3316c9cd0a.tar.gz |
Add JsonNode, a generic container for JSON types
This huge commit removes JsonData and adds JsonNode, the generic container
for fundamental and complex data types extracted from a JSON stream. The
contents of a JsonNode can be extracted from it in form of a GValue for
fundamental types (integers, floats, strings, booleans) or in form of
JsonObject and JsonArray objects. JsonObject and JsonArray now accept
JsonNodes instead of GValues.
The JsonParser object builds the data model tree when parsing a JSON stream;
the tree can be recursed by getting the root node and walking it using the
GValue API for the fundamental types and the objects/arrays API for complex
types.
The API has been updated and the tests now recurse through the generated
data model tree.
Diffstat (limited to 'json-glib/json-parser.c')
-rw-r--r-- | json-glib/json-parser.c | 87 |
1 files changed, 64 insertions, 23 deletions
diff --git a/json-glib/json-parser.c b/json-glib/json-parser.c index a97554a..4d50137 100644 --- a/json-glib/json-parser.c +++ b/json-glib/json-parser.c @@ -17,9 +17,8 @@ json_parser_error_quark (void) struct _JsonParserPrivate { - GList *top_levels; - - gint depth; + JsonNode *root; + JsonNode *current_node; }; static const GScannerConfig json_scanner_config = @@ -98,6 +97,14 @@ static guint json_parse_object (JsonParser *parser, static void json_parser_dispose (GObject *gobject) { + JsonParserPrivate *priv = JSON_PARSER_GET_PRIVATE (gobject); + + if (priv->root) + { + json_node_free (priv->root); + priv->root = NULL; + } + G_OBJECT_CLASS (json_parser_parent_class)->dispose (gobject); } @@ -136,7 +143,8 @@ json_parser_init (JsonParser *parser) parser->priv = priv = JSON_PARSER_GET_PRIVATE (parser); - priv->top_levels = NULL; + priv->root = NULL; + priv->current_node = NULL; } static guint @@ -161,20 +169,26 @@ json_parse_array (JsonParser *parser, token = g_scanner_get_next_token (scanner); while (token != G_TOKEN_RIGHT_BRACE) { + JsonNode *node = NULL; GValue value = { 0, }; /* nested array */ if (token == G_TOKEN_LEFT_BRACE) { - priv->depth += 1; + JsonNode *old_node = priv->current_node; + + priv->current_node = json_node_new (JSON_NODE_ARRAY); token = json_parse_array (parser, scanner, TRUE); - priv->depth -= 1; + node = priv->current_node; + priv->current_node = old_node; if (token != G_TOKEN_NONE) return token; + json_array_add_element (array, node); + token = g_scanner_get_next_token (scanner); if (token == G_TOKEN_RIGHT_BRACE) break; @@ -191,42 +205,59 @@ json_parse_array (JsonParser *parser, case G_TOKEN_INT: g_value_init (&value, G_TYPE_INT); g_value_set_int (&value, scanner->value.v_int); - json_array_append_element (array, &value); + + node = json_node_new (JSON_NODE_VALUE); + json_node_set_value (node, &value); + + g_value_unset (&value); break; case G_TOKEN_FLOAT: g_value_init (&value, G_TYPE_FLOAT); g_value_set_float (&value, scanner->value.v_float); - json_array_append_element (array, &value); + + node = json_node_new (JSON_NODE_VALUE); + json_node_set_value (node, &value); + + g_value_unset (&value); break; case G_TOKEN_STRING: g_value_init (&value, G_TYPE_STRING); g_value_set_string (&value, scanner->value.v_string); - json_array_append_element (array, &value); + + node = json_node_new (JSON_NODE_VALUE); + json_node_set_value (node, &value); + + g_value_unset (&value); break; case JSON_TOKEN_TRUE: case JSON_TOKEN_FALSE: g_value_init (&value, G_TYPE_BOOLEAN); - g_value_set_boolean (&value, token == JSON_TOKEN_TRUE ? TRUE - : FALSE); - json_array_append_element (array, &value); + g_value_set_boolean (&value, token == JSON_TOKEN_TRUE ? TRUE : FALSE); + + node = json_node_new (JSON_NODE_VALUE); + json_node_set_value (node, &value); + + g_value_unset (&value); break; case JSON_TOKEN_NULL: - /* NULL values are packed as empty GValues */ + node = json_node_new (JSON_NODE_NULL); break; default: return G_TOKEN_RIGHT_BRACE; } + if (node) + json_array_add_element (array, node); + token = g_scanner_get_next_token (scanner); } - if (priv->depth == 0) - priv->top_levels = g_list_prepend (priv->top_levels, array); + json_node_set_array (priv->current_node, array); return G_TOKEN_NONE; } @@ -256,15 +287,18 @@ static guint json_parse_statement (JsonParser *parser, GScanner *scanner) { + JsonParserPrivate *priv = parser->priv; guint token; token = g_scanner_peek_next_token (scanner); switch (token) { case G_TOKEN_LEFT_CURLY: + priv->root = priv->current_node = json_node_new (JSON_NODE_OBJECT); return json_parse_object (parser, scanner); case G_TOKEN_LEFT_BRACE: + priv->root = priv->current_node = json_node_new (JSON_NODE_ARRAY); return json_parse_array (parser, scanner, FALSE); default: @@ -401,6 +435,12 @@ json_parser_load_from_data (JsonParser *parser, if (length < 0) length = strlen (data); + if (parser->priv->root) + { + json_node_free (parser->priv->root); + parser->priv->root = NULL; + } + scanner = json_scanner_new (parser); g_scanner_input_text (scanner, data, strlen (data)); @@ -479,24 +519,25 @@ json_parser_load_from_data (JsonParser *parser, g_scanner_destroy (scanner); + parser->priv->current_node = NULL; + return retval; } /** - * json_parser_get_toplevels: + * json_parser_get_root: * @parser: a #JsonParser * - * Retrieves the top level entities from the parsed JSON stream. + * Retrieves the top level node from the parsed JSON stream. * - * Return value: a list of pointers to the top-level entites. The - * returned list is owned by the #JsonParser and should never be - * modified or freed. + * Return value: the root #JsonNode . The returned node is owned by + * the #JsonParser and should never be modified or freed. */ -GList * -json_parser_get_toplevels (JsonParser *parser) +JsonNode * +json_parser_get_root (JsonParser *parser) { g_return_val_if_fail (JSON_IS_PARSER (parser), NULL); - return parser->priv->top_levels; + return parser->priv->root; } |