[libgdata/tasks-integration] UNFINISHED more work on tidying up JSON parsing/generation
- From: Philip Withnall <pwithnall src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [libgdata/tasks-integration] UNFINISHED more work on tidying up JSON parsing/generation
- Date: Wed, 28 Aug 2013 05:45:45 +0000 (UTC)
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 & 'escaping'\""
+ "\"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]