[libgdata/tasks-integration] UNFINISHED more work on tidying up JSON parsing/generation



commit b0ce5915f6bed78db1c6d906e0153b39e50d3e96
Author: Philip Withnall <philip tecnocode co uk>
Date:   Tue Aug 27 23:44:01 2013 -0600

    UNFINISHED more work on tidying up JSON parsing/generation
    
    Tests almost pass. Just need to fix extra_json.

 docs/reference/gdata-sections.txt |    2 +
 gdata/gdata-entry.c               |   61 +++++++++++++++++++++++++++++--------
 gdata/gdata-parsable.c            |   43 +++++++++++++++++---------
 gdata/gdata-parsable.h            |    4 +-
 gdata/gdata-parser.c              |    6 ++--
 gdata/gdata-private.h             |    2 +-
 gdata/tests/general.c             |   51 +++++++++++++++++++++++++------
 7 files changed, 125 insertions(+), 44 deletions(-)
---
diff --git a/docs/reference/gdata-sections.txt b/docs/reference/gdata-sections.txt
index 103bf9c..c869fb3 100644
--- a/docs/reference/gdata-sections.txt
+++ b/docs/reference/gdata-sections.txt
@@ -724,6 +724,8 @@ GDataParsable
 GDataParsableClass
 gdata_parsable_new_from_xml
 gdata_parsable_get_xml
+gdata_parsable_new_from_json
+gdata_parsable_get_json
 <SUBSECTION Standard>
 gdata_parsable_get_type
 GDATA_IS_PARSABLE
diff --git a/gdata/gdata-entry.c b/gdata/gdata-entry.c
index e9cba79..c1d3ce9 100644
--- a/gdata/gdata-entry.c
+++ b/gdata/gdata-entry.c
@@ -57,7 +57,7 @@ static void get_xml (GDataParsable *parsable, GString *xml_string);
 static void get_namespaces (GDataParsable *parsable, GHashTable *namespaces);
 static gchar *get_entry_uri (const gchar *id) G_GNUC_WARN_UNUSED_RESULT;
 static gboolean parse_json (GDataParsable *parsable, JsonReader *reader, gpointer user_data, GError **error);
