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 | |
| 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.
| -rw-r--r-- | json-glib/Makefile.am | 2 | ||||
| -rw-r--r-- | json-glib/json-array.c | 64 | ||||
| -rw-r--r-- | json-glib/json-data.c | 93 | ||||
| -rw-r--r-- | json-glib/json-node.c | 269 | ||||
| -rw-r--r-- | json-glib/json-object.c | 44 | ||||
| -rw-r--r-- | json-glib/json-parser.c | 87 | ||||
| -rw-r--r-- | json-glib/json-parser.h | 2 | ||||
| -rw-r--r-- | json-glib/json-private.h | 38 | ||||
| -rw-r--r-- | json-glib/json-types.h | 59 | ||||
| -rw-r--r-- | tests/test-01.c | 2 | ||||
| -rw-r--r-- | tests/test-02.c | 112 |
11 files changed, 535 insertions, 237 deletions
diff --git a/json-glib/Makefile.am b/json-glib/Makefile.am index 8ca1d4e..446520b 100644 --- a/json-glib/Makefile.am +++ b/json-glib/Makefile.am @@ -46,7 +46,7 @@ source_h_private = json-private.h source_c = \ json-array.c \ - json-data.c \ + json-node.c \ json-object.c \ json-parser.c \ $(NULL) diff --git a/json-glib/json-array.c b/json-glib/json-array.c index 6596c90..2f0a249 100644 --- a/json-glib/json-array.c +++ b/json-glib/json-array.c @@ -3,11 +3,17 @@ #include "json-types.h" #include "json-private.h" +/** + * SECTION:json-array + * @short_description: a JSON array representation + * + */ + struct _JsonArray { - GValueArray *elements; + GPtrArray *elements; - volatile guint ref_count; + volatile gint ref_count; }; JsonArray * @@ -18,7 +24,7 @@ json_array_new (void) array = g_slice_new (JsonArray); array->ref_count = 1; - array->elements = g_value_array_new (0); + array->elements = g_ptr_array_new (); return array; } @@ -31,7 +37,7 @@ json_array_sized_new (guint n_elements) array = g_slice_new (JsonArray); array->ref_count = 1; - array->elements = g_value_array_new (n_elements); + array->elements = g_ptr_array_sized_new (n_elements); return array; } @@ -77,7 +83,12 @@ json_array_unref (JsonArray *array) g_atomic_int_compare_and_exchange (&array->ref_count, old_ref, old_ref - 1); else { - g_value_array_free (array->elements); + gint i; + + for (i = 0; i < array->elements->len; i++) + json_node_free (g_ptr_array_index (array->elements, i)); + + g_ptr_array_free (array->elements, TRUE); array->elements = NULL; g_slice_free (JsonArray, array); @@ -88,7 +99,7 @@ json_array_unref (JsonArray *array) * json_array_get_elements: * @array: a #JsonArray * - * Gets the elements of a #JsonArray in list form. + * Gets the elements of a #JsonArray as a list of #JsonNode<!-- -->s. * * Return value: a #GList containing the elements of the array. The * contents of the list are owned by the array and should never be @@ -104,9 +115,9 @@ json_array_get_elements (JsonArray *array) g_return_val_if_fail (array != NULL, NULL); retval = NULL; - for (i = 0; i < array->elements->n_values; i++) + for (i = 0; i < array->elements->len; i++) retval = g_list_prepend (retval, - g_value_array_get_nth (array->elements, i)); + g_ptr_array_index (array->elements, i)); return g_list_reverse (retval); } @@ -118,16 +129,16 @@ json_array_get_elements (JsonArray *array) * * Retrieves the element at @index_ inside a #JsonArray. * - * Return value: a pointer to the value at the requested position + * Return value: a pointer to the #JsonNode at the requested index */ -GValue * +JsonNode * json_array_get_element (JsonArray *array, guint index_) { g_return_val_if_fail (array != NULL, NULL); - g_return_val_if_fail (index_ < array->elements->n_values, NULL); + g_return_val_if_fail (index_ < array->elements->len, NULL); - return g_value_array_get_nth (array->elements, index_); + return g_ptr_array_index (array->elements, index_); } /** @@ -143,34 +154,15 @@ json_array_get_length (JsonArray *array) { g_return_val_if_fail (array != NULL, 0); - return array->elements->n_values; -} - -void -json_array_append_element (JsonArray *array, - const GValue *value) -{ - g_return_if_fail (array != NULL); - - g_value_array_append (array->elements, value); -} - -void -json_array_prepend_element (JsonArray *array, - const GValue *value) -{ - g_return_if_fail (array != NULL); - - g_value_array_prepend (array->elements, value); + return array->elements->len; } void -json_array_insert_element (JsonArray *array, - gint index_, - const GValue *value) +json_array_add_element (JsonArray *array, + JsonNode *node) { g_return_if_fail (array != NULL); - g_return_if_fail (index_ <= array->elements->n_values); + g_return_if_fail (node != NULL); - g_value_array_insert (array->elements, index_, value); + g_ptr_array_add (array->elements, node); } diff --git a/json-glib/json-data.c b/json-glib/json-data.c deleted file mode 100644 index ce6f7ab..0000000 --- a/json-glib/json-data.c +++ /dev/null @@ -1,93 +0,0 @@ -#include "config.h" - -#include <glib.h> - -#include "json-types.h" -#include "json-private.h" - -JsonData * -json_data_new (JsonDataType type) -{ - JsonData *data; - - data = g_slice_new (JsonData); - data->type = type; - - return data; -} - -void -json_data_set_object (JsonData *data, - JsonObject *object) -{ - g_return_if_fail (data != NULL); - g_return_if_fail (JSON_DATA_TYPE (data) == JSON_DATA_OBJECT); - g_return_if_fail (object != NULL); - - data->data.object = object; -} - -/** - * json_data_get_object: - * @data: a #JsonData - * - * Retrieves the #JsonObject stored inside a #JsonData - * - * Return value: the #JsonObject - */ -JsonObject * -json_data_get_object (JsonData *data) -{ - g_return_val_if_fail (data != NULL, NULL); - g_return_val_if_fail (JSON_DATA_TYPE (data) == JSON_DATA_OBJECT, NULL); - - return data->data.object; -} - -void -json_data_set_array (JsonData *data, - JsonArray *array) -{ - g_return_if_fail (data != NULL); - g_return_if_fail (JSON_DATA_TYPE (data) == JSON_DATA_ARRAY); - g_return_if_fail (array != NULL); - - data->data.array = array; -} - -/** - * json_data_get_array: - * @data: a #JsonData - * - * Retrieves the #JsonArray stored inside a #JsonData - * - * Return value: the #JsonArray - */ -JsonArray * -json_data_get_array (JsonData *data) -{ - g_return_val_if_fail (data != NULL, NULL); - g_return_val_if_fail (JSON_DATA_TYPE (data) == JSON_DATA_ARRAY, NULL); - - return data->data.array; -} - -void -json_data_free (JsonData *data) -{ - if (data) - { - switch (data->type) - { - case JSON_DATA_OBJECT: - json_object_unref (data->data.object); - break; - - case JSON_DATA_ARRAY: - json_array_unref (data->data.array); - break; - } - - g_slice_free (JsonData, data); - } -} diff --git a/json-glib/json-node.c b/json-glib/json-node.c new file mode 100644 index 0000000..50d3df0 --- /dev/null +++ b/json-glib/json-node.c @@ -0,0 +1,269 @@ +/** + * SECTION:json-node + * @short_description: Base element in a JSON stream + * + * A #JsonNode is a generic container of elements inside a JSON stream. + * It can contain fundamental types (integers, booleans, floating point + * numbers, strings) and complex types (arrays and objects). + * + * When parsing a JSON data stream you extract the root node and walk + * the node tree by retrieving the type of data contained inside the + * node with the %JSON_NODE_TYPE macro. If the node contains a fundamental + * type you can retrieve a copy of the GValue holding it with the + * json_node_get_value() function, and then use the GValue API to extract + * the data; if the node contains a complex type you can retrieve the + * #JsonObject or the #JsonArray using json_node_get_object() or + * json_node_get_array() respectively, and then retrieve the nodes + * they contain. + */ + +#include "config.h" + +#include <glib.h> + +#include "json-types.h" +#include "json-private.h" + +JsonNode * +json_node_new (JsonNodeType type) +{ + JsonNode *data; + + data = g_slice_new (JsonNode); + data->type = type; + + return data; +} + +JsonNode * +json_node_copy (JsonNode *node) +{ + JsonNode *copy; + + g_return_val_if_fail (node != NULL, NULL); + + copy = g_slice_new (JsonNode); + *copy = *node; + + switch (copy->type) + { + case JSON_NODE_OBJECT: + copy->data.object = json_object_ref (node->data.object); + break; + case JSON_NODE_ARRAY: + copy->data.array = json_array_ref (node->data.array); + break; + case JSON_NODE_VALUE: + g_value_init (&(copy->data.value), G_VALUE_TYPE (&(node->data.value))); + g_value_copy (&(node->data.value), &(copy->data.value)); + break; + case JSON_NODE_NULL: + break; + default: + g_assert_not_reached (); + } + + return copy; +} + +void +json_node_set_object (JsonNode *node, + JsonObject *object) +{ + g_return_if_fail (node != NULL); + g_return_if_fail (JSON_NODE_TYPE (node) == JSON_NODE_OBJECT); + + if (node->data.object) + json_object_unref (node->data.object); + + if (object) + node->data.object = json_object_ref (object); + else + node->data.object = NULL; +} + +void +json_node_take_object (JsonNode *node, + JsonObject *object) +{ + g_return_if_fail (node != NULL); + g_return_if_fail (JSON_NODE_TYPE (node) == JSON_NODE_OBJECT); + + if (node->data.object) + { + json_object_unref (node->data.object); + node->data.object = NULL; + } + + if (object) + node->data.object = object; +} + +/** + * json_node_get_object: + * @data: a #JsonNode + * + * Retrieves the #JsonObject stored inside a #JsonNode + * + * Return value: the #JsonObject + */ +JsonObject * +json_node_get_object (JsonNode *node) +{ + g_return_val_if_fail (node != NULL, NULL); + g_return_val_if_fail (JSON_NODE_TYPE (node) == JSON_NODE_OBJECT, NULL); + + return node->data.object; +} + +JsonObject * +json_node_dup_object (JsonNode *node) +{ + g_return_val_if_fail (node != NULL, NULL); + g_return_val_if_fail (JSON_NODE_TYPE (node) == JSON_NODE_OBJECT, NULL); + + if (node->data.object) + return json_object_ref (node->data.object); + + return NULL; +} + +void +json_node_set_array (JsonNode *node, + JsonArray *array) +{ + g_return_if_fail (node != NULL); + g_return_if_fail (JSON_NODE_TYPE (node) == JSON_NODE_ARRAY); + + if (node->data.array) + json_array_unref (node->data.array); + + if (array) + node->data.array = json_array_ref (array); + else + node->data.array = NULL; +} + +void +json_node_take_array (JsonNode *node, + JsonArray *array) +{ + g_return_if_fail (node != NULL); + g_return_if_fail (JSON_NODE_TYPE (node) == JSON_NODE_ARRAY); + + if (node->data.array) + { + json_array_unref (node->data.array); + node->data.array = NULL; + } + + if (array) + node->data.array = array; +} + +/** + * json_node_get_array: + * @node: a #JsonNode + * + * Retrieves the #JsonArray stored inside a #JsonNode + * + * Return value: the #JsonArray + */ +JsonArray * +json_node_get_array (JsonNode *node) +{ + g_return_val_if_fail (node != NULL, NULL); + g_return_val_if_fail (JSON_NODE_TYPE (node) == JSON_NODE_ARRAY, NULL); + + return node->data.array; +} + +JsonArray * +json_node_dup_array (JsonNode *node) +{ + g_return_val_if_fail (node != NULL, NULL); + g_return_val_if_fail (JSON_NODE_TYPE (node) == JSON_NODE_ARRAY, NULL); + + if (node->data.array) + return json_array_ref (node->data.array); + + return NULL; +} + +void +json_node_get_value (JsonNode *node, + GValue *value) +{ + g_return_if_fail (node != NULL); + g_return_if_fail (JSON_NODE_TYPE (node) == JSON_NODE_VALUE); + + if (G_VALUE_TYPE (&(node->data.value)) != 0) + { + g_value_init (value, G_VALUE_TYPE (&(node->data.value))); + g_value_copy (&(node->data.value), value); + } +} + +void +json_node_set_value (JsonNode *node, + const GValue *value) +{ + g_return_if_fail (node != NULL); + g_return_if_fail (JSON_NODE_TYPE (node) == JSON_NODE_VALUE); + + if (G_VALUE_TYPE (&(node->data.value)) != 0) + g_value_unset (&(node->data.value)); + + g_value_init (&(node->data.value), G_VALUE_TYPE (value)); + g_value_copy (value, &(node->data.value)); +} + +void +json_node_free (JsonNode *node) +{ + if (G_LIKELY (node)) + { + switch (node->type) + { + case JSON_NODE_OBJECT: + json_object_unref (node->data.object); + break; + + case JSON_NODE_ARRAY: + json_array_unref (node->data.array); + break; + + case JSON_NODE_VALUE: + g_value_unset (&(node->data.value)); + break; + + case JSON_NODE_NULL: + break; + } + + g_slice_free (JsonNode, node); + } +} + +G_CONST_RETURN gchar * +json_node_type_name (JsonNode *node) +{ + g_return_val_if_fail (node != NULL, "(null)"); + + switch (node->type) + { + case JSON_NODE_OBJECT: + return "JsonObject"; + + case JSON_NODE_ARRAY: + return "JsonArray"; + + case JSON_NODE_NULL: + return "NULL"; + + case JSON_NODE_VALUE: + return g_type_name (G_VALUE_TYPE (&(node->data.value))); + } + + return "unknown"; +} diff --git a/json-glib/json-object.c b/json-glib/json-object.c index aa4d517..0aa7855 100644 --- a/json-glib/json-object.c +++ b/json-glib/json-object.c @@ -7,7 +7,7 @@ /** * SECTION:json-object - * @short_description: a JSON Object type + * @short_description: a JSON object representation * * #JsonObject is a boxed type representing a JSON object data type. Each * JSON object can have zero or more members, and each member is accessed @@ -19,7 +19,7 @@ struct _JsonObject { GHashTable *members; - volatile guint ref_count; + volatile gint ref_count; }; JsonObject * @@ -32,7 +32,7 @@ json_object_new (void) object->ref_count = 1; object->members = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, - g_free); + (GDestroyNotify) json_node_free); return object; } @@ -57,21 +57,6 @@ json_object_ref (JsonObject *object) return object; } -static void -object_unset_members (gpointer key, - gpointer value, - gpointer user_data) -{ - GValue *gvalue = value; - - /* we copy the contents of the GValues, so we need to unset it - * before actually freeing them along with the hash table - */ - - if (G_VALUE_TYPE (gvalue) != 0) /* we allow unset values */ - g_value_unset (gvalue); -} - /** * json_object_unref: * @object: a #JsonObject @@ -93,7 +78,6 @@ json_object_unref (JsonObject *object) g_atomic_int_compare_and_exchange (&object->ref_count, old_ref, old_ref - 1); else { - g_hash_table_foreach (object->members, object_unset_members, NULL); g_hash_table_destroy (object->members); object->members = NULL; @@ -102,27 +86,23 @@ json_object_unref (JsonObject *object) } void -json_object_add_member (JsonObject *object, - const gchar *member_name, - const GValue *value) +json_object_add_member (JsonObject *object, + const gchar *member_name, + JsonNode *node) { - GValue *copy; - g_return_if_fail (object != NULL); g_return_if_fail (member_name != NULL); - g_return_if_fail (value != NULL); + g_return_if_fail (node != NULL); if (json_object_has_member (object, member_name)) { - g_warning ("JsonObject already has a `%s' member", member_name); + g_warning ("JsonObject already has a `%s' member of type `%s'", + member_name, + json_node_type_name (node)); return; } - copy = g_new (GValue, 1); - g_value_init (copy, G_VALUE_TYPE (value)); - g_value_copy (value, copy); - - g_hash_table_replace (object->members, g_strdup (member_name), copy); + g_hash_table_replace (object->members, g_strdup (member_name), node); } /** @@ -155,7 +135,7 @@ json_object_get_members (JsonObject *object) * Return value: a pointer to the value for the requested object * member, or %NULL */ -GValue * +JsonNode * json_object_get_member (JsonObject *object, const gchar *member_name) { 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; } diff --git a/json-glib/json-parser.h b/json-glib/json-parser.h index 071b881..2b2152b 100644 --- a/json-glib/json-parser.h +++ b/json-glib/json-parser.h @@ -72,7 +72,7 @@ gboolean json_parser_load_from_data (JsonParser *parser, const gchar *data, gsize length, GError **error); -GList * json_parser_get_toplevels (JsonParser *parser); +JsonNode * json_parser_get_root (JsonParser *parser); G_END_DECLS diff --git a/json-glib/json-private.h b/json-glib/json-private.h index 76d27d0..1cfc655 100644 --- a/json-glib/json-private.h +++ b/json-glib/json-private.h @@ -2,31 +2,29 @@ #define __JSON_PRIVATE_H__ #include <glib-object.h> -#include <json-glib/json-types.h> +#include "json-types.h" G_BEGIN_DECLS -JsonData *json_data_new (JsonDataType type); -void json_data_set_object (JsonData *data, - JsonObject *object); -void json_data_set_array (JsonData *data, - JsonArray *array); -void json_data_free (JsonData *data); +JsonNode * json_node_new (JsonNodeType type); +JsonNode * json_node_copy (JsonNode *node); +void json_node_set_object (JsonNode *node, + JsonObject *object); +void json_node_set_array (JsonNode *node, + JsonArray *array); +void json_node_set_value (JsonNode *node, + const GValue *value); +void json_node_free (JsonNode *node); -JsonObject *json_object_new (void); -void json_object_add_member (JsonObject *object, - const gchar *member_name, - const GValue *value); +JsonObject * json_object_new (void); +void json_object_add_member (JsonObject *object, + const gchar *member_name, + JsonNode *node); -JsonArray * json_array_new (void); -JsonArray * json_array_sized_new (guint n_elements); -void json_array_append_element (JsonArray *array, - const GValue *value); -void json_array_prepend_element (JsonArray *array, - const GValue *value); -void json_array_insert_element (JsonArray *array, - gint index_, - const GValue *value); +JsonArray * json_array_new (void); +JsonArray * json_array_sized_new (guint n_elements); +void json_array_add_element (JsonArray *array, + JsonNode *node); G_END_DECLS diff --git a/json-glib/json-types.h b/json-glib/json-types.h index f8e61a2..0cacec3 100644 --- a/json-glib/json-types.h +++ b/json-glib/json-types.h @@ -5,48 +5,57 @@ G_BEGIN_DECLS -#define JSON_DATA_TYPE(data) (((JsonData *) (data))->type) +#define JSON_NODE_TYPE(node) (((JsonNode *) (node))->type) #define JSON_TYPE_OBJECT (json_object_get_type ()) #define JSON_TYPE_ARRAY (json_array_get_type ()) typedef struct _JsonObject JsonObject; typedef struct _JsonArray JsonArray; -typedef struct _JsonData JsonData; +typedef struct _JsonNode JsonNode; typedef enum { - JSON_DATA_OBJECT, - JSON_DATA_ARRAY -} JsonDataType; + JSON_NODE_OBJECT, + JSON_NODE_ARRAY, + JSON_NODE_VALUE, + JSON_NODE_NULL +} JsonNodeType; -struct _JsonData +struct _JsonNode { /*< private >*/ - JsonDataType type; + JsonNodeType type; union { JsonObject *object; JsonArray *array; + GValue value; } data; + + JsonNode *parent; }; -JsonObject * json_data_get_object (JsonData *data); -JsonArray * json_data_get_array (JsonData *data); - -JsonObject * json_object_ref (JsonObject *object); -void json_object_unref (JsonObject *object); -GList * json_object_get_members (JsonObject *object); -GValue * json_object_get_member (JsonObject *object, - const gchar *member_name); -gboolean json_object_has_member (JsonObject *object, - const gchar *member_name); -guint json_object_get_size (JsonObject *object); - -JsonArray * json_array_ref (JsonArray *array); -void json_array_unref (JsonArray *array); -GList * json_array_get_elements (JsonArray *array); -GValue * json_array_get_element (JsonArray *array, - guint index_); -guint json_array_get_length (JsonArray *array); +JsonObject * json_node_get_object (JsonNode *node); +JsonArray * json_node_get_array (JsonNode *node); +void json_node_get_value (JsonNode *node, + GValue *value); +JsonNode * json_node_get_parent (JsonNode *node); +G_CONST_RETURN gchar *json_node_type_name (JsonNode *node); + +JsonObject * json_object_ref (JsonObject *object); +void json_object_unref (JsonObject *object); +GList * json_object_get_members (JsonObject *object); +JsonNode * json_object_get_member (JsonObject *object, + const gchar *member_name); +gboolean json_object_has_member (JsonObject *object, + const gchar *member_name); +guint json_object_get_size (JsonObject *object); + +JsonArray * json_array_ref (JsonArray *array); +void json_array_unref (JsonArray *array); +GList * json_array_get_elements (JsonArray *array); +JsonNode * json_array_get_element (JsonArray *array, + guint index_); +guint json_array_get_length (JsonArray *array); G_END_DECLS diff --git a/tests/test-01.c b/tests/test-01.c index c530aa9..543803e 100644 --- a/tests/test-01.c +++ b/tests/test-01.c @@ -23,7 +23,7 @@ main (int argc, char *argv[]) return EXIT_FAILURE; } - g_assert (NULL == json_parser_get_toplevels (parser)); + g_assert (NULL == json_parser_get_root (parser)); g_object_unref (parser); diff --git a/tests/test-02.c b/tests/test-02.c index cd09cbe..78047bb 100644 --- a/tests/test-02.c +++ b/tests/test-02.c @@ -15,12 +15,106 @@ static const gchar *test_arrays[] = { static guint n_test_arrays = G_N_ELEMENTS (test_arrays); +static void +print_value (gint indent, + JsonNode *node) +{ + gint j; + gchar indent_str[80]; + GValue value = { 0, }; + + for (j = 0; j < indent; j++) + indent_str[j] = ' '; + + indent_str[j] = '\0'; + + json_node_get_value (node, &value); + + switch (G_VALUE_TYPE (&value)) + { + case G_TYPE_INT: + g_print ("%sFound integer: `%d'\n", + indent_str, + g_value_get_int (&value)); + break; + + case G_TYPE_STRING: + g_print ("%sFound string: `%s'\n", + indent_str, + g_value_get_string (&value)); + break; + + case G_TYPE_FLOAT: + g_print ("%sFound float: `%f'\n", + indent_str, + g_value_get_float (&value)); + break; + + case G_TYPE_BOOLEAN: + g_print ("%sFound boolean: `%s'\n", + indent_str, + g_value_get_boolean (&value) ? "true" : "false"); + break; + + default: + g_print ("%sUnknown value\n", indent_str); + break; + } + + g_value_unset (&value); +} + +static void +print_array (gint indent, + JsonArray *array) +{ + gint array_len = json_array_get_length (array); + gint j; + gchar indent_str[80]; + + for (j = 0; j < indent; j++) + indent_str[j] = ' '; + + indent_str[j] = '\0'; + + if (array_len == 0) + { + g_print ("%sFound empty array\n", indent_str); + return; + } + + for (j = 0; j < array_len; j++) + { + JsonNode *node = json_array_get_element (array, j); + + switch (JSON_NODE_TYPE (node)) + { + case JSON_NODE_ARRAY: + g_print ("%sFound array (len:%d)\n", + indent_str, + json_array_get_length (json_node_get_array (node))); + print_array (indent + 1, json_node_get_array (node)); + break; + case JSON_NODE_OBJECT: + g_print ("%sFound object (size:%d)\n", + indent_str, + json_object_get_size (json_node_get_object (node))); + break; + case JSON_NODE_VALUE: + print_value (indent, node); + break; + case JSON_NODE_NULL: + g_print ("%sFound null\n", indent_str); + break; + } + } +} + int main (int argc, char *argv[]) { JsonParser *parser; gint i; - GList *l; g_type_init (); @@ -29,6 +123,8 @@ main (int argc, char *argv[]) for (i = 0; i < n_test_arrays; i++) { GError *error = NULL; + JsonNode *node; + JsonArray *array; if (!json_parser_load_from_data (parser, test_arrays[i], -1, &error)) { @@ -40,11 +136,17 @@ main (int argc, char *argv[]) g_object_unref (parser); return EXIT_FAILURE; } - } - l = json_parser_get_toplevels (parser); - g_assert (l != NULL); - g_assert (g_list_length (l) == n_test_arrays); + node = json_parser_get_root (parser); + g_assert (node != NULL); + g_assert (JSON_NODE_TYPE (node) == JSON_NODE_ARRAY); + + array = json_node_get_array (node); + g_assert (array != NULL); + + g_print ("*** Test %d ***\n", i); + print_array (1, array); + } g_object_unref (parser); |
