[libgdata] [core] Move all element object parsing into two functions
- From: Philip Withnall <pwithnall src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [libgdata] [core] Move all element object parsing into two functions
- Date: Thu, 25 Mar 2010 00:35:54 +0000 (UTC)
commit c18152c862c7311c21293a6840ef8e20a77daa6a
Author: Philip Withnall <philip tecnocode co uk>
Date: Tue Mar 23 16:40:53 2010 +0000
[core] Move all element object parsing into two functions
docs/reference/gdata-sections.txt | 1 +
gdata/gd/gdata-gd-organization.c | 23 +---
gdata/gd/gdata-gd-when.c | 40 ++++--
gdata/gd/gdata-gd-when.h | 2 +
gdata/gdata-entry.c | 29 +---
gdata/gdata-feed.c | 66 ++++-----
gdata/gdata-parser.c | 161 ++++++++++++++++++++--
gdata/gdata-parser.h | 22 ++-
gdata/gdata.symbols | 1 +
gdata/media/gdata-media-group.c | 53 ++-----
gdata/media/gdata-media-group.h | 2 +
gdata/services/calendar/gdata-calendar-event.c | 29 +---
gdata/services/contacts/gdata-contacts-contact.c | 61 ++-------
gdata/services/documents/gdata-documents-entry.c | 17 +--
gdata/services/picasaweb/gdata-picasaweb-album.c | 34 ++----
gdata/services/picasaweb/gdata-picasaweb-file.c | 52 ++-----
gdata/services/youtube/gdata-youtube-control.c | 16 +--
gdata/services/youtube/gdata-youtube-group.c | 11 +-
gdata/services/youtube/gdata-youtube-video.c | 31 +----
gdata/tests/general.c | 7 +
20 files changed, 329 insertions(+), 329 deletions(-)
---
diff --git a/docs/reference/gdata-sections.txt b/docs/reference/gdata-sections.txt
index 2c9810e..a627a7a 100644
--- a/docs/reference/gdata-sections.txt
+++ b/docs/reference/gdata-sections.txt
@@ -804,6 +804,7 @@ gdata_gd_when_set_is_date
gdata_gd_when_get_value_string
gdata_gd_when_set_value_string
gdata_gd_when_get_reminders
+gdata_gd_when_add_reminder
<SUBSECTION Standard>
gdata_gd_when_get_type
GDATA_GD_WHEN
diff --git a/gdata/gd/gdata-gd-organization.c b/gdata/gd/gdata-gd-organization.c
index ebb024f..8fa64e3 100644
--- a/gdata/gd/gdata-gd-organization.c
+++ b/gdata/gd/gdata-gd-organization.c
@@ -391,26 +391,13 @@ parse_xml (GDataParsable *parsable, xmlDoc *doc, xmlNode *node, gpointer user_da
gdata_parser_string_from_element (node, "orgTitle", P_NO_DUPES, &(priv->title), &success, error) == TRUE ||
gdata_parser_string_from_element (node, "orgDepartment", P_NO_DUPES, &(priv->department), &success, error) == TRUE ||
gdata_parser_string_from_element (node, "orgJobDescription", P_NO_DUPES, &(priv->job_description), &success, error) == TRUE ||
- gdata_parser_string_from_element (node, "orgSymbol", P_NO_DUPES, &(priv->symbol), &success, error) == TRUE) {
+ gdata_parser_string_from_element (node, "orgSymbol", P_NO_DUPES, &(priv->symbol), &success, error) == TRUE ||
+ gdata_parser_object_from_element (node, "where", P_REQUIRED | P_NO_DUPES, GDATA_TYPE_GD_WHERE,
+ &(priv->location), &success, error) == TRUE) {
return success;
- } else if (xmlStrcmp (node->name, (xmlChar*) "where") == 0) {
- /* gd:where */
- GDataGDWhere *location = GDATA_GD_WHERE (_gdata_parsable_new_from_xml_node (GDATA_TYPE_GD_WHERE, doc, node, NULL, error));
- if (location == NULL)
- return FALSE;
-
- if (priv->location != NULL) {
- g_object_unref (location);
- return gdata_parser_error_duplicate_element (node, error);
- }
-
- priv->location = location;
- } else if (GDATA_PARSABLE_CLASS (gdata_gd_organization_parent_class)->parse_xml (parsable, doc, node, user_data, error) == FALSE) {
- /* Error! */
- return FALSE;
+ } else {
+ return GDATA_PARSABLE_CLASS (gdata_gd_organization_parent_class)->parse_xml (parsable, doc, node, user_data, error);
}
-
- return TRUE;
}
static void
diff --git a/gdata/gd/gdata-gd-when.c b/gdata/gd/gdata-gd-when.c
index ac19cb7..1ca161b 100644
--- a/gdata/gd/gdata-gd-when.c
+++ b/gdata/gd/gdata-gd-when.c
@@ -291,21 +291,14 @@ pre_parse_xml (GDataParsable *parsable, xmlDoc *doc, xmlNode *root_node, gpointe
static gboolean
parse_xml (GDataParsable *parsable, xmlDoc *doc, xmlNode *node, gpointer user_data, GError **error)
{
- GDataGDWhenPrivate *priv = GDATA_GD_WHEN (parsable)->priv;
-
- if (xmlStrcmp (node->name, (xmlChar*) "reminder") == 0) {
- /* gd:reminder */
- GDataGDReminder *reminder = GDATA_GD_REMINDER (_gdata_parsable_new_from_xml_node (GDATA_TYPE_GD_REMINDER, doc, node, NULL, error));
- if (reminder == NULL)
- return FALSE;
+ gboolean success;
- priv->reminders = g_list_prepend (priv->reminders, reminder);
- } else if (GDATA_PARSABLE_CLASS (gdata_gd_when_parent_class)->parse_xml (parsable, doc, node, user_data, error) == FALSE) {
- /* Error! */
- return FALSE;
+ if (gdata_parser_object_from_element_setter (node, "reminder", P_REQUIRED, GDATA_TYPE_GD_REMINDER,
+ gdata_gd_when_add_reminder, parsable, &success, error) == TRUE) {
+ return success;
+ } else {
+ return GDATA_PARSABLE_CLASS (gdata_gd_when_parent_class)->parse_xml (parsable, doc, node, user_data, error);
}
-
- return TRUE;
}
static gboolean
@@ -592,3 +585,24 @@ gdata_gd_when_get_reminders (GDataGDWhen *self)
g_return_val_if_fail (GDATA_IS_GD_WHEN (self), NULL);
return self->priv->reminders;
}
+
+/**
+ * gdata_gd_when_add_reminder:
+ * @self: a #GDataGDWhen
+ * @reminder: a #GDataGDReminder to add
+ *
+ * Adds a reminder to the #GDataGDWhen's list of reminders and increments its reference count.
+ *
+ * Duplicate reminders will not be added to the list.
+ *
+ * Since: 0.7.0
+ **/
+void
+gdata_gd_when_add_reminder (GDataGDWhen *self, GDataGDReminder *reminder)
+{
+ g_return_if_fail (GDATA_IS_GD_WHEN (self));
+ g_return_if_fail (GDATA_IS_GD_REMINDER (reminder));
+
+ if (g_list_find_custom (self->priv->reminders, reminder, (GCompareFunc) gdata_gd_reminder_compare) == NULL)
+ self->priv->reminders = g_list_append (self->priv->reminders, g_object_ref (reminder));
+}
diff --git a/gdata/gd/gdata-gd-when.h b/gdata/gd/gdata-gd-when.h
index cf6f143..2f2e1f4 100644
--- a/gdata/gd/gdata-gd-when.h
+++ b/gdata/gd/gdata-gd-when.h
@@ -24,6 +24,7 @@
#include <glib-object.h>
#include <gdata/gdata-parsable.h>
+#include <gdata/gd/gdata-gd-reminder.h>
G_BEGIN_DECLS
@@ -78,6 +79,7 @@ const gchar *gdata_gd_when_get_value_string (GDataGDWhen *self);
void gdata_gd_when_set_value_string (GDataGDWhen *self, const gchar *value_string);
GList *gdata_gd_when_get_reminders (GDataGDWhen *self);
+void gdata_gd_when_add_reminder (GDataGDWhen *self, GDataGDReminder *reminder);
/* TODO: More reminder API */
G_END_DECLS
diff --git a/gdata/gdata-entry.c b/gdata/gdata-entry.c
index 4f0e4f1..98ec252 100644
--- a/gdata/gdata-entry.c
+++ b/gdata/gdata-entry.c
@@ -372,6 +372,7 @@ pre_parse_xml (GDataParsable *parsable, xmlDoc *doc, xmlNode *root_node, gpointe
static gboolean
parse_xml (GDataParsable *parsable, xmlDoc *doc, xmlNode *node, gpointer user_data, GError **error)
{
+ gboolean success;
GDataEntry *self;
g_return_val_if_fail (GDATA_IS_ENTRY (parsable), FALSE);
@@ -414,33 +415,19 @@ parse_xml (GDataParsable *parsable, xmlDoc *doc, xmlNode *node, gpointer user_da
return FALSE;
}
xmlFree (published);
- } else if (xmlStrcmp (node->name, (xmlChar*) "category") == 0) {
- /* atom:category */
- GDataCategory *category = GDATA_CATEGORY (_gdata_parsable_new_from_xml_node (GDATA_TYPE_CATEGORY, doc, node, NULL, error));
- if (category == NULL)
- return FALSE;
-
- self->priv->categories = g_list_prepend (self->priv->categories, category);
+ } else if (gdata_parser_object_from_element_setter (node, "category", P_REQUIRED, GDATA_TYPE_CATEGORY,
+ gdata_entry_add_category, self, &success, error) == TRUE ||
+ gdata_parser_object_from_element_setter (node, "link", P_REQUIRED, GDATA_TYPE_LINK,
+ gdata_entry_add_link, self, &success, error) == TRUE ||
+ gdata_parser_object_from_element_setter (node, "author", P_REQUIRED, GDATA_TYPE_AUTHOR,
+ gdata_entry_add_author, self, &success, error) == TRUE) {
+ return success;
} else if (xmlStrcmp (node->name, (xmlChar*) "content") == 0) {
/* atom:content */
xmlChar *content = xmlNodeListGetString (doc, node->children, TRUE);
if (content == NULL)
content = xmlGetProp (node, (xmlChar*) "src");
self->priv->content = (gchar*) content;
- } else if (xmlStrcmp (node->name, (xmlChar*) "link") == 0) {
- /* atom:link */
- GDataLink *link = GDATA_LINK (_gdata_parsable_new_from_xml_node (GDATA_TYPE_LINK, doc, node, NULL, error));
- if (link == NULL)
- return FALSE;
-
- self->priv->links = g_list_prepend (self->priv->links, link);
- } else if (xmlStrcmp (node->name, (xmlChar*) "author") == 0) {
- /* atom:author */
- GDataAuthor *author = GDATA_AUTHOR (_gdata_parsable_new_from_xml_node (GDATA_TYPE_AUTHOR, doc, node, NULL, error));
- if (author == NULL)
- return FALSE;
-
- self->priv->authors = g_list_prepend (self->priv->authors, author);
} else if (xmlStrcmp (node->name, (xmlChar*) "summary") == 0) {
/* atom:summary */
self->priv->summary = (gchar*) xmlNodeListGetString (doc, node->children, TRUE);
diff --git a/gdata/gdata-feed.c b/gdata/gdata-feed.c
index a071cee..e0740c1 100644
--- a/gdata/gdata-feed.c
+++ b/gdata/gdata-feed.c
@@ -51,6 +51,10 @@ static gboolean pre_parse_xml (GDataParsable *parsable, xmlDoc *doc, xmlNode *ro
static gboolean parse_xml (GDataParsable *parsable, xmlDoc *doc, xmlNode *node, gpointer user_data, GError **error);
static gboolean post_parse_xml (GDataParsable *parsable, gpointer user_data, GError **error);
+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);
+
struct _GDataFeedPrivate {
GList *entries;
gchar *title;
@@ -428,7 +432,15 @@ parse_xml (GDataParsable *parsable, xmlDoc *doc, xmlNode *node, gpointer user_da
gdata_parser_string_from_element (node, "subtitle", P_NO_DUPES, &(self->priv->subtitle), &success, error) == TRUE ||
gdata_parser_string_from_element (node, "id", P_NO_DUPES, &(self->priv->id), &success, error) == TRUE ||
gdata_parser_string_from_element (node, "logo", P_NO_DUPES, &(self->priv->logo), &success, error) == TRUE ||
- gdata_parser_string_from_element (node, "icon", P_NO_DUPES, &(self->priv->icon), &success, error) == TRUE) {
+ gdata_parser_string_from_element (node, "icon", P_NO_DUPES, &(self->priv->icon), &success, error) == TRUE ||
+ gdata_parser_object_from_element_setter (node, "category", P_REQUIRED, GDATA_TYPE_CATEGORY,
+ _gdata_feed_add_category, self, &success, error) == TRUE ||
+ gdata_parser_object_from_element_setter (node, "link", P_REQUIRED, GDATA_TYPE_LINK,
+ _gdata_feed_add_link, self, &success, error) == TRUE ||
+ gdata_parser_object_from_element_setter (node, "author", P_REQUIRED, GDATA_TYPE_AUTHOR,
+ _gdata_feed_add_author, self, &success, error) == TRUE ||
+ gdata_parser_object_from_element (node, "generator", P_REQUIRED | P_NO_DUPES, GDATA_TYPE_GENERATOR,
+ &(self->priv->generator), &success, error) == TRUE) {
return success;
/*TODO for atom:id: xmlStrcmp (node->ns->href, (xmlChar*) "http://www.w3.org/2005/Atom") == 0) {*/
} else if (xmlStrcmp (node->name, (xmlChar*) "updated") == 0) {
@@ -447,40 +459,6 @@ parse_xml (GDataParsable *parsable, xmlDoc *doc, xmlNode *node, gpointer user_da
return FALSE;
}
xmlFree (updated_string);
- } else if (xmlStrcmp (node->name, (xmlChar*) "category") == 0) {
- /* atom:category */
- GDataCategory *category = GDATA_CATEGORY (_gdata_parsable_new_from_xml_node (GDATA_TYPE_CATEGORY, doc, node, NULL, error));
- if (category == NULL)
- return FALSE;
-
- self->priv->categories = g_list_prepend (self->priv->categories, category);
- } else if (xmlStrcmp (node->name, (xmlChar*) "link") == 0) {
- /* atom:link */
- GDataLink *link = GDATA_LINK (_gdata_parsable_new_from_xml_node (GDATA_TYPE_LINK, doc, node, NULL, error));
- if (link == NULL)
- return FALSE;
-
- self->priv->links = g_list_prepend (self->priv->links, link);
- } else if (xmlStrcmp (node->name, (xmlChar*) "author") == 0) {
- /* atom:author */
- GDataAuthor *author = GDATA_AUTHOR (_gdata_parsable_new_from_xml_node (GDATA_TYPE_AUTHOR, doc, node, NULL, error));
- if (author == NULL)
- return FALSE;
-
- self->priv->authors = g_list_prepend (self->priv->authors, author);
- } else if (xmlStrcmp (node->name, (xmlChar*) "generator") == 0) {
- /* atom:generator */
- GDataGenerator *generator;
-
- /* Duplicate checking */
- if (self->priv->generator != NULL)
- return gdata_parser_error_duplicate_element (node, error);
-
- generator = GDATA_GENERATOR (_gdata_parsable_new_from_xml_node (GDATA_TYPE_GENERATOR, doc, node, NULL, error));
- if (generator == NULL)
- return FALSE;
-
- self->priv->generator = generator;
} else if (xmlStrcmp (node->name, (xmlChar*) "totalResults") == 0) {
/* openSearch:totalResults */
xmlChar *total_results_string;
@@ -636,6 +614,12 @@ gdata_feed_get_categories (GDataFeed *self)
return self->priv->categories;
}
+static void
+_gdata_feed_add_category (GDataFeed *self, GDataCategory *category)
+{
+ self->priv->categories = g_list_prepend (self->priv->categories, g_object_ref (category));
+}
+
/**
* gdata_feed_get_links:
* @self: a #GDataFeed
@@ -682,6 +666,12 @@ gdata_feed_look_up_link (GDataFeed *self, const gchar *rel)
return GDATA_LINK (element->data);
}
+static void
+_gdata_feed_add_link (GDataFeed *self, GDataLink *link)
+{
+ self->priv->links = g_list_prepend (self->priv->links, g_object_ref (link));
+}
+
/**
* gdata_feed_get_authors:
* @self: a #GDataFeed
@@ -697,6 +687,12 @@ gdata_feed_get_authors (GDataFeed *self)
return self->priv->authors;
}
+static void
+_gdata_feed_add_author (GDataFeed *self, GDataAuthor *author)
+{
+ self->priv->authors = g_list_prepend (self->priv->authors, g_object_ref (author));
+}
+
/**
* gdata_feed_get_title:
* @self: a #GDataFeed
diff --git a/gdata/gdata-parser.c b/gdata/gdata-parser.c
index 6536285..039d44e 100644
--- a/gdata/gdata-parser.c
+++ b/gdata/gdata-parser.c
@@ -26,6 +26,7 @@
#include "gdata-parser.h"
#include "gdata-service.h"
+#include "gdata-private.h"
static gchar *
print_element (xmlNode *node)
@@ -73,8 +74,8 @@ gdata_parser_error_not_iso8601_format (xmlNode *element, const gchar *actual_val
{
gchar *element_string = print_element (element);
g_set_error (error, GDATA_SERVICE_ERROR, GDATA_SERVICE_ERROR_PROTOCOL_ERROR,
- /* Translators: the first parameter is the name of an XML element (including the angle brackets ("<" and ">")), and the second parameter is
- * the erroneous value (which was not in ISO 8601 format).
+ /* Translators: the first parameter is the name of an XML element (including the angle brackets ("<" and ">")),
+ * and the second parameter is the erroneous value (which was not in ISO 8601 format).
*
* For example:
* The content of a <media:group/media:uploaded> element ("2009-05-06 26:30Z") was not in ISO 8601 format. */
@@ -253,7 +254,7 @@ gdata_parser_boolean_from_property (xmlNode *element, const gchar *property_name
* gdata_parser_string_from_element:
* @element: the element to check against
* @element_name: the name of the element to parse
- * @options: a bitwise combination of parsing options from #GDataParserStringOptions, or %P_NONE
+ * @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
@@ -278,22 +279,19 @@ gdata_parser_boolean_from_property (xmlNode *element, const gchar *property_name
* Since: 0.7.0
*/
gboolean
-gdata_parser_string_from_element (xmlNode *element, const gchar *element_name, GDataParserStringOptions options,
+gdata_parser_string_from_element (xmlNode *element, const gchar *element_name, GDataParserOptions options,
gchar **output, gboolean *success, GError **error)
{
xmlChar *text;
+ /* Check it's the right element */
if (xmlStrcmp (element->name, (xmlChar*) element_name) != 0)
return FALSE;
/* Check if the output string has already been set */
- if (*output != NULL) {
- if (options & P_NO_DUPES) {
- *success = gdata_parser_error_duplicate_element (element, error);
- return TRUE;
- } else {
- g_free (*output);
- }
+ if (options & P_NO_DUPES && *output != NULL) {
+ *success = gdata_parser_error_duplicate_element (element, error);
+ return TRUE;
}
/* Get the string and check it for NULLness or emptiness */
@@ -304,12 +302,153 @@ gdata_parser_string_from_element (xmlNode *element, const gchar *element_name, G
return TRUE;
}
+ /* Success! */
+ g_free (*output);
*output = (gchar*) text;
*success = TRUE;
return TRUE;
}
+/*
+ * gdata_parser_object_from_element_setter:
+ * @element: the element to check against
+ * @element_name: the name of the element to parse
+ * @options: a bitwise combination of parsing options from #GDataParserOptions, or %P_NONE
+ * @object_type: the type of the object to parse
+ * @_setter: a function to call once parsing's finished to return the object (#GDataParserSetterFunc)
+ * @_parent_parsable: the first parameter to pass to @_setter (of type #GDataParsable)
+ * @success: the return location for a value which is %TRUE if the object 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 object content of @element if its name is @element_name, subject to various checks specified by @options. If @element matches @element_name,
+ * @element will be parsed as an @object_type, which must extend #GDataParsable. If parsing is successful, @_setter will be called with its first
+ * parameter as @_parent_parsable, and its second as the parsed object of type @object_type. @_setter must reference the parsed object it's passed if
+ * it wants to keep it, as gdata_parser_object_from_element_setter will unreference it before returning.
+ *
+ * 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_object_from_element_setter() 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_object_from_element_setter() return %TRUE, the value of @success can be examined.
+ *
+ * @_setter and @_parent_parsable are both #gpointer<!-- -->s to avoid casts having to be put into calls to gdata_parser_object_from_element_setter().
+ * @_setter is actually of type #GDataParserSetterFunc, and @_parent_parsable should be a subclass of #GDataParsable. Neither parameter should be %NULL.
+ * No checks are implemented against these conditions (for efficiency reasons), so calling code must be correct.
+ *
+ * Return value: %TRUE if @element matched @element_name, %FALSE otherwise
+ *
+ * Since: 0.7.0
+ */
+gboolean
+gdata_parser_object_from_element_setter (xmlNode *element, const gchar *element_name, GDataParserOptions options, GType object_type,
+ gpointer /* GDataParserSetterFunc */ _setter, gpointer /* GDataParsable * */ _parent_parsable,
+ gboolean *success, GError **error)
+{
+ GDataParsable *parsable, *parent_parsable;
+ GDataParserSetterFunc setter;
+
+ /* We're lax on the types so that we don't have to do loads of casting when calling the function, which makes the parsing code more legible */
+ setter = (GDataParserSetterFunc) _setter;
+ parent_parsable = (GDataParsable*) _parent_parsable;
+
+ /* Check it's the right element */
+ if (xmlStrcmp (element->name, (xmlChar*) element_name) != 0)
+ return FALSE;
+
+ /* Get the object and check for instantiation failure */
+ parsable = _gdata_parsable_new_from_xml_node (object_type, element->doc, element, NULL, error);
+ if (options & P_REQUIRED && parsable == NULL) {
+ /* The error has already been set by _gdata_parsable_new_from_xml_node() */
+ *success = FALSE;
+ return TRUE;
+ }
+
+ /* Success! */
+ setter (parent_parsable, parsable);
+ g_object_unref (parsable);
+ *success = TRUE;
+
+ return TRUE;
+}
+
+/*
+ * gdata_parser_object_from_element:
+ * @element: the element to check against
+ * @element_name: the name of the element to parse
+ * @options: a bitwise combination of parsing options from #GDataParserOptions, or %P_NONE
+ * @object_type: the type of the object to parse
+ * @_output: the return location for the parsed object (of type #GDataParsable)
+ * @success: the return location for a value which is %TRUE if the object 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 object content of @element if its name is @element_name, subject to various checks specified by @options. If @element matches @element_name,
+ * @element will be parsed as an @object_type, which must extend #GDataParsable. If parsing is successful, the parsed object will be returned in
+ * @_output, which must be of type #GDataParsable (or a subclass). Ownership of the parsed object will pass to the calling code.
+ *
+ * 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_object_from_element_setter() 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_object_from_element_setter() return %TRUE, the value of @success can be examined.
+ *
+ * @_object is a #gpointer to avoid casts having to be put into calls to gdata_parser_object_from_element(). It is actually of type #GDataParsable
+ * and must not be %NULL. No check is implemented against this condition (for efficiency reasons), so calling code must be correct.
+ *
+ * Return value: %TRUE if @element matched @element_name, %FALSE otherwise
+ *
+ * Since: 0.7.0
+ */
+gboolean
+gdata_parser_object_from_element (xmlNode *element, const gchar *element_name, GDataParserOptions options, GType object_type,
+ gpointer /* GDataParsable ** */ _output, gboolean *success, GError **error)
+{
+ GDataParsable *parsable, **output;
+
+ /* We're lax on the types so that we don't have to do loads of casting when calling the function, which makes the parsing code more legible */
+ output = (GDataParsable**) _output;
+
+ /* Check it's the right element */
+ if (xmlStrcmp (element->name, (xmlChar*) element_name) != 0)
+ return FALSE;
+
+ /* If we're not using a setter, check if the output already exists */
+ if (options & P_NO_DUPES && *output != NULL) {
+ *success = gdata_parser_error_duplicate_element (element, error);
+ return TRUE;
+ }
+
+ /* Get the object and check for instantiation failure */
+ parsable = _gdata_parsable_new_from_xml_node (object_type, element->doc, element, NULL, error);
+ if (options & P_REQUIRED && parsable == NULL) {
+ /* The error has already been set by _gdata_parsable_new_from_xml_node() */
+ *success = FALSE;
+ return TRUE;
+ }
+
+ /* Success! */
+ if (*output != NULL)
+ g_object_unref (*output);
+ *output = parsable;
+ *success = TRUE;
+
+ 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 4147e23..c8d9692 100644
--- a/gdata/gdata-parser.h
+++ b/gdata/gdata-parser.h
@@ -19,6 +19,8 @@
#include <glib.h>
+#include "gdata-parsable.h"
+
#ifndef GDATA_PARSER_H
#define GDATA_PARSER_H
@@ -36,14 +38,15 @@ gboolean gdata_parser_time_val_from_date (const gchar *date, GTimeVal *_time);
gchar *gdata_parser_date_from_time_val (const GTimeVal *_time) G_GNUC_WARN_UNUSED_RESULT;
/*
- * GDataParserStringOptions:
+ * GDataParserOptions:
* @P_NONE: no special options; the content of the element will be outputted directly without any checks
* @P_NO_DUPES: the element must be encountered at most once; if encountered more than once, an error will be returned
* @P_REQUIRED: the element content must not be %NULL if the element exists
- * @P_NON_EMPTY: the element content must not be empty (i.e. a zero-length string) if the element exists
+ * @P_NON_EMPTY: the element content must not be empty (i.e. a zero-length string) if the element exists;
+ * this only applies to gdata_parser_string_from_element()
*
- * Parsing options to be passed in a bitwise fashion to gdata_parser_string_from_element(). Their names aren't namespaced as they
- * aren't public, and brevity is important, since they're used frequently in the parsing code.
+ * Parsing options to be passed in a bitwise fashion to gdata_parser_string_from_element() or gdata_parser_object_from_element().
+ * Their names aren't namespaced as they aren't public, and brevity is important, since they're used frequently in the parsing code.
*
* Since: 0.7.0
*/
@@ -52,11 +55,18 @@ typedef enum {
P_NO_DUPES = 1 << 0,
P_REQUIRED = 1 << 1,
P_NON_EMPTY = 1 << 2
-} GDataParserStringOptions;
+} GDataParserOptions;
+
+typedef void (*GDataParserSetterFunc) (GDataParsable *parent_parsable, GDataParsable *parsable);
gboolean gdata_parser_boolean_from_property (xmlNode *element, const gchar *property_name, gboolean *output, gint default_output, GError **error);
-gboolean gdata_parser_string_from_element (xmlNode *element, const gchar *element_name, GDataParserStringOptions options,
+gboolean gdata_parser_string_from_element (xmlNode *element, const gchar *element_name, GDataParserOptions options,
gchar **output, gboolean *success, GError **error);
+gboolean gdata_parser_object_from_element_setter (xmlNode *element, const gchar *element_name, GDataParserOptions options, GType object_type,
+ gpointer /* GDataParserSetterFunc */ _setter, gpointer /* GDataParsable * */ _parent_parsable,
+ 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);
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;
diff --git a/gdata/gdata.symbols b/gdata/gdata.symbols
index 2d1a764..ec7cda6 100644
--- a/gdata/gdata.symbols
+++ b/gdata/gdata.symbols
@@ -393,6 +393,7 @@ gdata_gd_when_set_is_date
gdata_gd_when_get_value_string
gdata_gd_when_set_value_string
gdata_gd_when_get_reminders
+gdata_gd_when_add_reminder
gdata_gd_who_get_type
gdata_gd_who_new
gdata_gd_who_compare
diff --git a/gdata/media/gdata-media-group.c b/gdata/media/gdata-media-group.c
index 346c996..065154b 100644
--- a/gdata/media/gdata-media-group.c
+++ b/gdata/media/gdata-media-group.c
@@ -143,35 +143,16 @@ parse_xml (GDataParsable *parsable, xmlDoc *doc, xmlNode *node, gpointer user_da
if (gdata_parser_string_from_element (node, "title", P_NONE, &(self->priv->title), &success, error) == TRUE ||
gdata_parser_string_from_element (node, "description", P_NONE, &(self->priv->description), &success, error) == TRUE ||
- gdata_parser_string_from_element (node, "keywords", P_NONE, &(self->priv->keywords), &success, error) == TRUE) {
+ gdata_parser_string_from_element (node, "keywords", P_NONE, &(self->priv->keywords), &success, error) == TRUE ||
+ gdata_parser_object_from_element_setter (node, "category", P_REQUIRED, GDATA_TYPE_MEDIA_CATEGORY,
+ gdata_media_group_set_category, self, &success, error) == TRUE ||
+ gdata_parser_object_from_element_setter (node, "content", P_REQUIRED, GDATA_TYPE_MEDIA_CONTENT,
+ _gdata_media_group_add_content, self, &success, error) == TRUE ||
+ gdata_parser_object_from_element_setter (node, "thumbnail", P_REQUIRED, GDATA_TYPE_MEDIA_THUMBNAIL,
+ _gdata_media_group_add_thumbnail, self, &success, error) == TRUE ||
+ gdata_parser_object_from_element (node, "credit", P_REQUIRED | P_NO_DUPES, GDATA_TYPE_MEDIA_CREDIT,
+ &(self->priv->credit), &success, error) == TRUE) {
return success;
- } else if (xmlStrcmp (node->name, (xmlChar*) "category") == 0) {
- /* media:category */
- GDataMediaCategory *category = GDATA_MEDIA_CATEGORY (_gdata_parsable_new_from_xml_node (GDATA_TYPE_MEDIA_CATEGORY, doc,
- node, NULL, error));
- if (category == NULL)
- return FALSE;
-
- gdata_media_group_set_category (self, category);
- } else if (xmlStrcmp (node->name, (xmlChar*) "content") == 0) {
- /* media:content */
- GDataMediaContent *content = GDATA_MEDIA_CONTENT (_gdata_parsable_new_from_xml_node (GDATA_TYPE_MEDIA_CONTENT, doc, node, NULL, error));
- if (content == NULL)
- return FALSE;
-
- _gdata_media_group_add_content (self, content);
- } else if (xmlStrcmp (node->name, (xmlChar*) "credit") == 0) {
- /* media:credit */
- GDataMediaCredit *credit = GDATA_MEDIA_CREDIT (_gdata_parsable_new_from_xml_node (GDATA_TYPE_MEDIA_CREDIT, doc, node, NULL, error));
- if (credit == NULL)
- return FALSE;
-
- if (self->priv->credit != NULL) {
- g_object_unref (credit);
- return gdata_parser_error_duplicate_element (node, error);
- }
-
- _gdata_media_group_set_credit (self, credit);
} else if (xmlStrcmp (node->name, (xmlChar*) "player") == 0) {
/* media:player */
xmlChar *player_uri = xmlGetProp (node, (xmlChar*) "url");
@@ -229,14 +210,6 @@ parse_xml (GDataParsable *parsable, xmlDoc *doc, xmlNode *node, gpointer user_da
for (country = country_list; *country != NULL; country++)
g_hash_table_insert (self->priv->restricted_countries, *country, GUINT_TO_POINTER (relationship_bool));
g_free (country_list);
- } else if (xmlStrcmp (node->name, (xmlChar*) "thumbnail") == 0) {
- /* media:thumbnail */
- GDataMediaThumbnail *thumb = GDATA_MEDIA_THUMBNAIL (_gdata_parsable_new_from_xml_node (GDATA_TYPE_MEDIA_THUMBNAIL, doc,
- node, NULL, error));
- if (thumb == NULL)
- return FALSE;
-
- self->priv->thumbnails = g_list_prepend (self->priv->thumbnails, thumb);
} else if (GDATA_PARSABLE_CLASS (gdata_media_group_parent_class)->parse_xml (parsable, doc, node, user_data, error) == FALSE) {
/* Error! */
return FALSE;
@@ -460,7 +433,7 @@ gdata_media_group_get_contents (GDataMediaGroup *self)
void
_gdata_media_group_add_content (GDataMediaGroup *self, GDataMediaContent *content)
{
- self->priv->contents = g_list_prepend (self->priv->contents, content);
+ self->priv->contents = g_list_prepend (self->priv->contents, g_object_ref (content));
}
/**
@@ -535,3 +508,9 @@ gdata_media_group_get_thumbnails (GDataMediaGroup *self)
g_return_val_if_fail (GDATA_IS_MEDIA_GROUP (self), NULL);
return self->priv->thumbnails;
}
+
+void
+_gdata_media_group_add_thumbnail (GDataMediaGroup *self, GDataMediaThumbnail *thumbnail)
+{
+ self->priv->thumbnails = g_list_prepend (self->priv->thumbnails, g_object_ref (thumbnail));
+}
diff --git a/gdata/media/gdata-media-group.h b/gdata/media/gdata-media-group.h
index ab54970..c6e69bc 100644
--- a/gdata/media/gdata-media-group.h
+++ b/gdata/media/gdata-media-group.h
@@ -27,6 +27,7 @@
#include <gdata/media/gdata-media-category.h>
#include <gdata/media/gdata-media-content.h>
#include <gdata/media/gdata-media-credit.h>
+#include <gdata/media/gdata-media-thumbnail.h>
G_BEGIN_DECLS
@@ -79,6 +80,7 @@ void _gdata_media_group_set_credit (GDataMediaGroup *self, GDataMediaCredit *cre
const gchar *gdata_media_group_get_player_uri (GDataMediaGroup *self);
gboolean gdata_media_group_is_restricted_in_country (GDataMediaGroup *self, const gchar *country);
GList *gdata_media_group_get_thumbnails (GDataMediaGroup *self);
+void _gdata_media_group_add_thumbnail (GDataMediaGroup *self, GDataMediaThumbnail *thumbnail);
G_END_DECLS
diff --git a/gdata/services/calendar/gdata-calendar-event.c b/gdata/services/calendar/gdata-calendar-event.c
index b1ca713..4c38582 100644
--- a/gdata/services/calendar/gdata-calendar-event.c
+++ b/gdata/services/calendar/gdata-calendar-event.c
@@ -447,6 +447,7 @@ gdata_calendar_event_new (const gchar *id)
static gboolean
parse_xml (GDataParsable *parsable, xmlDoc *doc, xmlNode *node, gpointer user_data, GError **error)
{
+ gboolean success;
GDataCalendarEvent *self;
g_return_val_if_fail (GDATA_IS_CALENDAR_EVENT (parsable), FALSE);
@@ -528,13 +529,13 @@ parse_xml (GDataParsable *parsable, xmlDoc *doc, xmlNode *node, gpointer user_da
xmlFree (value);
gdata_calendar_event_set_sequence (self, value_uint);
- } else if (xmlStrcmp (node->name, (xmlChar*) "when") == 0) {
- /* gd:when */
- GDataGDWhen *when = GDATA_GD_WHEN (_gdata_parsable_new_from_xml_node (GDATA_TYPE_GD_WHEN, doc, node, NULL, error));
- if (when == NULL)
- return FALSE;
-
- gdata_calendar_event_add_time (self, when);
+ } else if (gdata_parser_object_from_element_setter (node, "when", P_REQUIRED, GDATA_TYPE_GD_WHEN,
+ gdata_calendar_event_add_time, self, &success, error) == TRUE ||
+ gdata_parser_object_from_element_setter (node, "who", P_REQUIRED, GDATA_TYPE_GD_WHO,
+ gdata_calendar_event_add_person, self, &success, error) == TRUE ||
+ gdata_parser_object_from_element_setter (node, "where", P_REQUIRED, GDATA_TYPE_GD_WHERE,
+ gdata_calendar_event_add_place, self, &success, error) == TRUE) {
+ return success;
} else if (xmlStrcmp (node->name, (xmlChar*) "guestsCanModify") == 0) {
/* gCal:guestsCanModify */
gboolean guests_can_modify;
@@ -559,20 +560,6 @@ parse_xml (GDataParsable *parsable, xmlDoc *doc, xmlNode *node, gpointer user_da
if (gdata_parser_boolean_from_property (node, "value", &anyone_can_add_self, -1, error) == FALSE)
return FALSE;
gdata_calendar_event_set_anyone_can_add_self (self, anyone_can_add_self);
- } else if (xmlStrcmp (node->name, (xmlChar*) "who") == 0) {
- /* gd:who */
- GDataGDWho *who = GDATA_GD_WHO (_gdata_parsable_new_from_xml_node (GDATA_TYPE_GD_WHO, doc, node, NULL, error));
- if (who == NULL)
- return FALSE;
-
- gdata_calendar_event_add_person (self, who);
- } else if (xmlStrcmp (node->name, (xmlChar*) "where") == 0) {
- /* gd:where */
- GDataGDWhere *where = GDATA_GD_WHERE (_gdata_parsable_new_from_xml_node (GDATA_TYPE_GD_WHERE, doc, node, NULL, error));
- if (where == NULL)
- return FALSE;
-
- gdata_calendar_event_add_place (self, where);
} else if (xmlStrcmp (node->name, (xmlChar*) "recurrence") == 0) {
/* gd:recurrence */
self->priv->recurrence = (gchar*) xmlNodeListGetString (doc, node->children, TRUE);
diff --git a/gdata/services/contacts/gdata-contacts-contact.c b/gdata/services/contacts/gdata-contacts-contact.c
index 207db82..7e71a98 100644
--- a/gdata/services/contacts/gdata-contacts-contact.c
+++ b/gdata/services/contacts/gdata-contacts-contact.c
@@ -290,6 +290,7 @@ gdata_contacts_contact_new (const gchar *id)
static gboolean
parse_xml (GDataParsable *parsable, xmlDoc *doc, xmlNode *node, gpointer user_data, GError **error)
{
+ gboolean success;
GDataContactsContact *self;
g_return_val_if_fail (GDATA_IS_CONTACTS_CONTACT (parsable), FALSE);
@@ -309,54 +310,18 @@ parse_xml (GDataParsable *parsable, xmlDoc *doc, xmlNode *node, gpointer user_da
return FALSE;
}
g_free (edited);
- } else if (xmlStrcmp (node->name, (xmlChar*) "name") == 0) {
- /* gd:name */
- GDataGDName *name = GDATA_GD_NAME (_gdata_parsable_new_from_xml_node (GDATA_TYPE_GD_NAME, doc, node, NULL, error));
- if (name == NULL)
- return FALSE;
-
- if (self->priv->name != NULL)
- g_object_unref (self->priv->name);
- self->priv->name = name;
- } else if (xmlStrcmp (node->name, (xmlChar*) "email") == 0) {
- /* gd:email */
- GDataGDEmailAddress *email = GDATA_GD_EMAIL_ADDRESS (_gdata_parsable_new_from_xml_node (GDATA_TYPE_GD_EMAIL_ADDRESS, doc,
- node, NULL, error));
- if (email == NULL)
- return FALSE;
-
- gdata_contacts_contact_add_email_address (self, email);
- } else if (xmlStrcmp (node->name, (xmlChar*) "im") == 0) {
- /* gd:im */
- GDataGDIMAddress *im = GDATA_GD_IM_ADDRESS (_gdata_parsable_new_from_xml_node (GDATA_TYPE_GD_IM_ADDRESS, doc, node, NULL, error));
- if (im == NULL)
- return FALSE;
-
- gdata_contacts_contact_add_im_address (self, im);
- } else if (xmlStrcmp (node->name, (xmlChar*) "phoneNumber") == 0) {
- /* gd:phoneNumber */
- GDataGDPhoneNumber *number = GDATA_GD_PHONE_NUMBER (_gdata_parsable_new_from_xml_node (GDATA_TYPE_GD_PHONE_NUMBER, doc,
- node, NULL, error));
- if (number == NULL)
- return FALSE;
-
- gdata_contacts_contact_add_phone_number (self, number);
- } else if (xmlStrcmp (node->name, (xmlChar*) "structuredPostalAddress") == 0) {
- /* gd:structuredPostalAddress â?? deprecates gd:postalAddress */
- GDataGDPostalAddress *address = GDATA_GD_POSTAL_ADDRESS (_gdata_parsable_new_from_xml_node (GDATA_TYPE_GD_POSTAL_ADDRESS,
- doc, node, NULL, error));
- if (address == NULL)
- return FALSE;
-
- gdata_contacts_contact_add_postal_address (self, address);
- } else if (xmlStrcmp (node->name, (xmlChar*) "organization") == 0) {
- /* gd:organization */
- GDataGDOrganization *organization = GDATA_GD_ORGANIZATION (_gdata_parsable_new_from_xml_node (GDATA_TYPE_GD_ORGANIZATION,
- doc, node, NULL, error));
- if (organization == NULL)
- return FALSE;
-
- gdata_contacts_contact_add_organization (self, organization);
+ } else if (gdata_parser_object_from_element_setter (node, "email", P_REQUIRED, GDATA_TYPE_GD_EMAIL_ADDRESS,
+ gdata_contacts_contact_add_email_address, self, &success, error) == TRUE ||
+ gdata_parser_object_from_element_setter (node, "im", P_REQUIRED, GDATA_TYPE_GD_IM_ADDRESS,
+ gdata_contacts_contact_add_im_address, self, &success, error) == TRUE ||
+ gdata_parser_object_from_element_setter (node, "phoneNumber", P_REQUIRED, GDATA_TYPE_GD_PHONE_NUMBER,
+ gdata_contacts_contact_add_phone_number, self, &success, error) == TRUE ||
+ gdata_parser_object_from_element_setter (node, "structuredPostalAddress", P_REQUIRED, GDATA_TYPE_GD_POSTAL_ADDRESS,
+ gdata_contacts_contact_add_postal_address, self, &success, error) == TRUE ||
+ gdata_parser_object_from_element_setter (node, "organization", P_REQUIRED, GDATA_TYPE_GD_ORGANIZATION,
+ gdata_contacts_contact_add_organization, self, &success, error) == TRUE ||
+ gdata_parser_object_from_element (node, "name", P_REQUIRED, GDATA_TYPE_GD_NAME, &(self->priv->name), &success, error) == TRUE) {
+ return success;
} else if (xmlStrcmp (node->name, (xmlChar*) "extendedProperty") == 0) {
/* gd:extendedProperty */
xmlChar *name, *value;
diff --git a/gdata/services/documents/gdata-documents-entry.c b/gdata/services/documents/gdata-documents-entry.c
index 1bcc4f1..e31467f 100644
--- a/gdata/services/documents/gdata-documents-entry.c
+++ b/gdata/services/documents/gdata-documents-entry.c
@@ -201,6 +201,7 @@ gdata_documents_entry_access_handler_init (GDataAccessHandlerIface *iface)
static gboolean
parse_xml (GDataParsable *parsable, xmlDoc *doc, xmlNode *node, gpointer user_data, GError **error)
{
+ gboolean success;
GDataDocumentsEntry *self = GDATA_DOCUMENTS_ENTRY (parsable);
if (xmlStrcmp (node->name, (xmlChar*) "edited") == 0) {
@@ -249,17 +250,11 @@ parse_xml (GDataParsable *parsable, xmlDoc *doc, xmlNode *node, gpointer user_da
self->priv->document_id = g_strdup (document_id_parts[1]);
g_strfreev (document_id_parts);
- } else if (xmlStrcmp (node->name, (xmlChar*) "feedLink") == 0) {
- GDataLink *link = GDATA_LINK (_gdata_parsable_new_from_xml_node (GDATA_TYPE_LINK, doc, node, NULL, error));
- if (link == NULL)
- return FALSE;
- gdata_entry_add_link (GDATA_ENTRY (self), link);
- g_object_unref (link);
- } else if (xmlStrcmp (node->name, (xmlChar*) "lastModifiedBy") == 0) {
- GDataAuthor *last_modified_by = GDATA_AUTHOR (_gdata_parsable_new_from_xml_node (GDATA_TYPE_AUTHOR, doc, node, NULL, error));
- if (last_modified_by == NULL)
- return FALSE;
- self->priv->last_modified_by = last_modified_by;
+ } else if (gdata_parser_object_from_element_setter (node, "feedLink", P_REQUIRED, GDATA_TYPE_LINK,
+ gdata_entry_add_link, self, &success, error) == TRUE ||
+ gdata_parser_object_from_element (node, "lastModifiedBy", P_REQUIRED, GDATA_TYPE_AUTHOR,
+ &(self->priv->last_modified_by), &success, error) == TRUE) {
+ return success;
} else if (GDATA_PARSABLE_CLASS (gdata_documents_entry_parent_class)->parse_xml (parsable, doc, node, user_data, error) == FALSE) {
/* Error! */
return FALSE;
diff --git a/gdata/services/picasaweb/gdata-picasaweb-album.c b/gdata/services/picasaweb/gdata-picasaweb-album.c
index 9b705fb..96341bf 100644
--- a/gdata/services/picasaweb/gdata-picasaweb-album.c
+++ b/gdata/services/picasaweb/gdata-picasaweb-album.c
@@ -550,31 +550,15 @@ parse_xml (GDataParsable *parsable, xmlDoc *doc, xmlNode *node, gpointer user_da
gboolean success;
GDataPicasaWebAlbum *self = GDATA_PICASAWEB_ALBUM (parsable);
- if (xmlStrcmp (node->name, (xmlChar*) "group") == 0) {
- /* media:group */
- GDataMediaGroup *group = GDATA_MEDIA_GROUP (_gdata_parsable_new_from_xml_node (GDATA_TYPE_MEDIA_GROUP, doc, node, NULL, error));
- if (group == NULL)
- return FALSE;
-
- if (self->priv->media_group != NULL)
- /* We should really error here, but we can't, as priv->media_group has to be pre-populated
- * in order for things like gdata_picasaweb_album_get_tags() to work. */
- g_object_unref (self->priv->media_group);
-
- self->priv->media_group = group;
- } else if (xmlStrcmp (node->name, (xmlChar*) "where") == 0) {
- /* georss:where */
- GDataGeoRSSWhere *where = GDATA_GEORSS_WHERE (_gdata_parsable_new_from_xml_node (GDATA_TYPE_GEORSS_WHERE, doc, node, NULL, error));
- if (where == NULL)
- return FALSE;
-
- if (self->priv->georss_where != NULL)
- g_object_unref (self->priv->georss_where);
-
- self->priv->georss_where = where;
- } else if (gdata_parser_string_from_element (node, "user", P_REQUIRED | P_NON_EMPTY, &(self->priv->user), &success, error) == TRUE ||
- gdata_parser_string_from_element (node, "nickname", P_REQUIRED | P_NON_EMPTY, &(self->priv->nickname), &success, error) == TRUE ||
- gdata_parser_string_from_element (node, "location", P_NONE, &(self->priv->location), &success, error) == TRUE) {
+ /* TODO: This should also be P_NO_DUPES, but we can't, as priv->media_group has to be pre-populated
+ * in order for things like gdata_picasaweb_album_get_tags() to work. */
+ if (gdata_parser_object_from_element (node, "group", P_REQUIRED, GDATA_TYPE_MEDIA_GROUP,
+ &(self->priv->media_group), &success, error) == TRUE ||
+ gdata_parser_object_from_element (node, "where", P_REQUIRED, GDATA_TYPE_GEORSS_WHERE,
+ &(self->priv->georss_where), &success, error) == TRUE ||
+ gdata_parser_string_from_element (node, "user", P_REQUIRED | P_NON_EMPTY, &(self->priv->user), &success, error) == TRUE ||
+ gdata_parser_string_from_element (node, "nickname", P_REQUIRED | P_NON_EMPTY, &(self->priv->nickname), &success, error) == TRUE ||
+ gdata_parser_string_from_element (node, "location", P_NONE, &(self->priv->location), &success, error) == TRUE) {
return success;
} else if (xmlStrcmp (node->name, (xmlChar*) "edited") == 0) {
/* app:edited */
diff --git a/gdata/services/picasaweb/gdata-picasaweb-file.c b/gdata/services/picasaweb/gdata-picasaweb-file.c
index c4466ed..9cea5a1 100644
--- a/gdata/services/picasaweb/gdata-picasaweb-file.c
+++ b/gdata/services/picasaweb/gdata-picasaweb-file.c
@@ -796,38 +796,20 @@ parse_xml (GDataParsable *parsable, xmlDoc *doc, xmlNode *node, gpointer user_da
gboolean success;
GDataPicasaWebFile *self = GDATA_PICASAWEB_FILE (parsable);
- if (xmlStrcmp (node->name, (xmlChar*) "group") == 0) {
- /* media:group */
- GDataMediaGroup *group = GDATA_MEDIA_GROUP (_gdata_parsable_new_from_xml_node (GDATA_TYPE_MEDIA_GROUP, doc, node, NULL, error));
- if (group == NULL)
- return FALSE;
-
- if (self->priv->media_group != NULL)
- /* We should really error here, but we can't, as priv->media_group has to be pre-populated
- * in order for things like gdata_picasaweb_file_set_description() to work. */
- g_object_unref (self->priv->media_group);
-
- self->priv->media_group = group;
- } else if (xmlStrcmp (node->name, (xmlChar*) "where") == 0) {
- /* georss:where */
- GDataGeoRSSWhere *where = GDATA_GEORSS_WHERE (_gdata_parsable_new_from_xml_node (GDATA_TYPE_GEORSS_WHERE, doc, node, NULL, error));
- if (where == NULL)
- return FALSE;
-
- if (self->priv->georss_where != NULL)
- g_object_unref (self->priv->georss_where);
-
- self->priv->georss_where = where;
- } else if (xmlStrcmp (node->name, (xmlChar*) "tags") == 0) {
- /* exif:tags */
- GDataExifTags *tags = GDATA_EXIF_TAGS (_gdata_parsable_new_from_xml_node (GDATA_TYPE_EXIF_TAGS, doc, node, NULL, error));
- if (tags == NULL)
- return FALSE;
-
- if (self->priv->exif_tags != NULL)
- g_object_unref (self->priv->exif_tags);
-
- self->priv->exif_tags = tags;
+ /* TODO: This should also be P_NO_DUPES, but we can't, as priv->media_group has to be pre-populated
+ * in order for things like gdata_picasaweb_file_set_description() to work. */
+ if (gdata_parser_object_from_element (node, "group", P_REQUIRED, GDATA_TYPE_MEDIA_GROUP,
+ &(self->priv->media_group), &success, error) == TRUE ||
+ gdata_parser_object_from_element (node, "where", P_REQUIRED, GDATA_TYPE_GEORSS_WHERE,
+ &(self->priv->georss_where), &success, error) == TRUE ||
+ gdata_parser_object_from_element (node, "tags", P_REQUIRED, GDATA_TYPE_EXIF_TAGS,
+ &(self->priv->exif_tags), &success, error) == TRUE ||
+ gdata_parser_string_from_element (node, "videostatus", P_NO_DUPES, &(self->priv->video_status), &success, error) == TRUE ||
+ gdata_parser_string_from_element (node, "imageVersion", P_NONE, &(self->priv->version), &success, error) == TRUE ||
+ gdata_parser_string_from_element (node, "albumid", P_NONE, &(self->priv->album_id), &success, error) == TRUE ||
+ gdata_parser_string_from_element (node, "client", P_NONE, &(self->priv->client), &success, error) == TRUE ||
+ gdata_parser_string_from_element (node, "checksum", P_NONE, &(self->priv->client), &success, error) == TRUE) {
+ return success;
} else if (xmlStrcmp (node->name, (xmlChar*) "edited") == 0) {
/* app:edited */
xmlChar *edited = xmlNodeListGetString (doc, node->children, TRUE);
@@ -884,12 +866,6 @@ parse_xml (GDataParsable *parsable, xmlDoc *doc, xmlNode *node, gpointer user_da
xmlChar *comment_count = xmlNodeListGetString (doc, node->children, TRUE);
self->priv->comment_count = strtoul ((gchar*) comment_count, NULL, 10);
xmlFree (comment_count);
- } else if (gdata_parser_string_from_element (node, "videostatus", P_NO_DUPES, &(self->priv->video_status), &success, error) == TRUE ||
- gdata_parser_string_from_element (node, "imageVersion", P_NONE, &(self->priv->version), &success, error) == TRUE ||
- gdata_parser_string_from_element (node, "albumid", P_NONE, &(self->priv->album_id), &success, error) == TRUE ||
- gdata_parser_string_from_element (node, "client", P_NONE, &(self->priv->client), &success, error) == TRUE ||
- gdata_parser_string_from_element (node, "checksum", P_NONE, &(self->priv->client), &success, error) == TRUE) {
- return success;
} else if (xmlStrcmp (node->name, (xmlChar*) "access") == 0) {
/* gphoto:access */
/* Visibility is already obtained through the album. When PicasaWeb supports per-file access restrictions,
diff --git a/gdata/services/youtube/gdata-youtube-control.c b/gdata/services/youtube/gdata-youtube-control.c
index d909729..9937d65 100644
--- a/gdata/services/youtube/gdata-youtube-control.c
+++ b/gdata/services/youtube/gdata-youtube-control.c
@@ -96,6 +96,7 @@ gdata_youtube_control_dispose (GObject *object)
static gboolean
parse_xml (GDataParsable *parsable, xmlDoc *doc, xmlNode *node, gpointer user_data, GError **error)
{
+ gboolean success;
GDataYouTubeControl *self = GDATA_YOUTUBE_CONTROL (parsable);
if (xmlStrcmp (node->name, (xmlChar*) "draft") == 0) {
@@ -106,18 +107,9 @@ parse_xml (GDataParsable *parsable, xmlDoc *doc, xmlNode *node, gpointer user_da
else
self->priv->is_draft = TRUE;
xmlFree (draft);
- } else if (xmlStrcmp (node->name, (xmlChar*) "state") == 0) {
- /* yt:state */
- GDataYouTubeState *state = GDATA_YOUTUBE_STATE (_gdata_parsable_new_from_xml_node (GDATA_TYPE_YOUTUBE_STATE, doc, node, NULL, error));
- if (state == NULL)
- return FALSE;
-
- if (self->priv->state != NULL) {
- g_object_unref (state);
- return gdata_parser_error_duplicate_element (node, error);
- }
-
- self->priv->state = state;
+ } else if (gdata_parser_object_from_element (node, "state", P_REQUIRED | P_NO_DUPES, GDATA_TYPE_YOUTUBE_STATE,
+ &(self->priv->state), &success, error) == TRUE) {
+ return success;
} else if (GDATA_PARSABLE_CLASS (gdata_youtube_control_parent_class)->parse_xml (parsable, doc, node, user_data, error) == FALSE) {
/* Error! */
return FALSE;
diff --git a/gdata/services/youtube/gdata-youtube-group.c b/gdata/services/youtube/gdata-youtube-group.c
index 4792b96..e5da07e 100644
--- a/gdata/services/youtube/gdata-youtube-group.c
+++ b/gdata/services/youtube/gdata-youtube-group.c
@@ -93,14 +93,9 @@ parse_xml (GDataParsable *parsable, xmlDoc *doc, xmlNode *node, gpointer user_da
gboolean success;
GDataYouTubeGroup *self = GDATA_YOUTUBE_GROUP (parsable);
- if (xmlStrcmp (node->name, (xmlChar*) "content") == 0) {
- /* media:content */
- GDataYouTubeContent *content = GDATA_YOUTUBE_CONTENT (_gdata_parsable_new_from_xml_node (GDATA_TYPE_YOUTUBE_CONTENT, doc,
- node, NULL, error));
- if (content == NULL)
- return FALSE;
-
- _gdata_media_group_add_content (GDATA_MEDIA_GROUP (self), GDATA_MEDIA_CONTENT (content));
+ if (gdata_parser_object_from_element_setter (node, "content", P_REQUIRED, GDATA_TYPE_YOUTUBE_CONTENT,
+ _gdata_media_group_add_content, self, &success, error) == TRUE) {
+ return success;
} else if (xmlStrcmp (node->name, (xmlChar*) "credit") == 0) {
/* media:credit */
GDataYouTubeCredit *credit = GDATA_YOUTUBE_CREDIT (_gdata_parsable_new_from_xml_node (GDATA_TYPE_YOUTUBE_CREDIT, doc,
diff --git a/gdata/services/youtube/gdata-youtube-video.c b/gdata/services/youtube/gdata-youtube-video.c
index 097c905..390482e 100644
--- a/gdata/services/youtube/gdata-youtube-video.c
+++ b/gdata/services/youtube/gdata-youtube-video.c
@@ -624,20 +624,14 @@ gdata_youtube_video_new (const gchar *id)
static gboolean
parse_xml (GDataParsable *parsable, xmlDoc *doc, xmlNode *node, gpointer user_data, GError **error)
{
+ gboolean success;
GDataYouTubeVideo *self = GDATA_YOUTUBE_VIDEO (parsable);
- if (xmlStrcmp (node->name, (xmlChar*) "group") == 0) {
- /* media:group */
- GDataMediaGroup *group = GDATA_MEDIA_GROUP (_gdata_parsable_new_from_xml_node (GDATA_TYPE_YOUTUBE_GROUP, doc, node, NULL, error));
- if (group == NULL)
- return FALSE;
-
- if (self->priv->media_group != NULL) {
- g_object_unref (group);
- return gdata_parser_error_duplicate_element (node, error);
- }
-
- self->priv->media_group = group;
+ if (gdata_parser_object_from_element (node, "group", P_REQUIRED | P_NO_DUPES, GDATA_TYPE_YOUTUBE_GROUP,
+ &(self->priv->media_group), &success, error) == TRUE ||
+ gdata_parser_object_from_element (node, "control", P_REQUIRED | P_NO_DUPES, GDATA_TYPE_YOUTUBE_CONTROL,
+ &(self->priv->youtube_control), &success, error) == TRUE) {
+ return success;
} else if (xmlStrcmp (node->name, (xmlChar*) "rating") == 0) {
/* gd:rating */
xmlChar *min, *max, *num_raters, *average;
@@ -767,19 +761,6 @@ parse_xml (GDataParsable *parsable, xmlDoc *doc, xmlNode *node, gpointer user_da
}
xmlFree (recorded);
gdata_youtube_video_set_recorded (self, &recorded_timeval);
- } else if (xmlStrcmp (node->name, (xmlChar*) "control") == 0) {
- /* app:control */
- GDataYouTubeControl *control = GDATA_YOUTUBE_CONTROL (_gdata_parsable_new_from_xml_node (GDATA_TYPE_YOUTUBE_CONTROL, doc,
- node, NULL, error));
- if (control == NULL)
- return FALSE;
-
- if (self->priv->youtube_control != NULL) {
- g_object_unref (control);
- return gdata_parser_error_duplicate_element (node, error);
- }
-
- self->priv->youtube_control = control;
} else if (GDATA_PARSABLE_CLASS (gdata_youtube_video_parent_class)->parse_xml (parsable, doc, node, user_data, error) == FALSE) {
/* Error! */
return FALSE;
diff --git a/gdata/tests/general.c b/gdata/tests/general.c
index 73e01e7..0a92ed1 100644
--- a/gdata/tests/general.c
+++ b/gdata/tests/general.c
@@ -1800,6 +1800,7 @@ static void
test_gd_when (void)
{
GDataGDWhen *when, *when2;
+ GDataGDReminder *reminder;
gchar *xml;
GList *reminders;
GTimeVal time_val, time_val2;
@@ -1874,12 +1875,18 @@ test_gd_when (void)
g_assert (gdata_gd_reminder_is_absolute_time (GDATA_GD_REMINDER (reminders->data)) == FALSE);
g_assert_cmpint (gdata_gd_reminder_get_relative_time (GDATA_GD_REMINDER (reminders->data)), ==, 15);
+ /* Add another reminder */
+ reminder = gdata_gd_reminder_new ("alert", &time_val, -1);
+ gdata_gd_when_add_reminder (when, reminder);
+ g_object_unref (reminder);
+
/* Check the outputted XML is correct */
xml = gdata_parsable_get_xml (GDATA_PARSABLE (when));
g_assert_cmpstr (xml, ==,
"<gd:when xmlns='http://www.w3.org/2005/Atom' xmlns:gd='http://schemas.google.com/g/2005' startTime='2005-06-06' "
"endTime='2005-06-08' valueString='This weekend'>"
"<gd:reminder minutes='15'/>"
+ "<gd:reminder absoluteTime='2005-06-06T00:00:00Z' method='alert'/>"
"<foobar/>"
"</gd:when>");
g_free (xml);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]