-static void get_json (GDataParsable *parsable, GString *json_string);
+static void get_json (GDataParsable *parsable, JsonBuilder *builder);
 
 struct _GDataEntryPrivate {
        gchar *title;
@@ -596,14 +596,22 @@ parse_json (GDataParsable *parsable, JsonReader *reader, gpointer user_data, GEr
        gboolean success;
        GDataEntryPrivate *priv = GDATA_ENTRY (parsable)->priv;
 
-       /* selfLink in JSON is the same as 'content' entry in XML */
-       if (gdata_parser_string_from_json_member (reader, "title", P_DEFAULT, &(priv->title), &success, 
error) == TRUE ||
-           gdata_parser_string_from_json_member (reader, "id", P_DEFAULT, &(priv->id), &success, error) == 
TRUE ||
-           gdata_parser_int64_time_from_json_member (reader, "updated", P_REQUIRED | P_NO_DUPES, 
&(priv->updated), &success, error) == TRUE) {
+       if (gdata_parser_string_from_json_member (reader, "title", P_DEFAULT | P_NO_DUPES, &(priv->title), 
&success, error) == TRUE ||
+           gdata_parser_string_from_json_member (reader, "id", P_NON_EMPTY | P_NO_DUPES, &(priv->id), 
&success, error) == TRUE ||
+           gdata_parser_int64_time_from_json_member (reader, "updated", P_REQUIRED | P_NO_DUPES, 
&(priv->updated), &success, error) == TRUE ||
+           gdata_parser_string_from_json_member (reader, "etag", P_NON_EMPTY | P_NO_DUPES, &(priv->etag), 
&success, error) == TRUE) {
                return success;
-       } else if (strcmp (json_reader_get_member_name (reader), "selfLink") == 0) {
-               priv->content = g_strdup (json_reader_get_string_value (reader));
-               priv->content_is_uri = TRUE;
+       } else if (g_strcmp0 (json_reader_get_member_name (reader), "selfLink") == 0) {
+               GDataLink *_link = gdata_link_new (json_reader_get_string_value (reader), GDATA_LINK_SELF);
+               gdata_entry_add_link (GDATA_ENTRY (parsable), _link);
+               g_object_unref (_link);
+
+               return TRUE;
+       } else if (g_strcmp0 (json_reader_get_member_name (reader), "kind") == 0) {
+               GDataCategory *category = gdata_category_new (json_reader_get_string_value (reader), 
"http://schemas.google.com/g/2005#kind";, NULL);
+               gdata_entry_add_category (GDATA_ENTRY (parsable), category);
+               g_object_unref (category);
+
                return TRUE;
        }
 
@@ -611,22 +619,49 @@ parse_json (GDataParsable *parsable, JsonReader *reader, gpointer user_data, GEr
 }
 
 static void
-get_json (GDataParsable *parsable, GString *json_string)
+get_json (GDataParsable *parsable, JsonBuilder *builder)
 {
        GDataEntryPrivate *priv = GDATA_ENTRY (parsable)->priv;
+       GList *i;
+       GDataLink *_link;
 
-       /* TODO: This is the wrong kind of escaping. */
-       gdata_parser_string_append_escaped (json_string, "\"title\": \"", priv->title, "\"");
+       json_builder_set_member_name (builder, "title");
+       json_builder_add_string_value (builder, priv->title);
 
        if (priv->id != NULL) {
-               gdata_parser_string_append_escaped (json_string, ",\"id\": \"", priv->id, "\"");
+               json_builder_set_member_name (builder, "id");
+               json_builder_add_string_value (builder, priv->id);
        }
 
        if (priv->updated != -1) {
                gchar *updated = gdata_parser_int64_to_iso8601 (priv->updated);
-               g_string_append_printf (json_string, ",\"updated\": \"%s\"", updated);
+               json_builder_set_member_name (builder, "updated");
+               json_builder_add_string_value (builder, updated);
                g_free (updated);
        }
+
+       /* If we have a "kind" category, add that. */
+       for (i = priv->categories; i != NULL; i = i->next) {
+               GDataCategory *category = GDATA_CATEGORY (i->data);
+
+               if (g_strcmp0 (gdata_category_get_scheme (category), "http://schemas.google.com/g/2005#kind";) 
== 0) {
+                       json_builder_set_member_name (builder, "kind");
+                       json_builder_add_string_value (builder, gdata_category_get_term (category));
+               }
+       }
+
+       /* Add the ETag, if available. */
+       if (gdata_entry_get_etag (GDATA_ENTRY (parsable)) != NULL) {
+               json_builder_set_member_name (builder, "etag");
+               json_builder_add_string_value (builder, priv->etag);
+       }
+
+       /* Add the self-link. */
+       _link = gdata_entry_look_up_link (GDATA_ENTRY (parsable), GDATA_LINK_SELF);
+       if (_link != NULL) {
+               json_builder_set_member_name (builder, "selfLink");
+               json_builder_add_string_value (builder, gdata_link_get_uri (_link));
+       }
 }
 
 /**
diff --git a/gdata/gdata-parsable.c b/gdata/gdata-parsable.c
index f829c0b..29b9e69 100644
--- a/gdata/gdata-parsable.c
+++ b/gdata/gdata-parsable.c
@@ -193,7 +193,7 @@ real_parse_json (GDataParsable *parsable, JsonReader *reader, gpointer user_data
        generator = json_generator_new ();
        g_object_get (G_OBJECT (reader), "root", &root, NULL);
        json_generator_set_root (generator, root);
-       g_object_unref (root);
+       json_node_free (root);
 
        json = json_generator_to_data (generator, NULL);
        g_string_append (parsable->priv->extra_xml, json);
@@ -432,8 +432,6 @@ _gdata_parsable_new_from_json_node (GType parsable_type, JsonReader *reader, gpo
                return NULL;
        }
 
-       g_assert (klass->element_name != NULL);
-
        /* Parse each child member. This assumes the outermost node is an object. */
        for (i = 0; i < json_reader_count_members (reader); i++) {
                g_return_val_if_fail (json_reader_read_element (reader, i), NULL);
@@ -589,48 +587,63 @@ _gdata_parsable_get_xml (GDataParsable *self, GString *xml_string, gboolean decl
 gchar *
 gdata_parsable_get_json (GDataParsable *self)
 {
-       GString *json_string;
+       JsonGenerator *generator;
+       JsonBuilder *builder;
+       JsonNode *root;
+       gchar *output;
 
        g_return_val_if_fail (GDATA_IS_PARSABLE (self), NULL);
 
-       json_string = g_string_sized_new (1000);
-       _gdata_parsable_get_json (self, json_string);
+       /* Build the JSON tree. */
+       builder = json_builder_new ();
+       _gdata_parsable_get_json (self, builder);
+       root = json_builder_get_root (builder);
+       g_object_unref (builder);
 
-       return g_string_free (json_string, FALSE);
+       /* Serialise it to a string. */
+       generator = json_generator_new ();
+       json_generator_set_root (generator, root);
+       output = json_generator_to_data (generator, NULL);
+       g_object_unref (generator);
+
+       json_node_free (root);
+
+       return output;
 }
 
 /*
  * _gdata_parsable_get_json:
  * @self: a #GDataParsable
- * @json_string: a #GString to build the JSON in
+ * @builder: a #JsonBuilder to build the JSON in
  *
  * Builds a JSON representation of the #GDataParsable in its current state, such that it could be inserted 
on the server.
  *
- * Return value: the object's JSON; free with g_free()
- *
  * Since: UNRELEASED
  */
 void
-_gdata_parsable_get_json (GDataParsable *self, GString *json_string)
+_gdata_parsable_get_json (GDataParsable *self, JsonBuilder *builder)
 {
        GDataParsableClass *klass;
 
        g_return_if_fail (GDATA_IS_PARSABLE (self));
-       g_return_if_fail (json_string != NULL);
+       g_return_if_fail (JSON_IS_BUILDER (builder));
 
        klass = GDATA_PARSABLE_GET_CLASS (self);
 
-       g_string_append (json_string, "{");
+       json_builder_begin_object (builder);
 
        /* Add the JSON. */
        if (klass->get_json != NULL)
-               klass->get_json (self, json_string);
+               klass->get_json (self, builder);
 
+#if 0
+TODO
        /* Any extra JSON? Note: The use of extra_xml is intended; the variable is re-used and hence is 
mis-named. */
        if (self->priv->extra_xml != NULL && self->priv->extra_xml->str != NULL)
                g_string_append (json_string, self->priv->extra_xml->str);
+#endif
 
-       g_string_append (json_string, "}");
+       json_builder_end_object (builder);
 }
 
 /*
diff --git a/gdata/gdata-parsable.h b/gdata/gdata-parsable.h
index 8ac5b0f..2f13c25 100644
--- a/gdata/gdata-parsable.h
+++ b/gdata/gdata-parsable.h
@@ -76,7 +76,7 @@ typedef struct {
  * @get_namespaces: a function to return a string containing the namespace declarations used by the 
@parsable when represented in XML form
  * @parse_json: a function to parse a JSON representation of the #GDataParsable to set the properties of the 
@parsable
  * @post_parse_json: a function called after parsing a JSON object, to allow the @parsable to validate the 
parsed properties
- * @get_json: a function to build a JSON representation of the #GDataParsable in its current state, 
appending it to the provided #GString
+ * @get_json: a function to build a JSON representation of the #GDataParsable in its current state, 
appending it to the provided #JsonBuilder
  * @element_name: the name of the XML element which represents this parsable
  * @element_namespace: the prefix of the XML namespace used for the parsable
  *
@@ -98,7 +98,7 @@ typedef struct {
 
        gboolean (*parse_json) (GDataParsable *parsable, JsonReader *reader, gpointer user_data, GError 
**error);
        gboolean (*post_parse_json) (GDataParsable *parsable, gpointer user_data, GError **error);
-       void (*get_json) (GDataParsable *parsable, GString *json_string);
+       void (*get_json) (GDataParsable *parsable, JsonBuilder *builder);
 
        const gchar *element_name;
        const gchar *element_namespace;
diff --git a/gdata/gdata-parser.c b/gdata/gdata-parser.c
index 5520b1a..0222293 100644
--- a/gdata/gdata-parser.c
+++ b/gdata/gdata-parser.c
@@ -765,7 +765,7 @@ gdata_parser_string_from_json_member (JsonReader *reader, const gchar *member_na
        const GError *child_error = NULL;
 
        /* Check if there's such element */
-       if (strcmp (json_reader_get_member_name (reader), member_name) != 0) {
+       if (g_strcmp0 (json_reader_get_member_name (reader), member_name) != 0) {
                return FALSE;
        }
 
@@ -834,7 +834,7 @@ gdata_parser_int64_time_from_json_member (JsonReader *reader, const gchar *membe
        const GError *child_error = NULL;
 
        /* Check if there's such element */
-       if (strcmp (json_reader_get_member_name (reader), member_name) != 0) {
+       if (g_strcmp0 (json_reader_get_member_name (reader), member_name) != 0) {
                return FALSE;
        }
 
@@ -903,7 +903,7 @@ gdata_parser_boolean_from_json_member (JsonReader *reader, const gchar *member_n
        const GError *child_error = NULL;
 
        /* Check if there's such an element. */
-       if (strcmp (json_reader_get_member_name (reader), member_name) != 0) {
+       if (g_strcmp0 (json_reader_get_member_name (reader), member_name) != 0) {
                return FALSE;
        }
 
diff --git a/gdata/gdata-private.h b/gdata/gdata-private.h
index 62ae7d0..dd76ad5 100644
--- a/gdata/gdata-private.h
+++ b/gdata/gdata-private.h
@@ -84,7 +84,7 @@ G_GNUC_INTERNAL GDataParsable *_gdata_parsable_new_from_json (GType parsable_typ
 G_GNUC_INTERNAL GDataParsable *_gdata_parsable_new_from_json_node (GType parsable_type, JsonReader *reader, 
gpointer user_data,
                                                                    GError **error) G_GNUC_WARN_UNUSED_RESULT 
G_GNUC_MALLOC;
 G_GNUC_INTERNAL void _gdata_parsable_get_xml (GDataParsable *self, GString *xml_string, gboolean 
declare_namespaces);
-G_GNUC_INTERNAL void _gdata_parsable_get_json (GDataParsable *self, GString *json_string);
+G_GNUC_INTERNAL void _gdata_parsable_get_json (GDataParsable *self, JsonBuilder *builder);
 G_GNUC_INTERNAL void _gdata_parsable_string_append_escaped (GString *xml_string, const gchar *pre, const 
gchar *element_content, const gchar *post);
 G_GNUC_INTERNAL gboolean _gdata_parsable_is_constructed_from_xml (GDataParsable *self);
 
diff --git a/gdata/tests/general.c b/gdata/tests/general.c
index 7268771..e303161 100644
--- a/gdata/tests/general.c
+++ b/gdata/tests/general.c
@@ -458,28 +458,23 @@ test_entry_get_xml (void)
 static void
 test_entry_get_json (void)
 {
-       gint64 updated, published, updated2, published2, updated3, published3;
+       gint64 updated, published, updated2, published2;
        GDataEntry *entry, *entry2;
-       GDataCategory *category;
-       GDataLink *_link; /* stupid unistd.h */
-       GDataAuthor *author;
-       gchar *json, *title, *summary, *id, *etag, *content, *content_uri, *rights;
-       gboolean is_inserted;
-       GList *list;
+       gchar *json;
        GError *error = NULL;
 
        entry = gdata_entry_new (NULL);
 
        /* Set the properties more conventionally */
-       gdata_entry_set_title (entry, "Testing title & 'escaping'");
+       gdata_entry_set_title (entry, "Testing title & \"escaping\"");
        gdata_entry_set_summary (entry, NULL);
-       gdata_entry_set_content (entry, "This is some sample content testing, amongst other things, <markup> 
& odd characters‽");
+       gdata_entry_set_content (entry, NULL);
        gdata_entry_set_rights (entry, NULL);
 
        /* Check the generated JSON's OK */
        gdata_test_assert_json (entry,
                "{"
-                       "\"title\": \"Testing title & &apos;escaping&apos;\""
+                       "\"title\":\"Testing title & \\\"escaping\\\"\""
                "}");
 
        /* Check again by re-parsing the JSON to a GDataEntry. */
@@ -544,6 +539,41 @@ test_entry_parse_xml (void)
 }
 
 static void
+test_entry_parse_json (void)
+{
+       GDataEntry *entry;
+       GError *error = NULL;
+
+       /* Create an entry from JSON with unhandled nodes. */
+       entry = GDATA_ENTRY (gdata_parsable_new_from_json (GDATA_TYPE_ENTRY,
+               "{"
+                       "\"title\":\"A title\","
+                       "\"updated\":\"2009-01-25T14:07:37Z\","
+                       "\"selfLink\":\"http://example.com/\",";
+                       "\"etag\":\"some-etag\","
+                       "\"id\":\"some-id\","
+                       "\"kind\":\"kind#kind\","
+                       "\"unhandled-member\":false"
+                "}", -1, &error));
+       g_assert_no_error (error);
+       g_assert (GDATA_IS_ENTRY (entry));
+       g_clear_error (&error);
+
+       /* Now check the outputted JSON from the entry still has the unhandled nodes. */
+       gdata_test_assert_json (entry,
+               "{"
+                       "\"title\":\"A title\","
+                       "\"id\":\"some-id\","
+                       "\"updated\":\"2009-01-25T14:07:37Z\","
+                       "\"etag\":\"some-etag\","
+                       "\"selfLink\":\"http://example.com/\",";
+                       "\"kind\":\"kind#kind\","
+                       "\"unhandled-member\":false"
+                "}");
+       g_object_unref (entry);
+}
+
+static void
 test_entry_error_handling (void)
 {
        GDataEntry *entry;
@@ -4048,6 +4078,7 @@ main (int argc, char *argv[])
        g_test_add_func ("/entry/get_xml", test_entry_get_xml);
        g_test_add_func ("/entry/get_json", test_entry_get_json);
        g_test_add_func ("/entry/parse_xml", test_entry_parse_xml);
+       g_test_add_func ("/entry/parse_json", test_entry_parse_json);
        g_test_add_func ("/entry/error_handling", test_entry_error_handling);
        g_test_add_func ("/entry/escaping", test_entry_escaping);
        g_test_add_func ("/entry/links/remove", test_entry_links_remove);


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]