[libgdata] [core] Move all element string content parsing into one function



commit 39c746ad78870a34dceec15a1775a6df3e3476d4
Author: Philip Withnall <philip tecnocode co uk>
Date:   Tue Mar 23 00:19:47 2010 +0000

    [core] Move all element string content parsing into one function

 gdata/atom/gdata-author.c                        |   30 ++---------
 gdata/exif/gdata-exif-tags.c                     |   17 ++----
 gdata/gd/gdata-gd-im-address.c                   |   10 ++--
 gdata/gd/gdata-gd-name.c                         |   36 +++++--------
 gdata/gd/gdata-gd-organization.c                 |   32 +++---------
 gdata/gd/gdata-gd-postal-address.c               |   44 +++++++--------
 gdata/gdata-feed.c                               |   39 +++-----------
 gdata/gdata-parser.c                             |   63 ++++++++++++++++++++++
 gdata/gdata-parser.h                             |   21 +++++++
 gdata/media/gdata-media-content.c                |    2 +-
 gdata/media/gdata-media-group.c                  |   14 ++---
 gdata/services/picasaweb/gdata-picasaweb-album.c |   23 ++------
 gdata/services/picasaweb/gdata-picasaweb-file.c  |   28 +++-------
 gdata/services/picasaweb/gdata-picasaweb-user.c  |   39 +++-----------
 gdata/services/youtube/gdata-youtube-group.c     |   10 +---
 15 files changed, 177 insertions(+), 231 deletions(-)
