[libgdata/tasks-integration: 1/2] Added _gdata_feed_new_from_json definition to gdata-private.h and created function from _gdata_feed_
- From: Philip Withnall <pwithnall src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [libgdata/tasks-integration: 1/2] Added _gdata_feed_new_from_json definition to gdata-private.h and created function from _gdata_feed_
- Date: Tue, 27 Aug 2013 17:43:44 +0000 (UTC)
commit 40b97d1ae06a44c633632ffb9ac11ece1d025532
Author: Peteris Krisjanis <pecisk gmail com>
Date: Mon Jul 8 18:29:17 2013 +0300
Added _gdata_feed_new_from_json definition to gdata-private.h and created function from
_gdata_feed_new_from_xml example. Needs to add soup message header check at GDataService and create actual
GDataParsable method for parsing JSON output.
Initial code of detection of content type from SoupMessage, using SoupMessageHeaders in
__gdata_service_query. Currently _gdata_feed_new_from_json is carbon copy of xml function, as Im about to
write JSON functions for parsing data yet.
Added functions _gdata_parsable_new_from_json and _gdata_parsable_new_from_json_node to parse JSON data
using virtual functions parse_json and post_parse_json.
Added json-glib dependency to configure.ac and Makefile.am.
Annoying random paste bug fixed.
Wide range of changes implementing parse_json/post_parse_json for GDataParsable, GDataFeed, GDataEntry.
Also added helper functions to GDataParser. GDataEntry will be finished in next commit, along with adding
GDataTasks.
Added more changes to GDataEntry parse_json virtual function to check for common values from JSON
entries. Added several parser functions and error issuers to GDataParser. Fixes all over parse_json chain for
GDataFeed->GDataParsable and GDataEntry->GDataParsable.
Several updates.
core: More fixes
Tons of fixes to get stuff compiled without errors and warnings. Doesnt link at introspection stage
though.
Conflicts:
gdata/services/tasks/gdata-tasks-query.c
gdata/services/tasks/gdata-tasks-query.h
gdata/services/tasks/gdata-tasks-service.c
gdata/services/tasks/gdata-tasks-service.h
gdata/services/tasks/gdata-tasks-task.c
gdata/services/tasks/gdata-tasks-task.h
gdata/services/tasks/gdata-tasks-tasklist.c
First wave of fixing all small bugs.
Conflicts:
gdata/services/tasks/gdata-tasks-query.c
gdata/services/tasks/gdata-tasks-query.h
gdata/services/tasks/gdata-tasks-task.c
gdata/services/tasks/gdata-tasks-task.h
Fixing one JSON element check in GDataFeed parse_json, and removed two g_objec_unrefs for JsonReader in
_gdata_parsable_new_from_json_node.
Makefile.am | 4 +-
configure.ac | 3 +-
gdata/gdata-entry.c | 58 ++++++++++++++
gdata/gdata-feed.c | 79 +++++++++++++++++++
gdata/gdata-parsable.c | 93 ++++++++++++++++++++++
gdata/gdata-parsable.h | 5 +
gdata/gdata-parser.c | 200 ++++++++++++++++++++++++++++++++++++++++++++++++
gdata/gdata-parser.h | 10 +++
gdata/gdata-private.h | 8 ++
gdata/gdata-service.c | 21 ++++-
10 files changed, 474 insertions(+), 7 deletions(-)
---
diff --git a/Makefile.am b/Makefile.am
index 67d4686..4ef7da9 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -487,7 +487,7 @@ EXTRA_DIST += m4/introspection.m4
if HAVE_INTROSPECTION
gdata/GData- GDATA_API_VERSION_MAJOR@ GDATA_API_VERSION_MINOR@.gir: gdata/libgdata.la
-gdata_GData_ GDATA_API_VERSION_MAJOR@_ GDATA_API_VERSION_MINOR@_gir_INCLUDES = GObject-2.0 libxml2-2.0
Soup-2.4
+gdata_GData_ GDATA_API_VERSION_MAJOR@_ GDATA_API_VERSION_MINOR@_gir_INCLUDES = GObject-2.0 libxml2-2.0
Soup-2.4 Json-1.0
if ENABLE_GOA
gdata_GData_ GDATA_API_VERSION_MAJOR@_ GDATA_API_VERSION_MINOR@_gir_INCLUDES += Goa-1.0
endif
@@ -521,7 +521,7 @@ gdata/libgdata.vapi: gdata/GData- GDATA_API_VERSION_MAJOR@ GDATA_API_VERSION_MI
VAPIGEN_VAPIS = gdata/libgdata.vapi
-gdata_libgdata_vapi_DEPS = libxml-2.0 libsoup-2.4
+gdata_libgdata_vapi_DEPS = libxml-2.0 libsoup-2.4 json-glib-1.0
gdata_libgdata_vapi_METADATADIRS = $(srcdir)/gdata
gdata_libgdata_vapi_FILES = gdata/GData- GDATA_API_VERSION_MAJOR@ GDATA_API_VERSION_MINOR@.gir
diff --git a/configure.ac b/configure.ac
index f111a0d..cf2054e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -39,6 +39,7 @@ SOUP_REQS=2.37.91
OAUTH_REQS=0.9.4
GTK_REQS=2.91.2
GOA_REQS=3.2
+JSON_GLIB_REQS=0.15
# Before making a release, the GDATA_LT_VERSION string should be modified. The string is of the form c:r:a.
Follow these instructions sequentially:
#
@@ -64,7 +65,7 @@ AC_SUBST(GDATA_API_VERSION)
AC_SUBST(GDATA_API_VERSION_MAJOR)
AC_SUBST(GDATA_API_VERSION_MINOR)
-GDATA_PACKAGES_PUBLIC="gobject-2.0 glib-2.0 >= $GLIB_REQS gio-2.0 >= $GIO_REQS libxml-2.0 libsoup-2.4 >=
$SOUP_REQS"
+GDATA_PACKAGES_PUBLIC="gobject-2.0 glib-2.0 >= $GLIB_REQS gio-2.0 >= $GIO_REQS libxml-2.0 libsoup-2.4 >=
$SOUP_REQS json-glib-1.0 >= $JSON_GLIB_REQS"
GDATA_PACKAGES_PRIVATE="gthread-2.0 oauth >= $OAUTH_REQS"
GDATA_PACKAGES="$GDATA_PACKAGES_PUBLIC $GDATA_PACKAGES_PRIVATE"
AC_SUBST([GDATA_PACKAGES_PUBLIC])
diff --git a/gdata/gdata-entry.c b/gdata/gdata-entry.c
index b46cc8e..8401d6a 100644
--- a/gdata/gdata-entry.c
+++ b/gdata/gdata-entry.c
@@ -33,6 +33,7 @@
#include <glib/gi18n-lib.h>
#include <libxml/parser.h>
#include <string.h>
+#include <json-glib/json-glib.h>
#include "gdata-entry.h"
#include "gdata-types.h"
@@ -55,6 +56,9 @@ static void pre_get_xml (GDataParsable *parsable, GString *xml_string);
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 gboolean post_parse_json (GDataParsable *parsable, gpointer user_data, GError **error);
+static void get_json (GDataParsable *parsable, GString *json_string);
struct _GDataEntryPrivate {
gchar *title;
@@ -112,6 +116,10 @@ gdata_entry_class_init (GDataEntryClass *klass)
parsable_class->get_namespaces = get_namespaces;
parsable_class->element_name = "entry";
+ parsable_class->parse_json = parse_json;
+ parsable_class->post_parse_json = post_parse_json;
+ parsable_class->get_json = get_json;
+
klass->get_entry_uri = get_entry_uri;
/**
@@ -584,6 +592,56 @@ get_entry_uri (const gchar *id)
return g_strdup (id);
}
+static gboolean
+parse_json (GDataParsable *parsable, JsonReader *reader, gpointer user_data, GError **error)
+{
+ 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) {
+ return success;
+ } else if (strcmp (json_reader_get_member_name (reader), "selfLink") == 0) {
+ priv->content = (gchar*) json_reader_get_string_value (reader);
+ priv->content_is_uri = TRUE;
+ return TRUE;
+ }
+
+ return GDATA_PARSABLE_CLASS (gdata_entry_parent_class)->parse_json (parsable, reader, user_data,
error);
+}
+
+static gboolean
+post_parse_json (GDataParsable *parsable, gpointer user_data, GError **error)
+{
+ GDataEntryPrivate *priv = GDATA_ENTRY (parsable)->priv;
+
+ /* Reverse our lists of stuff */
+ priv->categories = g_list_reverse (priv->categories);
+ priv->links = g_list_reverse (priv->links);
+ priv->authors = g_list_reverse (priv->authors);
+
+ return TRUE;
+}
+
+static void
+get_json (GDataParsable *parsable, GString *json_string)
+{
+ GDataEntryPrivate *priv = GDATA_ENTRY (parsable)->priv;
+
+ gdata_parser_string_append_escaped (json_string, "\"title\": \"", priv->title, "\",");
+
+ if (priv->id != NULL)
+ gdata_parser_string_append_escaped (json_string, "\"id\": \"", priv->id, "\",");
+
+ if (priv->updated != -1) {
+ gchar *updated = gdata_parser_int64_to_iso8601 (priv->updated);
+ g_string_append_printf (json_string, "\"updated\": \"%s\",", updated);
+ g_free (updated);
+ }
+}
+
/**
* gdata_entry_new:
* @id: (allow-none): the entry's ID, or %NULL
diff --git a/gdata/gdata-feed.c b/gdata/gdata-feed.c
index 0e51269..536652f 100644
--- a/gdata/gdata-feed.c
+++ b/gdata/gdata-feed.c
@@ -36,6 +36,7 @@
#include <glib/gi18n-lib.h>
#include <libxml/parser.h>
#include <string.h>
+#include <json-glib/json-glib.h>
#include "gdata-feed.h"
#include "gdata-entry.h"
@@ -57,6 +58,9 @@ static void _gdata_feed_add_category (GDataFeed *self, GDataCategory *category);
static void _gdata_feed_add_link (GDataFeed *self, GDataLink *link);
static void _gdata_feed_add_author (GDataFeed *self, GDataAuthor *author);
+static gboolean parse_json (GDataParsable *parsable, JsonReader *reader, gpointer user_data, GError **error);
+static gboolean post_parse_json (GDataParsable *parsable, gpointer user_data, GError **error);
+
struct _GDataFeedPrivate {
GList *entries;
gchar *title;
@@ -112,6 +116,9 @@ gdata_feed_class_init (GDataFeedClass *klass)
parsable_class->get_namespaces = get_namespaces;
parsable_class->element_name = "feed";
+ parsable_class->parse_json = parse_json;
+ parsable_class->post_parse_json = post_parse_json;
+
/**
* GDataFeed:title:
*
@@ -584,6 +591,59 @@ get_namespaces (GDataParsable *parsable, GHashTable *namespaces)
GDATA_PARSABLE_GET_CLASS (i->data)->get_namespaces (GDATA_PARSABLE (i->data), namespaces);
}
+static gboolean
+parse_json (GDataParsable *parsable, JsonReader *reader, gpointer user_data, GError **error)
+{
+ guint i;
+ GDataFeed *self = GDATA_FEED (parsable);
+ ParseData *data = user_data;
+
+ if (!strcmp (json_reader_get_member_name (reader), "items")) {
+ // loop trough elements array
+ for (i = 0; i < json_reader_count_elements (reader); i++) {
+ json_reader_read_element (reader, i);
+
+ GDataEntry *entry;
+ GType entry_type;
+
+ /* Allow @data to be %NULL, and assume we're parsing a vanilla feed, so that we can
test #GDataFeed in tests/general.c.
+ * A little hacky, but not too much so, and valuable for testing. */
+ entry_type = (data != NULL) ? data->entry_type : GDATA_TYPE_ENTRY;
+ // passing reader cursor to object
+ entry = GDATA_ENTRY (_gdata_parsable_new_from_json_node (entry_type, reader, NULL,
error));
+ if (entry == NULL)
+ return FALSE;
+
+ /* Calls the callbacks in the main thread */
+ if (data != NULL)
+ _gdata_feed_call_progress_callback (self, data, entry);
+ _gdata_feed_add_entry (self, entry);
+ g_object_unref (entry);
+
+ json_reader_end_element (reader);
+ }
+ }
+ else {
+ return GDATA_PARSABLE_CLASS (gdata_feed_parent_class)->parse_json (parsable, reader,
user_data, error);
+ }
+
+ return TRUE;
+}
+
+static gboolean
+post_parse_json (GDataParsable *parsable, gpointer user_data, GError **error)
+{
+ GDataFeedPrivate *priv = GDATA_FEED (parsable)->priv;
+
+ /* Reverse our lists of stuff */
+ priv->entries = g_list_reverse (priv->entries);
+ priv->categories = g_list_reverse (priv->categories);
+ priv->links = g_list_reverse (priv->links);
+ priv->authors = g_list_reverse (priv->authors);
+
+ return TRUE;
+}
+
/*
* _gdata_feed_new:
* @title: the feed's title
@@ -632,6 +692,25 @@ _gdata_feed_new_from_xml (GType feed_type, const gchar *xml, gint length, GType
return feed;
}
+GDataFeed *
+_gdata_feed_new_from_json (GType feed_type, const gchar *json, gint length, GType entry_type,
+ GDataQueryProgressCallback progress_callback, gpointer progress_user_data,
gboolean is_async, GError **error)
+{
+ ParseData *data;
+ GDataFeed *feed;
+
+ g_return_val_if_fail (g_type_is_a (feed_type, GDATA_TYPE_FEED), NULL);
+ g_return_val_if_fail (json != NULL, NULL);
+ g_return_val_if_fail (g_type_is_a (entry_type, GDATA_TYPE_ENTRY), NULL);
+ g_return_val_if_fail (error == NULL || *error == NULL, NULL);
+
+ data = _gdata_feed_parse_data_new (entry_type, progress_callback, progress_user_data, is_async);
+ feed = GDATA_FEED (_gdata_parsable_new_from_json (feed_type, json, length, data, error));
+ _gdata_feed_parse_data_free (data);
+
+ return feed;
+}
+
/**
* gdata_feed_get_entries:
* @self: a #GDataFeed
diff --git a/gdata/gdata-parsable.c b/gdata/gdata-parsable.c
index bada35b..72484f3 100644
--- a/gdata/gdata-parsable.c
+++ b/gdata/gdata-parsable.c
@@ -36,6 +36,7 @@
#include <glib/gi18n-lib.h>
#include <string.h>
#include <libxml/parser.h>
+#include <json-glib/json-glib.h>
#include "gdata-parsable.h"
#include "gdata-private.h"
@@ -51,6 +52,7 @@ static void gdata_parsable_get_property (GObject *object, guint property_id, GVa
static void gdata_parsable_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec
*pspec);
static void gdata_parsable_finalize (GObject *object);
static gboolean real_parse_xml (GDataParsable *parsable, xmlDoc *doc, xmlNode *node, gpointer user_data,
GError **error);
+static gboolean real_parse_json (GDataParsable *parsable, JsonReader *reader, gpointer user_data, GError
**error);
struct _GDataParsablePrivate {
GString *extra_xml;
@@ -75,6 +77,7 @@ gdata_parsable_class_init (GDataParsableClass *klass)
gobject_class->set_property = gdata_parsable_set_property;
gobject_class->finalize = gdata_parsable_finalize;
klass->parse_xml = real_parse_xml;
+ klass->parse_json = real_parse_json;
/**
* GDataParsable:constructed-from-xml:
@@ -178,6 +181,21 @@ real_parse_xml (GDataParsable *parsable, xmlDoc *doc, xmlNode *node, gpointer us
return TRUE;
}
+static gboolean
+real_parse_json (GDataParsable *parsable, JsonReader *reader, gpointer user_data, GError **error)
+{
+ const gchar *name;
+
+ /* Unhandled JSON */
+ /* FIXME Have to find a way how to extract any value in string format, now we get just name */
+ name = json_reader_get_member_name (reader);
+
+ g_string_append (parsable->priv->extra_xml, name);
+ g_debug("Unhandled JSON in %s: %s", G_OBJECT_TYPE_NAME (parsable), name);
+
+ return TRUE;
+}
+
/**
* gdata_parsable_new_from_xml:
* @parsable_type: the type of the class represented by the XML
@@ -320,6 +338,81 @@ _gdata_parsable_new_from_xml_node (GType parsable_type, xmlDoc *doc, xmlNode *no
return parsable;
}
+GDataParsable *
+_gdata_parsable_new_from_json (GType parsable_type, const gchar *json, gint length, gpointer user_data,
GError **error)
+{
+ JsonParser *parser;
+ JsonReader *reader;
+ GDataParsable *parsable;
+
+ g_return_val_if_fail (g_type_is_a (parsable_type, GDATA_TYPE_PARSABLE), NULL);
+ g_return_val_if_fail (json != NULL && *json != '\0', NULL);
+ g_return_val_if_fail (length >= -1, NULL);
+ g_return_val_if_fail (error == NULL || *error == NULL, NULL);
+
+ if (length == -1)
+ length = strlen (json);
+
+ parser = json_parser_new ();
+ if (!json_parser_load_from_data (parser, json, length, error))
+ return NULL;
+ /* FIXME do we need explictly check if json has returned error correctly? */
+
+ reader = json_reader_new (json_parser_get_root (parser));
+ parsable = _gdata_parsable_new_from_json_node (parsable_type, reader, user_data, error);
+
+ g_object_unref (reader);
+ g_object_unref (parser);
+
+ return parsable;
+}
+
+GDataParsable *
+_gdata_parsable_new_from_json_node (GType parsable_type, JsonReader *reader, gpointer user_data, GError
**error)
+{
+ GDataParsable *parsable;
+ GDataParsableClass *klass;
+ guint i;
+
+ g_return_val_if_fail (g_type_is_a (parsable_type, GDATA_TYPE_PARSABLE), NULL);
+ g_return_val_if_fail (reader != NULL, NULL);
+ g_return_val_if_fail (error == NULL || *error == NULL, NULL);
+
+ /* indicator property which allows distinguish between locally created and server based objects */
+ /* as it is used for non-xml tasks, and adding another one for json would be dublication */
+ parsable = g_object_new (parsable_type, "constructed-from-xml", TRUE, NULL);
+
+ klass = GDATA_PARSABLE_GET_CLASS (parsable);
+ if (klass->parse_json == NULL) {
+ g_object_unref (parsable);
+ return NULL;
+ }
+
+ g_assert (klass->element_name != NULL);
+
+ /* Parse each child element */
+ for (i = 0; i < json_reader_count_members (reader); i++) {
+ g_return_val_if_fail (json_reader_read_element (reader, i), NULL);
+ if (klass->parse_json (parsable, reader, user_data, error) == FALSE) {
+ g_object_unref (parsable);
+ return NULL;
+ }
+ /* get out of root object */
+ /* FIXME this is much slower than proper read_member usage */
+ /* can be replaced by count_members/list_members */
+ json_reader_end_element (reader);
+ }
+
+ /* Call the post-parse function */
+ if (klass->post_parse_json != NULL &&
+ klass->post_parse_json (parsable, user_data, error) == FALSE) {
+ g_object_unref (parsable);
+ return NULL;
+ }
+
+ return parsable;
+}
+
static void
build_namespaces_cb (gchar *prefix, gchar *href, GString *output)
{
diff --git a/gdata/gdata-parsable.h b/gdata/gdata-parsable.h
index ed0dc72..3c5e516 100644
--- a/gdata/gdata-parsable.h
+++ b/gdata/gdata-parsable.h
@@ -23,6 +23,7 @@
#include <glib.h>
#include <glib-object.h>
#include <libxml/parser.h>
+#include <json-glib/json-glib.h>
G_BEGIN_DECLS
@@ -91,6 +92,10 @@ typedef struct {
void (*get_xml) (GDataParsable *parsable, GString *xml_string);
void (*get_namespaces) (GDataParsable *parsable, GHashTable *namespaces);
+ 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);
+
const gchar *element_name;
const gchar *element_namespace;
} GDataParsableClass;
diff --git a/gdata/gdata-parser.c b/gdata/gdata-parser.c
index 57388bf..fc51907 100644
--- a/gdata/gdata-parser.c
+++ b/gdata/gdata-parser.c
@@ -23,7 +23,10 @@
#include <glib/gi18n-lib.h>
#include <sys/time.h>
#include <time.h>
+#include <string.h>
#include <libxml/parser.h>
+#include <json-glib/json-glib.h>
+
#include "gdata-parser.h"
#include "gdata-service.h"
@@ -259,6 +262,52 @@ gdata_parser_int64_from_iso8601 (const gchar *date, gint64 *_time)
return FALSE;
}
+gboolean
+gdata_parser_error_required_json_content_missing (JsonReader *reader, GError **error)
+{
+ gchar *element_string = (gchar*) json_reader_get_member_name (reader);
+
+ /* Translators: the parameter is the name of an JSON element.
+ *
+ * For example:
+ * A 'title' element was missing required content. */
+ g_set_error (error, GDATA_SERVICE_ERROR, GDATA_SERVICE_ERROR_PROTOCOL_ERROR, _("A \'%s\' element was
missing required content."), element_string);
+ g_free (element_string);
+
+ return FALSE;
+}
+
+gboolean
+gdata_parser_error_duplicate_json_element (JsonReader *reader, GError **error)
+{
+ gchar *element_string = (gchar*) json_reader_get_member_name (reader);
+
+ /* Translators: the parameter is the name of an JSON element.
+ *
+ * For example:
+ * A singleton element (title) was duplicated. */
+ g_set_error (error, GDATA_SERVICE_ERROR, GDATA_SERVICE_ERROR_PROTOCOL_ERROR, _("A singleton element
(%s) was duplicated."), element_string);
+ g_free (element_string);
+
+ return FALSE;
+}
+
+gboolean
+gdata_parser_error_not_iso8601_format_json (JsonReader *reader, const gchar *actual_value, GError **error)
+{
+ gchar *element_string = (gchar*) json_reader_get_member_name (reader);
+ g_set_error (error, GDATA_SERVICE_ERROR, GDATA_SERVICE_ERROR_PROTOCOL_ERROR,
+ /* Translators: the first parameter is the name of an JSON element,
+ * and the second parameter is the erroneous value (which was not in ISO 8601 format).
+ *
+ * For example:
+ * The content of a 'uploaded' element ("2009-05-06 26:30Z") was not in ISO 8601
format. */
+ _("The content of a \'%s\' element (\"%s\") was not in ISO 8601 format."),
element_string, actual_value);
+ g_free (element_string);
+
+ return FALSE;
+}
+
/*
* gdata_parser_boolean_from_property:
* @element: the XML element which owns the property to parse
@@ -673,6 +722,157 @@ gdata_parser_object_from_element (xmlNode *element, const gchar *element_name, G
return TRUE;
}
+/*
+ * gdata_parser_string_from_json_member:
+ * @reader: #JsonReader cursor object to read JSON node from
+ * @member_name: the name of the member to parse
+ * @options: a bitwise combination of parsing options from #GDataParserOptions, or %P_NONE
+ * @output: the return location for the parsed string content
+ * @success: the return location for a value which is %TRUE if the string was parsed successfully, %FALSE if
an error was encountered,
+ * and undefined if @element didn't match @element_name
+ * @error: a #GError, or %NULL
+ *
+ * Gets the string content of @element if its name is @element_name, subject to various checks specified by
@options.
+ *
+ * If @element doesn't match @element_name, %FALSE will be returned, @error will be unset and @success will
be unset.
+ *
+ * If @element matches @element_name but one of the checks specified by @options fails, %TRUE will be
returned, @error will be set to a
+ * %GDATA_SERVICE_ERROR_PROTOCOL_ERROR error and @success will be set to %FALSE.
+ *
+ * If @element matches @element_name and all of the checks specified by @options pass, %TRUE will be
returned, @error will be unset and
+ * @success will be set to %TRUE.
+ *
+ * The reason for returning the success of the parsing in @success is so that calls to
gdata_parser_string_from_element() can be chained
+ * together in a large "or" statement based on their return values, for the purposes of determining whether
any of the calls matched
+ * a given @element. If any of the calls to gdata_parser_string_from_element() return %TRUE, the value of
@success can be examined.
+ *
+ * Return value: %TRUE if @element matched @element_name, %FALSE otherwise
+ *
+ * Since: 0.7.0
+ */
+gboolean
+gdata_parser_string_from_json_member (JsonReader *reader, const gchar *member_name, GDataParserOptions
options,
+ gchar **output, gboolean *success, GError **error)
+{
+ gchar *text;
+
+ /* Check if there's such element */
+ if (strcmp (json_reader_get_member_name (reader), member_name) != 0) {
+ return FALSE;
+ }
+
+ /* Check if the output string has already been set */
+ if (options & P_NO_DUPES && *output != NULL) {
+ *success = gdata_parser_error_duplicate_json_element (reader, error);
+ return TRUE;
+ }
+
+ /* Get the string and check it for NULLness or emptiness */
+ text = (gchar*) json_reader_get_string_value (reader);
+ if ((options & P_REQUIRED && text == NULL) || (options & P_NON_EMPTY && text != NULL && *text ==
'\0')) {
+ g_free (text);
+ *success = gdata_parser_error_required_json_content_missing (reader, error);
+ return TRUE;
+ } else if (options & P_DEFAULT && (text == NULL || *text == '\0')) {
+ text = (gchar*) g_strdup ("");
+ }
+
+ /* Success! */
+ g_free (*output);
+ *output = (gchar*) text;
+ *success = TRUE;
+
+ return TRUE;
+}
+
+/*
+ * gdata_parser_int64_time_from_json_member:
+ * @reader: #JsonReader cursor object to read JSON node from
+ * @element_name: the name of the element to parse
+ * @options: a bitwise combination of parsing options from #GDataParserOptions, or %P_NONE
+ * @output: (out caller-allocates): the return location for the parsed time value
+ * @success: the return location for a value which is %TRUE if the time val was parsed successfully, %FALSE
if an error was encountered,
+ * and undefined if @element didn't match @element_name
+ * @error: a #GError, or %NULL
+ *
+ * Gets the time value of @element if its name is @element_name, subject to various checks specified by
@options. It expects the text content
+ * of @element to be a date or time value in ISO 8601 format. The returned time value will be a UNIX
timestamp (seconds since the epoch).
+ *
+ * If @element doesn't match @element_name, %FALSE will be returned, @error will be unset and @success will
be unset.
+ *
+ * If @element matches @element_name but one of the checks specified by @options fails, %TRUE will be
returned, @error will be set to a
+ * %GDATA_SERVICE_ERROR_PROTOCOL_ERROR error and @success will be set to %FALSE.
+ *
+ * If @element matches @element_name and all of the checks specified by @options pass, %TRUE will be
returned, @error will be unset and
+ * @success will be set to %TRUE.
+ *
+ * The reason for returning the success of the parsing in @success is so that calls to
gdata_parser_int64_time_from_element() can be chained
+ * together in a large "or" statement based on their return values, for the purposes of determining whether
any of the calls matched
+ * a given @element. If any of the calls to gdata_parser_int64_time_from_element() return %TRUE, the value
of @success can be examined.
+ *
+ * Return value: %TRUE if @element matched @element_name, %FALSE otherwise
+ *
+ * Since: 0.7.0
+ */
+gboolean
+gdata_parser_int64_time_from_json_member (JsonReader *reader, const gchar *member_name, GDataParserOptions
options,
+ gint64 *output, gboolean *success, GError **error)
+{
+ gchar *text;
+ GTimeVal time_val;
+
+ /* Check if there's such element */
+ if (strcmp (json_reader_get_member_name (reader), member_name) != 0) {
+ return FALSE;
+ }
+
+ /* Check if the output time val has already been set */
+ if (options & P_NO_DUPES && *output != -1) {
+ *success = gdata_parser_error_duplicate_json_element (reader, error);
+ return TRUE;
+ }
+
+ /* Get the string and check it for NULLness */
+ text = (gchar*) json_reader_get_string_value (reader);
+ if (options & P_REQUIRED && (text == NULL || *text == '\0')) {
+ g_free (text);
+ *success = gdata_parser_error_required_json_content_missing (reader, error);
+ return TRUE;
+ }
+
+ /* Attempt to parse the string as a GTimeVal */
+ if (g_time_val_from_iso8601 ((gchar*) text, &time_val) == FALSE) {
+ *success = gdata_parser_error_not_iso8601_format_json (reader, text, error);
+ g_free (text);
+ return TRUE;
+ }
+
+ *output = time_val.tv_sec;
+
+ /* Success! */
+ g_free (text);
+ *success = TRUE;
+
+ return TRUE;
+}
+
+/* FIXME API description */
+gboolean
+gdata_parser_boolean_from_json_member (JsonReader *reader, const gchar *member_name, GDataParserOptions
options, gboolean *output, gboolean *success, GError **error)
+{
+
+ /* Check if there's such element */
+ if (strcmp (json_reader_get_member_name (reader), member_name) != 0) {
+ return FALSE;
+ }
+
+ /* Get the boolean */
+ /* FIXME check json reader error if it fails to read it*/
+ *output = json_reader_get_boolean_value (reader);
+
+ return TRUE;
+}
+
void
gdata_parser_string_append_escaped (GString *xml_string, const gchar *pre, const gchar *element_content,
const gchar *post)
{
diff --git a/gdata/gdata-parser.h b/gdata/gdata-parser.h
index d37b18f..a94a9b0 100644
--- a/gdata/gdata-parser.h
+++ b/gdata/gdata-parser.h
@@ -35,6 +35,10 @@ gboolean gdata_parser_error_mutexed_properties (xmlNode *element, const gchar *p
gboolean gdata_parser_error_required_element_missing (const gchar *element_name, const gchar
*parent_element_name, GError **error);
gboolean gdata_parser_error_duplicate_element (xmlNode *element, GError **error);
+gboolean gdata_parser_error_duplicate_json_element (JsonReader *reader, GError **error);
+gboolean gdata_parser_error_required_json_content_missing (JsonReader *reader, GError **error);
+gboolean gdata_parser_error_not_iso8601_format_json (JsonReader *reader, const gchar *actual_value, GError
**error);
+
gboolean gdata_parser_int64_from_date (const gchar *date, gint64 *_time);
gchar *gdata_parser_date_from_int64 (gint64 _time) G_GNUC_WARN_UNUSED_RESULT G_GNUC_MALLOC;
gchar *gdata_parser_int64_to_iso8601 (gint64 _time) G_GNUC_WARN_UNUSED_RESULT G_GNUC_MALLOC;
@@ -80,6 +84,12 @@ gboolean gdata_parser_object_from_element_setter (xmlNode *element, const gchar
gboolean *success, GError **error);
gboolean gdata_parser_object_from_element (xmlNode *element, const gchar *element_name, GDataParserOptions
options, GType object_type,
gpointer /* GDataParsable ** */ _output, gboolean *success,
GError **error);
+gboolean gdata_parser_string_from_json_member (JsonReader *reader, const gchar *member_name,
GDataParserOptions options,
+ gchar **output, gboolean *success, GError **error);
+gboolean gdata_parser_int64_time_from_json_member (JsonReader *reader, const gchar *member_name,
GDataParserOptions options,
+ gint64 *output, gboolean *success, GError **error);
+gboolean gdata_parser_boolean_from_json_member (JsonReader *reader, const gchar *member_name,
GDataParserOptions options,
+ gboolean *output, gboolean *success, GError **error);
void gdata_parser_string_append_escaped (GString *xml_string, const gchar *pre, const gchar
*element_content, const gchar *post);
gchar *gdata_parser_utf8_trim_whitespace (const gchar *s) G_GNUC_WARN_UNUSED_RESULT G_GNUC_MALLOC;
diff --git a/gdata/gdata-private.h b/gdata/gdata-private.h
index 73905f4..0ffcd87 100644
--- a/gdata/gdata-private.h
+++ b/gdata/gdata-private.h
@@ -79,6 +79,11 @@ G_GNUC_INTERNAL GDataParsable *_gdata_parsable_new_from_xml (GType parsable_type
GError **error) G_GNUC_WARN_UNUSED_RESULT
G_GNUC_MALLOC;
G_GNUC_INTERNAL GDataParsable *_gdata_parsable_new_from_xml_node (GType parsable_type, xmlDoc *doc, xmlNode
*node, gpointer user_data,
GError **error) G_GNUC_WARN_UNUSED_RESULT
G_GNUC_MALLOC;
+G_GNUC_INTERNAL GDataParsable *_gdata_parsable_new_from_json (GType parsable_type, const gchar *json, gint
length, gpointer user_data,
+ GError **error) G_GNUC_WARN_UNUSED_RESULT
G_GNUC_MALLOC;
+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_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);
@@ -88,6 +93,9 @@ G_GNUC_INTERNAL GDataFeed *_gdata_feed_new (const gchar *title, const gchar *id,
G_GNUC_INTERNAL GDataFeed *_gdata_feed_new_from_xml (GType feed_type, const gchar *xml, gint length, GType
entry_type,
GDataQueryProgressCallback progress_callback, gpointer
progress_user_data, gboolean is_async,
GError **error) G_GNUC_WARN_UNUSED_RESULT G_GNUC_MALLOC;
+G_GNUC_INTERNAL GDataFeed *_gdata_feed_new_from_json (GType feed_type, const gchar *json, gint length, GType
entry_type,
+ GDataQueryProgressCallback progress_callback, gpointer
progress_user_data, gboolean is_async,
+ GError **error) G_GNUC_WARN_UNUSED_RESULT
G_GNUC_MALLOC;
G_GNUC_INTERNAL void _gdata_feed_add_entry (GDataFeed *self, GDataEntry *entry);
G_GNUC_INTERNAL gpointer _gdata_feed_parse_data_new (GType entry_type, GDataQueryProgressCallback
progress_callback, gpointer progress_user_data,
gboolean is_async);
diff --git a/gdata/gdata-service.c b/gdata/gdata-service.c
index 9c20aff..f9b27a4 100644
--- a/gdata/gdata-service.c
+++ b/gdata/gdata-service.c
@@ -914,17 +914,30 @@ __gdata_service_query (GDataService *self, GDataAuthorizationDomain *domain, con
gboolean is_async)
{
GDataServiceClass *klass;
- GDataFeed *feed;
+ GDataFeed *feed = NULL;
SoupMessage *message;
-
+ SoupMessageHeaders *headers;
+ gchar *content_type;
+
message = _gdata_service_query (self, domain, feed_uri, query, cancellable, error);
if (message == NULL)
return NULL;
g_assert (message->response_body->data != NULL);
klass = GDATA_SERVICE_GET_CLASS (self);
- feed = _gdata_feed_new_from_xml (klass->feed_type, message->response_body->data,
message->response_body->length, entry_type,
- progress_callback, progress_user_data, is_async, error);
+
+ headers = message->response_headers;
+ content_type = (gchar*) soup_message_headers_get_content_type (headers, NULL);
+ if (strncmp (content_type, "application/json", 16) == 0) {
+ g_debug("JSON content type detected.\n");
+ feed = _gdata_feed_new_from_json (klass->feed_type, message->response_body->data,
message->response_body->length, entry_type,
+ progress_callback,
progress_user_data, is_async, error);
+ } else if (strncmp (content_type, "application/atom+xml", 20) == 0) {
+ g_debug("XML content type detected.\n");
+ feed = _gdata_feed_new_from_xml (klass->feed_type, message->response_body->data,
message->response_body->length, entry_type,
+ progress_callback,
progress_user_data, is_async, error);
+ }
+
g_object_unref (message);
if (feed == NULL)
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]