---
diff --git a/gdata/atom/gdata-author.c b/gdata/atom/gdata-author.c
index d214e25..a6378cd 100644
--- a/gdata/atom/gdata-author.c
+++ b/gdata/atom/gdata-author.c
@@ -190,33 +190,13 @@ gdata_author_set_property (GObject *object, guint property_id, const GValue *val
 static gboolean
 parse_xml (GDataParsable *parsable, xmlDoc *doc, xmlNode *node, gpointer user_data, GError **error)
 {
+	gboolean success;
 	GDataAuthorPrivate *priv = GDATA_AUTHOR (parsable)->priv;
 
-	if (xmlStrcmp (node->name, (xmlChar*) "name") == 0) {
-		/* atom:name */
-		xmlChar *name;
-
-		if (priv->name != NULL)
-			return gdata_parser_error_duplicate_element (node, error);
-
-		name = xmlNodeListGetString (doc, node->children, TRUE);
-		if (name == NULL || *name == '\0') {
-			xmlFree (name);
-			return gdata_parser_error_required_content_missing (node, error);
-		}
-		priv->name = (gchar*) name;
-	} else if (xmlStrcmp (node->name, (xmlChar*) "uri") == 0) {
-		/* atom:uri */
-		if (priv->uri != NULL)
-			return gdata_parser_error_duplicate_element (node, error);
-
-		priv->uri = (gchar*) xmlNodeListGetString (doc, node->children, TRUE);
-	} else if (xmlStrcmp (node->name, (xmlChar*) "email") == 0) {
-		/* atom:email */
-		if (priv->email_address != NULL)
-			return gdata_parser_error_duplicate_element (node, error);
-
-		priv->email_address = (gchar*) xmlNodeListGetString (doc, node->children, TRUE);
+	if (gdata_parser_string_from_element (node, "name", P_NO_DUPES | P_REQUIRED | P_NON_EMPTY, &(priv->name), &success, error) == TRUE ||
+	    gdata_parser_string_from_element (node, "uri", P_NO_DUPES | P_REQUIRED | P_NON_EMPTY, &(priv->uri), &success, error) == TRUE ||
+	    gdata_parser_string_from_element (node, "email", P_NO_DUPES | P_REQUIRED | P_NON_EMPTY, &(priv->email_address), &success, error) == TRUE) {
+		return success;
 	} else if (GDATA_PARSABLE_CLASS (gdata_author_parent_class)->parse_xml (parsable, doc, node, user_data, error) == FALSE) {
 		/* Error! */
 		return FALSE;
diff --git a/gdata/exif/gdata-exif-tags.c b/gdata/exif/gdata-exif-tags.c
index 6db0d58..03f094d 100644
--- a/gdata/exif/gdata-exif-tags.c
+++ b/gdata/exif/gdata-exif-tags.c
@@ -106,6 +106,7 @@ gdata_exif_tags_finalize (GObject *object)
 static gboolean
 parse_xml (GDataParsable *parsable, xmlDoc *doc, xmlNode *node, gpointer user_data, GError **error)
 {
+	gboolean success;
 	GDataExifTags *self = GDATA_EXIF_TAGS (parsable);
 
 	if (xmlStrcmp (node->name, (xmlChar*) "distance") == 0 ) {
@@ -118,14 +119,10 @@ parse_xml (GDataParsable *parsable, xmlDoc *doc, xmlNode *node, gpointer user_da
 		xmlChar *fstop = xmlNodeListGetString (doc, node->children, TRUE);
 		self->priv->fstop = g_ascii_strtod ((gchar*) fstop, NULL);
 		xmlFree (fstop);
-	} else if (xmlStrcmp (node->name, (xmlChar*) "make") == 0) {
-		/* exif:make */
-		g_free (self->priv->make);
-		self->priv->make = (gchar*) xmlNodeListGetString (doc, node->children, TRUE);
-	} else if (xmlStrcmp (node->name, (xmlChar*) "model") == 0) {
-		/* exif:model */
-		g_free (self->priv->model);
-		self->priv->model = (gchar*) xmlNodeListGetString (doc, node->children, TRUE);
+	} else if (gdata_parser_string_from_element (node, "make", P_NONE, &(self->priv->make), &success, error) == TRUE ||
+	           gdata_parser_string_from_element (node, "model", P_NONE, &(self->priv->model), &success, error) == TRUE ||
+	           gdata_parser_string_from_element (node, "imageUniqueID", P_NONE, &(self->priv->image_unique_id), &success, error) == TRUE) {
+		return success;
 	} else if (xmlStrcmp (node->name, (xmlChar*) "exposure") == 0) {
 		/* exif:exposure */
 		xmlChar *exposure = xmlNodeListGetString (doc, node->children, TRUE);
@@ -159,10 +156,6 @@ parse_xml (GDataParsable *parsable, xmlDoc *doc, xmlNode *node, gpointer user_da
 
 		self->priv->_time.tv_sec = (glong) (milliseconds / 1000);
 		self->priv->_time.tv_usec = (glong) ((milliseconds % 1000) * 1000);
-	} else if (xmlStrcmp (node->name, (xmlChar*) "imageUniqueID") == 0) {
-		/* exif:imageUniqueID */
-		g_free (self->priv->image_unique_id);
-		self->priv->image_unique_id = (gchar*) xmlNodeListGetString (doc, node->children, TRUE);
 	} else if (GDATA_PARSABLE_CLASS (gdata_exif_tags_parent_class)->parse_xml (parsable, doc, node, user_data, error) == FALSE) {
 		/* Error! */
 		return FALSE;
diff --git a/gdata/gd/gdata-gd-im-address.c b/gdata/gd/gdata-gd-im-address.c
index 69d828a..09856fc 100644
--- a/gdata/gd/gdata-gd-im-address.c
+++ b/gdata/gd/gdata-gd-im-address.c
@@ -240,7 +240,7 @@ gdata_gd_im_address_set_property (GObject *object, guint property_id, const GVal
 static gboolean
 pre_parse_xml (GDataParsable *parsable, xmlDoc *doc, xmlNode *root_node, gpointer user_data, GError **error)
 {
-	xmlChar *address, *protocol, *rel;
+	xmlChar *address, *rel;
 	gboolean primary_bool;
 	GDataGDIMAddressPrivate *priv = GDATA_GD_IM_ADDRESS (parsable)->priv;
 
@@ -249,18 +249,20 @@ pre_parse_xml (GDataParsable *parsable, xmlDoc *doc, xmlNode *root_node, gpointe
 		return FALSE;
 
 	address = xmlGetProp (root_node, (xmlChar*) "address");
-	if (address == NULL || *address == '\0')
+	if (address == NULL || *address == '\0') {
+		xmlFree (address);
 		return gdata_parser_error_required_property_missing (root_node, "address", error);
+	}
 
 	rel = xmlGetProp (root_node, (xmlChar*) "rel");
 	if (rel != NULL && *rel == '\0') {
 		xmlFree (address);
+		xmlFree (rel);
 		return gdata_parser_error_required_property_missing (root_node, "rel", error);
 	}
-	protocol = xmlGetProp (root_node, (xmlChar*) "protocol");
 
 	priv->address = (gchar*) address;
-	priv->protocol = (gchar*) protocol;
+	priv->protocol = (gchar*) xmlGetProp (root_node, (xmlChar*) "protocol");
 	priv->relation_type = (gchar*) rel;
 	priv->label = (gchar*) xmlGetProp (root_node, (xmlChar*) "label");
 	priv->is_primary = primary_bool;
diff --git a/gdata/gd/gdata-gd-name.c b/gdata/gd/gdata-gd-name.c
index 9079f35..4facd1d 100644
--- a/gdata/gd/gdata-gd-name.c
+++ b/gdata/gd/gdata-gd-name.c
@@ -274,29 +274,19 @@ gdata_gd_name_set_property (GObject *object, guint property_id, const GValue *va
 	}
 }
 
-#define PARSE_STRING_ELEMENT(E,F)							\
-	if (xmlStrcmp (node->name, (xmlChar*) (E)) == 0) {				\
-		/* gd:##E */								\
-		if (priv->F != NULL)							\
-			return gdata_parser_error_duplicate_element (node, error);	\
-		priv->F = (gchar*) xmlNodeListGetString (doc, node->children, TRUE);	\
-	}
-
 static gboolean
 parse_xml (GDataParsable *parsable, xmlDoc *doc, xmlNode *node, gpointer user_data, GError **error)
 {
+	gboolean success;
 	GDataGDNamePrivate *priv = GDATA_GD_NAME (parsable)->priv;
 
-	PARSE_STRING_ELEMENT ("givenName", given_name)
-	else PARSE_STRING_ELEMENT ("additionalName", additional_name)
-	else PARSE_STRING_ELEMENT ("familyName", family_name)
-	else PARSE_STRING_ELEMENT ("namePrefix", prefix)
-	else PARSE_STRING_ELEMENT ("nameSuffix", suffix)
-	else if (xmlStrcmp (node->name, (xmlChar*) "fullName") == 0) {
-		/* gd:fullName */
-		if (priv->full_name != NULL)
-			return gdata_parser_error_duplicate_element (node, error);
-		priv->full_name = (gchar*) xmlNodeListGetString (doc, node->children, TRUE);
+	if (gdata_parser_string_from_element (node, "givenName", P_NO_DUPES, &(priv->given_name), &success, error) == TRUE ||
+	    gdata_parser_string_from_element (node, "additionalName", P_NO_DUPES, &(priv->additional_name), &success, error) == TRUE ||
+	    gdata_parser_string_from_element (node, "familyName", P_NO_DUPES, &(priv->family_name), &success, error) == TRUE ||
+	    gdata_parser_string_from_element (node, "namePrefix", P_NO_DUPES, &(priv->prefix), &success, error) == TRUE ||
+	    gdata_parser_string_from_element (node, "nameSuffix", P_NO_DUPES, &(priv->suffix), &success, error) == TRUE ||
+	    gdata_parser_string_from_element (node, "fullName", P_NO_DUPES, &(priv->full_name), &success, error) == TRUE) {
+		return success;
 	} else if (GDATA_PARSABLE_CLASS (gdata_gd_name_parent_class)->parse_xml (parsable, doc, node, user_data, error) == FALSE) {
 		/* Error! */
 		return FALSE;
@@ -305,21 +295,23 @@ parse_xml (GDataParsable *parsable, xmlDoc *doc, xmlNode *node, gpointer user_da
 	return TRUE;
 }
 
-#define OUTPUT_STRING_ELEMENT(E,F)									\
-	if (priv->F != NULL)										\
-		gdata_parser_string_append_escaped (xml_string, "<gd:" E ">", priv->F, "</gd:" E ">");
-
 static void
 get_xml (GDataParsable *parsable, GString *xml_string)
 {
 	GDataGDNamePrivate *priv = GDATA_GD_NAME (parsable)->priv;
 
+#define OUTPUT_STRING_ELEMENT(E,F)									\
+	if (priv->F != NULL)										\
+		gdata_parser_string_append_escaped (xml_string, "<gd:" E ">", priv->F, "</gd:" E ">");
+
 	OUTPUT_STRING_ELEMENT ("givenName", given_name)
 	OUTPUT_STRING_ELEMENT ("additionalName", additional_name)
 	OUTPUT_STRING_ELEMENT ("familyName", family_name)
 	OUTPUT_STRING_ELEMENT ("namePrefix", prefix)
 	OUTPUT_STRING_ELEMENT ("nameSuffix", suffix)
 	OUTPUT_STRING_ELEMENT ("fullName", full_name)
+
+#undef OUTPUT_STRING_ELEMENT
 }
 
 static void
diff --git a/gdata/gd/gdata-gd-organization.c b/gdata/gd/gdata-gd-organization.c
index 209b830..ebb024f 100644
--- a/gdata/gd/gdata-gd-organization.c
+++ b/gdata/gd/gdata-gd-organization.c
@@ -384,33 +384,15 @@ 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;
 	GDataGDOrganizationPrivate *priv = GDATA_GD_ORGANIZATION (parsable)->priv;
 
-	if (xmlStrcmp (node->name, (xmlChar*) "orgName") == 0) {
-		/* gd:orgName */
-		if (priv->name != NULL)
-			return gdata_parser_error_duplicate_element (node, error);
-		priv->name = (gchar*) xmlNodeListGetString (doc, node->children, TRUE);
-	} else if (xmlStrcmp (node->name, (xmlChar*) "orgTitle") == 0) {
-		/* gd:orgTitle */
-		if (priv->title != NULL)
-			return gdata_parser_error_duplicate_element (node, error);
-		priv->title = (gchar*) xmlNodeListGetString (doc, node->children, TRUE);
-	} else if (xmlStrcmp (node->name, (xmlChar*) "orgDepartment") == 0) {
-		/* gd:orgDepartment */
-		if (priv->department != NULL)
-			return gdata_parser_error_duplicate_element (node, error);
-		priv->department = (gchar*) xmlNodeListGetString (doc, node->children, TRUE);
-	} else if (xmlStrcmp (node->name, (xmlChar*) "orgJobDescription") == 0) {
-		/* gd:orgJobDescription */
-		if (priv->job_description != NULL)
-			return gdata_parser_error_duplicate_element (node, error);
-		priv->job_description = (gchar*) xmlNodeListGetString (doc, node->children, TRUE);
-	} else if (xmlStrcmp (node->name, (xmlChar*) "orgSymbol") == 0) {
-		/* gd:orgSymbol */
-		if (priv->symbol != NULL)
-			return gdata_parser_error_duplicate_element (node, error);
-		priv->symbol = (gchar*) xmlNodeListGetString (doc, node->children, TRUE);
+	if (gdata_parser_string_from_element (node, "orgName", P_NO_DUPES, &(priv->name), &success, error) == TRUE ||
+	    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) {
+		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));
diff --git a/gdata/gd/gdata-gd-postal-address.c b/gdata/gd/gdata-gd-postal-address.c
index 4f70da7..bb524ea 100644
--- a/gdata/gd/gdata-gd-postal-address.c
+++ b/gdata/gd/gdata-gd-postal-address.c
@@ -568,31 +568,25 @@ pre_parse_xml (GDataParsable *parsable, xmlDoc *doc, xmlNode *root_node, gpointe
 	return TRUE;
 }
 
-#define PARSE_STRING_ELEMENT(E,F)							\
-	if (xmlStrcmp (node->name, (xmlChar*) (E)) == 0) {				\
-		/* gd:##E */								\
-		if (priv->F != NULL)							\
-			return gdata_parser_error_duplicate_element (node, error);	\
-		priv->F = (gchar*) xmlNodeListGetString (doc, node->children, TRUE);	\
-	}
-
 static gboolean
 parse_xml (GDataParsable *parsable, xmlDoc *doc, xmlNode *node, gpointer user_data, GError **error)
 {
+	gboolean success;
 	GDataGDPostalAddressPrivate *priv = GDATA_GD_POSTAL_ADDRESS (parsable)->priv;
 
-	PARSE_STRING_ELEMENT ("agent", agent)
-	else PARSE_STRING_ELEMENT ("housename", house_name)
-	else PARSE_STRING_ELEMENT ("pobox", po_box)
-	else PARSE_STRING_ELEMENT ("street", street)
-	else PARSE_STRING_ELEMENT ("neighborhood", neighborhood)
-	else PARSE_STRING_ELEMENT ("city", city)
-	else PARSE_STRING_ELEMENT ("subregion", subregion)
-	else PARSE_STRING_ELEMENT ("region", region)
-	else PARSE_STRING_ELEMENT ("postcode", postcode)
-	else PARSE_STRING_ELEMENT ("country", country)
-	else PARSE_STRING_ELEMENT ("formattedAddress", formatted_address)
-	else if (GDATA_PARSABLE_CLASS (gdata_gd_postal_address_parent_class)->parse_xml (parsable, doc, node, user_data, error) == FALSE) {
+	if (gdata_parser_string_from_element (node, "agent", P_NO_DUPES, &(priv->agent), &success, error) == TRUE ||
+	    gdata_parser_string_from_element (node, "housename", P_NO_DUPES, &(priv->house_name), &success, error) == TRUE ||
+	    gdata_parser_string_from_element (node, "pobox", P_NO_DUPES, &(priv->po_box), &success, error) == TRUE ||
+	    gdata_parser_string_from_element (node, "street", P_NO_DUPES, &(priv->street), &success, error) == TRUE ||
+	    gdata_parser_string_from_element (node, "neighborhood", P_NO_DUPES, &(priv->neighborhood), &success, error) == TRUE ||
+	    gdata_parser_string_from_element (node, "city", P_NO_DUPES, &(priv->city), &success, error) == TRUE ||
+	    gdata_parser_string_from_element (node, "subregion", P_NO_DUPES, &(priv->subregion), &success, error) == TRUE ||
+	    gdata_parser_string_from_element (node, "region", P_NO_DUPES, &(priv->region), &success, error) == TRUE ||
+	    gdata_parser_string_from_element (node, "postcode", P_NO_DUPES, &(priv->postcode), &success, error) == TRUE ||
+	    gdata_parser_string_from_element (node, "country", P_NO_DUPES, &(priv->country), &success, error) == TRUE ||
+	    gdata_parser_string_from_element (node, "formattedAddress", P_NO_DUPES, &(priv->formatted_address), &success, error) == TRUE) {
+		return success;
+	} else if (GDATA_PARSABLE_CLASS (gdata_gd_postal_address_parent_class)->parse_xml (parsable, doc, node, user_data, error) == FALSE) {
 		/* Error! */
 		return FALSE;
 	}
@@ -620,15 +614,15 @@ pre_get_xml (GDataParsable *parsable, GString *xml_string)
 		g_string_append (xml_string, " primary='false'");
 }
 
-#define OUTPUT_STRING_ELEMENT(E,F)									\
-	if (priv->F != NULL)										\
-		gdata_parser_string_append_escaped (xml_string, "<gd:" E ">", priv->F, "</gd:" E ">");
-
 static void
 get_xml (GDataParsable *parsable, GString *xml_string)
 {
 	GDataGDPostalAddressPrivate *priv = GDATA_GD_POSTAL_ADDRESS (parsable)->priv;
 
+#define OUTPUT_STRING_ELEMENT(E,F)									\
+	if (priv->F != NULL)										\
+		gdata_parser_string_append_escaped (xml_string, "<gd:" E ">", priv->F, "</gd:" E ">");
+
 	OUTPUT_STRING_ELEMENT ("agent", agent)
 	OUTPUT_STRING_ELEMENT ("housename", house_name)
 	OUTPUT_STRING_ELEMENT ("street", street)
@@ -640,6 +634,8 @@ get_xml (GDataParsable *parsable, GString *xml_string)
 	OUTPUT_STRING_ELEMENT ("postcode", postcode)
 	OUTPUT_STRING_ELEMENT ("country", country)
 	OUTPUT_STRING_ELEMENT ("formattedAddress", formatted_address)
+
+#undef OUTPUT_STRING_ELEMENT
 }
 
 static void
diff --git a/gdata/gdata-feed.c b/gdata/gdata-feed.c
index 2cbae6f..a071cee 100644
--- a/gdata/gdata-feed.c
+++ b/gdata/gdata-feed.c
@@ -398,6 +398,7 @@ typedef struct {
 static gboolean
 parse_xml (GDataParsable *parsable, xmlDoc *doc, xmlNode *node, gpointer user_data, GError **error)
 {
+	gboolean success;
 	GDataFeed *self;
 	ParseData *data = user_data;
 
@@ -423,25 +424,13 @@ parse_xml (GDataParsable *parsable, xmlDoc *doc, xmlNode *node, gpointer user_da
 		if (data != NULL)
 			_gdata_feed_call_progress_callback (self, data, entry);
 		_gdata_feed_add_entry (self, entry);
-	} else if (xmlStrcmp (node->name, (xmlChar*) "title") == 0) {
-		/* atom:title */
-		if (self->priv->title != NULL)
-			return gdata_parser_error_duplicate_element (node, error);
-
-		self->priv->title = (gchar*) xmlNodeListGetString (doc, node->children, TRUE);
-	} else if (xmlStrcmp (node->name, (xmlChar*) "subtitle") == 0) {
-		/* atom:subtitle */
-		if (self->priv->subtitle != NULL)
-			return gdata_parser_error_duplicate_element (node, error);
-
-		self->priv->subtitle = (gchar*) xmlNodeListGetString (doc, node->children, TRUE);
-	} else if (xmlStrcmp (node->name, (xmlChar*) "id") == 0 && xmlStrcmp (node->ns->href, (xmlChar*) "http://www.w3.org/2005/Atom";) == 0) {
-		/* atom:id */
-		/* The namespace check is necessary because there's an "id" element in the gphoto namespace (PicasaWeb service) */
-		if (self->priv->id != NULL)
-			return gdata_parser_error_duplicate_element (node, error);
-
-		self->priv->id = (gchar*) xmlNodeListGetString (doc, node->children, TRUE);
+	} else if (gdata_parser_string_from_element (node, "title", P_NO_DUPES, &(self->priv->title), &success, error) == TRUE ||
+	           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) {
+		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) {
 		/* atom:updated */
 		xmlChar *updated_string;
@@ -465,18 +454,6 @@ parse_xml (GDataParsable *parsable, xmlDoc *doc, xmlNode *node, gpointer user_da
 			return FALSE;
 
 		self->priv->categories = g_list_prepend (self->priv->categories, category);
-	} else if (xmlStrcmp (node->name, (xmlChar*) "logo") == 0) {
-		/* atom:logo */
-		if (self->priv->logo != NULL)
-			return gdata_parser_error_duplicate_element (node, error);
-
-		self->priv->logo = (gchar*) xmlNodeListGetString (doc, node->children, TRUE);
-	} else if (xmlStrcmp (node->name, (xmlChar*) "icon") == 0) {
-		/* atom:icon */
-		if (self->priv->icon != NULL)
-			return gdata_parser_error_duplicate_element (node, error);
-
-		self->priv->icon = (gchar*) xmlNodeListGetString (doc, node->children, TRUE);
 	} 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));
diff --git a/gdata/gdata-parser.c b/gdata/gdata-parser.c
index 92d4a5b..6536285 100644
--- a/gdata/gdata-parser.c
+++ b/gdata/gdata-parser.c
@@ -221,6 +221,8 @@ gdata_parser_date_from_time_val (const GTimeVal *_time)
  * returned in @error.
  *
  * Return value: %TRUE on successful parsing, %FALSE otherwise
+ *
+ * Since: 0.7.0
  */
 gboolean
 gdata_parser_boolean_from_property (xmlNode *element, const gchar *property_name, gboolean *output, gint default_output, GError **error)
@@ -247,6 +249,67 @@ gdata_parser_boolean_from_property (xmlNode *element, const gchar *property_name
 	return TRUE;
 }
 
+/*
+ * 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
+ * @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_element (xmlNode *element, const gchar *element_name, GDataParserStringOptions options,
+                                  gchar **output, gboolean *success, GError **error)
+{
+	xmlChar *text;
+
+	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);
+		}
+	}
+
+	/* Get the string and check it for NULLness or emptiness */
+	text = xmlNodeListGetString (element->doc, element->children, TRUE);
+	if ((options & P_REQUIRED && text == NULL) || (options & P_NON_EMPTY && text != NULL && *text == '\0')) {
+		xmlFree (text);
+		*success = gdata_parser_error_required_content_missing (element, error);
+		return TRUE;
+	}
+
+	*output = (gchar*) text;
+	*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 7a445d5..4147e23 100644
--- a/gdata/gdata-parser.h
+++ b/gdata/gdata-parser.h
@@ -35,7 +35,28 @@ gboolean gdata_parser_error_duplicate_element (xmlNode *element, GError **error)
 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:
+ * @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
+ *
+ * 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.
+ *
+ * Since: 0.7.0
+ */
+typedef enum {
+	P_NONE = 0,
+	P_NO_DUPES = 1 << 0,
+	P_REQUIRED = 1 << 1,
+	P_NON_EMPTY = 1 << 2
+} GDataParserStringOptions;
+
 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,
+                                           gchar **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/media/gdata-media-content.c b/gdata/media/gdata-media-content.c
index abb0f4f..0842b5b 100644
--- a/gdata/media/gdata-media-content.c
+++ b/gdata/media/gdata-media-content.c
@@ -289,7 +289,7 @@ static gboolean
 pre_parse_xml (GDataParsable *parsable, xmlDoc *doc, xmlNode *root_node, gpointer user_data, GError **error)
 {
 	GDataMediaContentPrivate *priv = GDATA_MEDIA_CONTENT (parsable)->priv;
-	xmlChar *uri, *is_default, *expression, *medium, *duration, *filesize, *height, *width;
+	xmlChar *uri, *expression, *medium, *duration, *filesize, *height, *width;
 	gboolean is_default_bool;
 	GDataMediaExpression expression_enum;
 	GDataMediaMedium medium_enum;
diff --git a/gdata/media/gdata-media-group.c b/gdata/media/gdata-media-group.c
index e0753ea..346c996 100644
--- a/gdata/media/gdata-media-group.c
+++ b/gdata/media/gdata-media-group.c
@@ -138,17 +138,13 @@ gdata_media_group_finalize (GObject *object)
 static gboolean
 parse_xml (GDataParsable *parsable, xmlDoc *doc, xmlNode *node, gpointer user_data, GError **error)
 {
+	gboolean success;
 	GDataMediaGroup *self = GDATA_MEDIA_GROUP (parsable);
 
-	if (xmlStrcmp (node->name, (xmlChar*) "title") == 0) {
-		/* media:title */
-		self->priv->title = (gchar*) xmlNodeListGetString (doc, node->children, TRUE);
-	} else if (xmlStrcmp (node->name, (xmlChar*) "description") == 0) {
-		/* media:description */
-		self->priv->description = (gchar*) xmlNodeListGetString (doc, node->children, TRUE);
-	} else if (xmlStrcmp (node->name, (xmlChar*) "keywords") == 0) {
-		/* media:keywords */
-		self->priv->keywords = (gchar*) xmlNodeListGetString (doc, node->children, TRUE);
+	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) {
+		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,
diff --git a/gdata/services/picasaweb/gdata-picasaweb-album.c b/gdata/services/picasaweb/gdata-picasaweb-album.c
index e745f43..9b705fb 100644
--- a/gdata/services/picasaweb/gdata-picasaweb-album.c
+++ b/gdata/services/picasaweb/gdata-picasaweb-album.c
@@ -547,6 +547,7 @@ gdata_picasaweb_album_set_property (GObject *object, guint property_id, const GV
 static gboolean
 parse_xml (GDataParsable *parsable, xmlDoc *doc, xmlNode *node, gpointer user_data, GError **error)
 {
+	gboolean success;
 	GDataPicasaWebAlbum *self = GDATA_PICASAWEB_ALBUM (parsable);
 
 	if (xmlStrcmp (node->name, (xmlChar*) "group") == 0) {
@@ -571,20 +572,10 @@ parse_xml (GDataParsable *parsable, xmlDoc *doc, xmlNode *node, gpointer user_da
 			g_object_unref (self->priv->georss_where);
 
 		self->priv->georss_where = where;
-	} else if (xmlStrcmp (node->name, (xmlChar*) "user") == 0) {
-		/* gphoto:user */
-		xmlChar *user = xmlNodeListGetString (doc, node->children, TRUE);
-		if (user == NULL || *user == '\0')
-			return gdata_parser_error_required_content_missing (node, error);
-		g_free (self->priv->user);
-		self->priv->user = (gchar*) user;
-	} else if (xmlStrcmp (node->name, (xmlChar*) "nickname") == 0) {
-		/* gphoto:nickname */
-		xmlChar *nickname = xmlNodeListGetString (doc, node->children, TRUE);
-		if (nickname == NULL || *nickname == '\0')
-			return gdata_parser_error_required_content_missing (node, error);
-		g_free (self->priv->nickname);
-		self->priv->nickname = (gchar*) nickname;
+	} 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) {
+		return success;
 	} else if (xmlStrcmp (node->name, (xmlChar*) "edited") == 0) {
 		/* app:edited */
 		xmlChar *edited = xmlNodeListGetString (doc, node->children, TRUE);
@@ -595,10 +586,6 @@ parse_xml (GDataParsable *parsable, xmlDoc *doc, xmlNode *node, gpointer user_da
 			return FALSE;
 		}
 		xmlFree (edited);
-	} else if (xmlStrcmp (node->name, (xmlChar*) "location") == 0) {
-		/* gphoto:location */
-		g_free (self->priv->location);
-		self->priv->location = (gchar*) xmlNodeListGetString (doc, node->children, TRUE);
 	} else if (xmlStrcmp (node->name, (xmlChar*) "access") == 0) {
 		/* gphoto:access */
 		xmlChar *access = xmlNodeListGetString (doc, node->children, TRUE);
diff --git a/gdata/services/picasaweb/gdata-picasaweb-file.c b/gdata/services/picasaweb/gdata-picasaweb-file.c
index 81323ab..c4466ed 100644
--- a/gdata/services/picasaweb/gdata-picasaweb-file.c
+++ b/gdata/services/picasaweb/gdata-picasaweb-file.c
@@ -793,6 +793,7 @@ gdata_picasaweb_file_set_property (GObject *object, guint property_id, const GVa
 static gboolean
 parse_xml (GDataParsable *parsable, xmlDoc *doc, xmlNode *node, gpointer user_data, GError **error)
 {
+	gboolean success;
 	GDataPicasaWebFile *self = GDATA_PICASAWEB_FILE (parsable);
 
 	if (xmlStrcmp (node->name, (xmlChar*) "group") == 0) {
@@ -837,18 +838,11 @@ parse_xml (GDataParsable *parsable, xmlDoc *doc, xmlNode *node, gpointer user_da
 			return FALSE;
 		}
 		xmlFree (edited);
-	} else if (xmlStrcmp (node->name, (xmlChar*) "imageVersion") == 0) {
-		/* gphoto:imageVersion */
-		g_free (self->priv->version);
-		self->priv->version = (gchar*) xmlNodeListGetString (doc, node->children, TRUE);
 	} else if (xmlStrcmp (node->name, (xmlChar*) "position") == 0) {
 		/* gphoto:position */
 		xmlChar *position_str = xmlNodeListGetString (doc, node->children, TRUE);
 		gdata_picasaweb_file_set_position (self, g_ascii_strtod ((gchar*) position_str, NULL));
 		xmlFree (position_str);
-	} else if (xmlStrcmp (node->name, (xmlChar*) "albumid") == 0) {
-		/* gphoto:album_id */
-		self->priv->album_id = (gchar*) xmlNodeListGetString (doc, node->children, TRUE);
 	} else if (xmlStrcmp (node->name, (xmlChar*) "width") == 0) {
 		/* gphoto:width */
 		xmlChar *width = xmlNodeListGetString (doc, node->children, TRUE);
@@ -864,12 +858,6 @@ parse_xml (GDataParsable *parsable, xmlDoc *doc, xmlNode *node, gpointer user_da
 		xmlChar *size = xmlNodeListGetString (doc, node->children, TRUE);
 		self->priv->size = strtoul ((gchar*) size, NULL, 10);
 		xmlFree (size);
-	} else if (xmlStrcmp (node->name, (xmlChar*) "client") == 0) {
-		/* gphoto:client */
-		self->priv->client = (gchar*) xmlNodeListGetString (doc, node->children, TRUE);
-	} else if (xmlStrcmp (node->name, (xmlChar*) "checksum") == 0) {
-		/* gphoto:checksum */
-		self->priv->checksum = (gchar*) xmlNodeListGetString (doc, node->children, TRUE);
 	} else if (xmlStrcmp (node->name, (xmlChar*) "timestamp") == 0) {
 		/* gphoto:timestamp */
 		xmlChar *timestamp_str;
@@ -896,14 +884,12 @@ 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 (xmlStrcmp (node->name, (xmlChar*) "videostatus") == 0) {
-		/* gphoto:videostatus */
-		xmlChar *video_status = xmlNodeListGetString (doc, node->children, TRUE);
-		if (self->priv->video_status != NULL) {
-			xmlFree (video_status);
-			return gdata_parser_error_duplicate_element (node, error);
-		}
-		self->priv->video_status = (gchar*) video_status;
+	} 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/picasaweb/gdata-picasaweb-user.c b/gdata/services/picasaweb/gdata-picasaweb-user.c
index 7d61000..2863bc8 100644
--- a/gdata/services/picasaweb/gdata-picasaweb-user.c
+++ b/gdata/services/picasaweb/gdata-picasaweb-user.c
@@ -218,28 +218,13 @@ gdata_picasaweb_user_get_property (GObject *object, guint property_id, GValue *v
 static gboolean
 parse_xml (GDataParsable *parsable, xmlDoc *doc, xmlNode *node, gpointer user_data, GError **error)
 {
+	gboolean success;
 	GDataPicasaWebUser *self = GDATA_PICASAWEB_USER (parsable);
 
-	if (xmlStrcmp (node->name, (xmlChar*) "user") == 0) {
-		/* gphoto:user */
-		xmlChar *user = xmlNodeListGetString (doc, node->children, TRUE);
-		if (user == NULL || *user == '\0') {
-			g_free (user);
-			return gdata_parser_error_required_content_missing (node, error);
-		}
-
-		g_free (self->priv->user);
-		self->priv->user = (gchar*) user;
-	} else if (xmlStrcmp (node->name, (xmlChar*) "nickname") == 0) {
-		/* gphoto:nickname */
-		xmlChar *nickname = xmlNodeListGetString (doc, node->children, TRUE);
-		if (nickname == NULL || *nickname == '\0') {
-			g_free (nickname);
-			return gdata_parser_error_required_content_missing (node, error);
-		}
-
-		g_free (self->priv->nickname);
-		self->priv->nickname = (gchar*) nickname;
+	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, "thumbnail", P_REQUIRED | P_NON_EMPTY, &(self->priv->thumbnail_uri), &success, error) == TRUE) {
+		return success;
 	} else if (xmlStrcmp (node->name, (xmlChar*) "quotacurrent") == 0) {
 		/* gphoto:quota-current */
 		xmlChar *quota_current = xmlNodeListGetString (doc, node->children, TRUE);
@@ -255,22 +240,12 @@ parse_xml (GDataParsable *parsable, xmlDoc *doc, xmlNode *node, gpointer user_da
 		xmlChar *max_photos_per_album = xmlNodeListGetString (doc, node->children, TRUE);
 		self->priv->max_photos_per_album = strtol ((char*) max_photos_per_album, NULL, 10);
 		xmlFree (max_photos_per_album);
-	} else if (xmlStrcmp (node->name, (xmlChar*) "thumbnail") == 0) {
-		/* gphoto:thumbnail */
-		xmlChar *thumbnail = xmlNodeListGetString (doc, node->children, TRUE);
-		if (thumbnail == NULL || *thumbnail == '\0') {
-			g_free (thumbnail);
-			return gdata_parser_error_required_content_missing (node, error);
-		}
-
-		g_free (self->priv->thumbnail_uri);
-		self->priv->thumbnail_uri = (gchar*) thumbnail;
 	} else if (xmlStrcmp (node->name, (xmlChar*) "x-allowDownloads") == 0) { /* RHSTODO: see if this comes with the user */
 		/* gphoto:allowDownloads */
-		/* Not part of public API so we're capturing and ignoring for now.  See bgo #589858. */
+		/* TODO: Not part of public API so we're capturing and ignoring for now.  See bgo #589858. */
 	} else if (xmlStrcmp (node->name, (xmlChar*) "x-allowPrints") == 0) { /* RHSTODO: see if this comes with the user */
 		/* gphoto:allowPrints */
-		/* Not part of public API so we're capturing and ignoring for now.  See bgo #589858. */
+		/* TODO: Not part of public API so we're capturing and ignoring for now.  See bgo #589858. */
 	} else if (GDATA_PARSABLE_CLASS (gdata_picasaweb_user_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 adeae5f..4792b96 100644
--- a/gdata/services/youtube/gdata-youtube-group.c
+++ b/gdata/services/youtube/gdata-youtube-group.c
@@ -90,6 +90,7 @@ gdata_youtube_group_finalize (GObject *object)
 static gboolean
 parse_xml (GDataParsable *parsable, xmlDoc *doc, xmlNode *node, gpointer user_data, GError **error)
 {
+	gboolean success;
 	GDataYouTubeGroup *self = GDATA_YOUTUBE_GROUP (parsable);
 
 	if (xmlStrcmp (node->name, (xmlChar*) "content") == 0) {
@@ -139,14 +140,9 @@ parse_xml (GDataParsable *parsable, xmlDoc *doc, xmlNode *node, gpointer user_da
 		xmlFree (uploaded);
 
 		self->priv->uploaded = uploaded_timeval;
-	} else if (xmlStrcmp (node->name, (xmlChar*) "videoid") == 0) {
+	} else if (gdata_parser_string_from_element (node, "videoid", P_NO_DUPES, &(self->priv->video_id), &success, error) == TRUE) {
 		/* yt:videoid */
-		xmlChar *video_id = xmlNodeListGetString (doc, node->children, TRUE);
-		if (self->priv->video_id != NULL) {
-			xmlFree (video_id);
-			return gdata_parser_error_duplicate_element (node, error);
-		}
-		self->priv->video_id = (gchar*) video_id;
+		return success;
 	} else if (xmlStrcmp (node->name, (xmlChar*) "aspectRatio") == 0) {
 		/* yt:aspectRatio */
 		xmlChar *aspect_ratio = xmlNodeGetContent (node);



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