[libgdata] [core] Link element names and namespaces to the relevant classes



commit 920c0249bd241320abcd15cf3379b66d6c83e2f5
Author: Philip Withnall <philip tecnocode co uk>
Date:   Sun Jun 28 22:23:55 2009 +0100

    [core] Link element names and namespaces to the relevant classes
    
    This introduces new element_name and element_namespaces fields to the
    GDataParsableClass struct, allowing for simpler parsing of XML by linking
    XML element names to parsable object types. Some of the GDataParsable API
    is now public, which will allow for a more comprehensive test suite in future.

 docs/reference/gdata-sections.txt                  |   11 +--
 gdata/atom/gdata-author.c                          |    1 +
 gdata/atom/gdata-category.c                        |    1 +
 gdata/atom/gdata-generator.c                       |    1 +
 gdata/atom/gdata-link.c                            |    1 +
 gdata/gd/gdata-gd-email-address.c                  |    2 +
 gdata/gd/gdata-gd-im-address.c                     |    2 +
 gdata/gd/gdata-gd-organization.c                   |    2 +
 gdata/gd/gdata-gd-phone-number.c                   |    2 +
 gdata/gd/gdata-gd-postal-address.c                 |    2 +
 gdata/gd/gdata-gd-reminder.c                       |    2 +
 gdata/gd/gdata-gd-when.c                           |   12 ++-
 gdata/gd/gdata-gd-where.c                          |    2 +
 gdata/gd/gdata-gd-who.c                            |    2 +
 gdata/gdata-access-handler.c                       |   12 ++--
 gdata/gdata-access-rule.c                          |   21 -----
 gdata/gdata-access-rule.h                          |    1 -
 gdata/gdata-entry.c                                |   73 ++++-----------
 gdata/gdata-entry.h                                |    2 -
 gdata/gdata-feed.c                                 |   13 ++--
 gdata/gdata-parsable.c                             |   93 ++++++++++++++++----
 gdata/gdata-parsable.h                             |   12 ++-
 gdata/gdata-private.h                              |    9 +--
 gdata/gdata-service.c                              |   10 ++-
 gdata/gdata.symbols                                |   11 +--
 gdata/media/gdata-media-category.c                 |    2 +
 gdata/media/gdata-media-content.c                  |    2 +
 gdata/media/gdata-media-credit.c                   |    2 +
 gdata/media/gdata-media-group.c                    |   14 ++--
 gdata/media/gdata-media-thumbnail.c                |    2 +
 gdata/services/calendar/gdata-calendar-calendar.c  |   19 ----
 gdata/services/calendar/gdata-calendar-calendar.h  |    1 -
 gdata/services/calendar/gdata-calendar-event.c     |   49 ++++-------
 gdata/services/calendar/gdata-calendar-event.h     |    1 -
 gdata/services/contacts/gdata-contacts-contact.c   |   69 +++++----------
 gdata/services/contacts/gdata-contacts-contact.h   |    1 -
 gdata/services/picasaweb/gdata-picasaweb-album.c   |   26 +-----
 gdata/services/picasaweb/gdata-picasaweb-album.h   |    1 -
 gdata/services/picasaweb/gdata-picasaweb-file.c    |   26 +-----
 gdata/services/picasaweb/gdata-picasaweb-file.h    |    1 -
 gdata/services/picasaweb/gdata-picasaweb-service.c |    5 +-
 gdata/services/youtube/gdata-youtube-control.c     |    5 +-
 gdata/services/youtube/gdata-youtube-group.c       |    4 +-
 gdata/services/youtube/gdata-youtube-service.c     |    5 +-
 gdata/services/youtube/gdata-youtube-state.c       |    2 +
 gdata/services/youtube/gdata-youtube-video.c       |   33 ++-----
 gdata/services/youtube/gdata-youtube-video.h       |    1 -
 gdata/tests/calendar.c                             |   14 ++--
 gdata/tests/contacts.c                             |   14 ++--
 gdata/tests/general.c                              |   10 +-
 gdata/tests/picasaweb.c                            |    8 +-
 gdata/tests/youtube.c                              |   18 ++--
 52 files changed, 272 insertions(+), 363 deletions(-)
---
diff --git a/docs/reference/gdata-sections.txt b/docs/reference/gdata-sections.txt
index 8b22ce2..4acc178 100644
--- a/docs/reference/gdata-sections.txt
+++ b/docs/reference/gdata-sections.txt
@@ -132,7 +132,6 @@ GDataFeedPrivate
 GDataEntry
 GDataEntryClass
 gdata_entry_new
-gdata_entry_new_from_xml
 gdata_entry_get_title
 gdata_entry_set_title
 gdata_entry_get_summary
@@ -149,7 +148,6 @@ gdata_entry_get_categories
 gdata_entry_add_link
 gdata_entry_look_up_link
 gdata_entry_is_inserted
-gdata_entry_get_xml
 <SUBSECTION Standard>
 gdata_entry_get_type
 GDATA_ENTRY
@@ -203,7 +201,6 @@ GDataYouTubeServicePrivate
 GDataYouTubeVideo
 GDataYouTubeVideoClass
 gdata_youtube_video_new
-gdata_youtube_video_new_from_xml
 gdata_youtube_video_look_up_content
 gdata_youtube_video_get_thumbnails
 gdata_youtube_video_get_category
@@ -300,7 +297,6 @@ GDataContactsQueryPrivate
 GDataContactsContact
 GDataContactsContactClass
 gdata_contacts_contact_new
-gdata_contacts_contact_new_from_xml
 gdata_contacts_contact_get_email_addresses
 gdata_contacts_contact_get_primary_email_address
 gdata_contacts_contact_add_email_address
@@ -407,7 +403,6 @@ GDataCalendarQueryPrivate
 GDataCalendarCalendar
 GDataCalendarCalendarClass
 gdata_calendar_calendar_new
-gdata_calendar_calendar_new_from_xml
 gdata_calendar_calendar_get_color
 gdata_calendar_calendar_set_color
 gdata_calendar_calendar_is_hidden
@@ -437,7 +432,6 @@ GDataCalendarCalendarPrivate
 GDataCalendarEvent
 GDataCalendarEventClass
 gdata_calendar_event_new
-gdata_calendar_event_new_from_xml
 gdata_calendar_event_get_people
 gdata_calendar_event_add_person
 gdata_calendar_event_get_places
@@ -568,7 +562,6 @@ GDATA_TYPE_ACCESS_HANDLER
 GDataAccessRule
 GDataAccessRuleClass
 gdata_access_rule_new
-gdata_access_rule_new_from_xml
 gdata_access_rule_get_role
 gdata_access_rule_set_role
 gdata_access_rule_get_scope
@@ -590,6 +583,8 @@ GDataAccessRulePrivate
 <TITLE>GDataParsable</TITLE>
 GDataParsable
 GDataParsableClass
+gdata_parsable_new_from_xml
+gdata_parsable_get_xml
 <SUBSECTION Standard>
 gdata_parsable_get_type
 GDATA_IS_PARSABLE
@@ -1175,7 +1170,6 @@ GDataPicasaWebAlbum
 GDataPicasaWebAlbumClass
 GDataPicasaWebVisibility
 gdata_picasaweb_album_new
-gdata_picasaweb_album_new_from_xml
 gdata_picasaweb_album_get_user
 gdata_picasaweb_album_get_nickname
 gdata_picasaweb_album_get_edited
@@ -1216,7 +1210,6 @@ GDataPicasaWebAlbumPrivate
 GDataPicasaWebFile
 GDataPicasaWebFileClass
 gdata_picasaweb_file_new
-gdata_picasaweb_file_new_from_xml
 gdata_picasaweb_file_get_edited
 gdata_picasaweb_file_get_version
 gdata_picasaweb_file_get_position
diff --git a/gdata/atom/gdata-author.c b/gdata/atom/gdata-author.c
index 722db0d..09b972c 100644
--- a/gdata/atom/gdata-author.c
+++ b/gdata/atom/gdata-author.c
@@ -71,6 +71,7 @@ gdata_author_class_init (GDataAuthorClass *klass)
 	parsable_class->parse_xml = parse_xml;
 	parsable_class->post_parse_xml = post_parse_xml;
 	parsable_class->get_xml = get_xml;
+	parsable_class->element_name = "author";
 
 	/**
 	 * GDataAuthor:name:
diff --git a/gdata/atom/gdata-category.c b/gdata/atom/gdata-category.c
index 13dd0c6..549b5f2 100644
--- a/gdata/atom/gdata-category.c
+++ b/gdata/atom/gdata-category.c
@@ -69,6 +69,7 @@ gdata_category_class_init (GDataCategoryClass *klass)
 
 	parsable_class->pre_parse_xml = pre_parse_xml;
 	parsable_class->pre_get_xml = pre_get_xml;
+	parsable_class->element_name = "category";
 
 	/**
 	 * GDataCategory:term:
diff --git a/gdata/atom/gdata-generator.c b/gdata/atom/gdata-generator.c
index ff0b7db..bc1df18 100644
--- a/gdata/atom/gdata-generator.c
+++ b/gdata/atom/gdata-generator.c
@@ -67,6 +67,7 @@ gdata_generator_class_init (GDataGeneratorClass *klass)
 
 	parsable_class->pre_parse_xml = pre_parse_xml;
 	parsable_class->parse_xml = parse_xml;
+	parsable_class->element_name = "generator";
 
 	/**
 	 * GDataGenerator:name:
diff --git a/gdata/atom/gdata-link.c b/gdata/atom/gdata-link.c
index 860e68b..61da25e 100644
--- a/gdata/atom/gdata-link.c
+++ b/gdata/atom/gdata-link.c
@@ -75,6 +75,7 @@ gdata_link_class_init (GDataLinkClass *klass)
 
 	parsable_class->pre_parse_xml = pre_parse_xml;
 	parsable_class->pre_get_xml = pre_get_xml;
+	parsable_class->element_name = "link";
 
 	/**
 	 * GDataLink:uri:
diff --git a/gdata/gd/gdata-gd-email-address.c b/gdata/gd/gdata-gd-email-address.c
index 0dd89cf..bcb7d2f 100644
--- a/gdata/gd/gdata-gd-email-address.c
+++ b/gdata/gd/gdata-gd-email-address.c
@@ -73,6 +73,8 @@ gdata_gd_email_address_class_init (GDataGDEmailAddressClass *klass)
 	parsable_class->pre_parse_xml = pre_parse_xml;
 	parsable_class->pre_get_xml = pre_get_xml;
 	parsable_class->get_namespaces = get_namespaces;
+	parsable_class->element_name = "email";
+	parsable_class->element_namespace = "gd";
 
 	/**
 	 * GDataGDEmailAddress:address:
diff --git a/gdata/gd/gdata-gd-im-address.c b/gdata/gd/gdata-gd-im-address.c
index da86c4b..9fbac6d 100644
--- a/gdata/gd/gdata-gd-im-address.c
+++ b/gdata/gd/gdata-gd-im-address.c
@@ -75,6 +75,8 @@ gdata_gd_im_address_class_init (GDataGDIMAddressClass *klass)
 	parsable_class->pre_parse_xml = pre_parse_xml;
 	parsable_class->pre_get_xml = pre_get_xml;
 	parsable_class->get_namespaces = get_namespaces;
+	parsable_class->element_name = "im";
+	parsable_class->element_namespace = "gd";
 
 	/**
 	 * GDataGDIMAddress:address:
diff --git a/gdata/gd/gdata-gd-organization.c b/gdata/gd/gdata-gd-organization.c
index 7bedc2c..1e59356 100644
--- a/gdata/gd/gdata-gd-organization.c
+++ b/gdata/gd/gdata-gd-organization.c
@@ -79,6 +79,8 @@ gdata_gd_organization_class_init (GDataGDOrganizationClass *klass)
 	parsable_class->pre_get_xml = pre_get_xml;
 	parsable_class->get_xml = get_xml;
 	parsable_class->get_namespaces = get_namespaces;
+	parsable_class->element_name = "organization";
+	parsable_class->element_namespace = "gd";
 
 	/**
 	 * GDataGDOrganization:name:
diff --git a/gdata/gd/gdata-gd-phone-number.c b/gdata/gd/gdata-gd-phone-number.c
index b7d5bbb..e1fdc8c 100644
--- a/gdata/gd/gdata-gd-phone-number.c
+++ b/gdata/gd/gdata-gd-phone-number.c
@@ -79,6 +79,8 @@ gdata_gd_phone_number_class_init (GDataGDPhoneNumberClass *klass)
 	parsable_class->pre_get_xml = pre_get_xml;
 	parsable_class->get_xml = get_xml;
 	parsable_class->get_namespaces = get_namespaces;
+	parsable_class->element_name = "phoneNumber";
+	parsable_class->element_namespace = "gd";
 
 	/**
 	 * GDataGDPhoneNumber:number:
diff --git a/gdata/gd/gdata-gd-postal-address.c b/gdata/gd/gdata-gd-postal-address.c
index c2240fd..cd08270 100644
--- a/gdata/gd/gdata-gd-postal-address.c
+++ b/gdata/gd/gdata-gd-postal-address.c
@@ -77,6 +77,8 @@ gdata_gd_postal_address_class_init (GDataGDPostalAddressClass *klass)
 	parsable_class->pre_get_xml = pre_get_xml;
 	parsable_class->get_xml = get_xml;
 	parsable_class->get_namespaces = get_namespaces;
+	parsable_class->element_name = "postalAddress";
+	parsable_class->element_namespace = "gd";
 
 	/**
 	 * GDataGDPostalAddress:address:
diff --git a/gdata/gd/gdata-gd-reminder.c b/gdata/gd/gdata-gd-reminder.c
index d9abd4c..394660c 100644
--- a/gdata/gd/gdata-gd-reminder.c
+++ b/gdata/gd/gdata-gd-reminder.c
@@ -73,6 +73,8 @@ gdata_gd_reminder_class_init (GDataGDReminderClass *klass)
 	parsable_class->pre_parse_xml = pre_parse_xml;
 	parsable_class->pre_get_xml = pre_get_xml;
 	parsable_class->get_namespaces = get_namespaces;
+	parsable_class->element_name = "reminder";
+	parsable_class->element_namespace = "gd";
 
 	/**
 	 * GDataGDReminder:method:
diff --git a/gdata/gd/gdata-gd-when.c b/gdata/gd/gdata-gd-when.c
index a24f30b..5d383f1 100644
--- a/gdata/gd/gdata-gd-when.c
+++ b/gdata/gd/gdata-gd-when.c
@@ -85,6 +85,8 @@ gdata_gd_when_class_init (GDataGDWhenClass *klass)
 	parsable_class->pre_get_xml = pre_get_xml;
 	parsable_class->get_xml = get_xml;
 	parsable_class->get_namespaces = get_namespaces;
+	parsable_class->element_name = "when";
+	parsable_class->element_namespace = "gd";
 
 	/**
 	 * GDataGDWhen:start-time:
@@ -295,8 +297,7 @@ parse_xml (GDataParsable *parsable, xmlDoc *doc, xmlNode *node, gpointer user_da
 
 	if (xmlStrcmp (node->name, (xmlChar*) "reminder") == 0) {
 		/* gd:reminder */
-		GDataGDReminder *reminder = GDATA_GD_REMINDER (_gdata_parsable_new_from_xml_node (GDATA_TYPE_GD_REMINDER, "reminder", doc, node,
-												  NULL, error));
+		GDataGDReminder *reminder = GDATA_GD_REMINDER (_gdata_parsable_new_from_xml_node (GDATA_TYPE_GD_REMINDER, doc, node, NULL, error));
 		if (reminder == NULL)
 			return FALSE;
 
@@ -356,8 +357,11 @@ get_xml (GDataParsable *parsable, GString *xml_string)
 	GList *reminders;
 	GDataGDWhenPrivate *priv = GDATA_GD_WHEN (parsable)->priv;
 
-	for (reminders = priv->reminders; reminders != NULL; reminders = reminders->next)
-		g_string_append (xml_string, _gdata_parsable_get_xml (GDATA_PARSABLE (reminders->data), "gd:reminder", FALSE));
+	for (reminders = priv->reminders; reminders != NULL; reminders = reminders->next) {
+		gchar *xml = _gdata_parsable_get_xml (GDATA_PARSABLE (reminders->data), FALSE);
+		g_string_append (xml_string, xml);
+		g_free (xml);
+	}
 }
 
 static void
diff --git a/gdata/gd/gdata-gd-where.c b/gdata/gd/gdata-gd-where.c
index ff01d46..60f6ea3 100644
--- a/gdata/gd/gdata-gd-where.c
+++ b/gdata/gd/gdata-gd-where.c
@@ -75,6 +75,8 @@ gdata_gd_where_class_init (GDataGDWhereClass *klass)
 	parsable_class->pre_get_xml = pre_get_xml;
 	parsable_class->get_xml = get_xml;
 	parsable_class->get_namespaces = get_namespaces;
+	parsable_class->element_name = "where";
+	parsable_class->element_namespace = "gd";
 
 	/**
 	 * GDataGDWhere:relation-type:
diff --git a/gdata/gd/gdata-gd-who.c b/gdata/gd/gdata-gd-who.c
index 6226e27..1b78dcf 100644
--- a/gdata/gd/gdata-gd-who.c
+++ b/gdata/gd/gdata-gd-who.c
@@ -75,6 +75,8 @@ gdata_gd_who_class_init (GDataGDWhoClass *klass)
 	parsable_class->pre_get_xml = pre_get_xml;
 	parsable_class->get_xml = get_xml;
 	parsable_class->get_namespaces = get_namespaces;
+	parsable_class->element_name = "who";
+	parsable_class->element_namespace = "gd";
 
 	/**
 	 * GDataGDWho:relation-type:
diff --git a/gdata/gdata-access-handler.c b/gdata/gdata-access-handler.c
index 49f8421..108a024 100644
--- a/gdata/gdata-access-handler.c
+++ b/gdata/gdata-access-handler.c
@@ -188,7 +188,7 @@ gdata_access_handler_insert_rule (GDataAccessHandler *self, GDataService *servic
 		klass->append_query_headers (service, message);
 
 	/* Append the data */
-	upload_data = gdata_entry_get_xml (GDATA_ENTRY (rule));
+	upload_data = gdata_parsable_get_xml (GDATA_PARSABLE (rule));
 	soup_message_set_request (message, "application/atom+xml", SOUP_MEMORY_TAKE, upload_data, strlen (upload_data));
 
 	/* Send the message */
@@ -217,8 +217,8 @@ gdata_access_handler_insert_rule (GDataAccessHandler *self, GDataService *servic
 	g_assert (message->response_body->data != NULL);
 
 	/* Parse the XML; create and return a new GDataEntry of the same type as @entry */
-	updated_rule = GDATA_ACCESS_RULE (_gdata_entry_new_from_xml (G_OBJECT_TYPE (rule), message->response_body->data,
-					  message->response_body->length, error));
+	updated_rule = GDATA_ACCESS_RULE (gdata_parsable_new_from_xml (G_OBJECT_TYPE (rule), message->response_body->data,
+								       message->response_body->length, error));
 	g_object_unref (message);
 
 	return updated_rule;
@@ -302,7 +302,7 @@ gdata_access_handler_update_rule (GDataAccessHandler *self, GDataService *servic
 	/* Looks like ACLs don't support ETags */
 
 	/* Append the data */
-	upload_data = gdata_entry_get_xml (GDATA_ENTRY (rule));
+	upload_data = gdata_parsable_get_xml (GDATA_PARSABLE (rule));
 	soup_message_set_request (message, "application/atom+xml", SOUP_MEMORY_TAKE, upload_data, strlen (upload_data));
 
 	/* Send the message */
@@ -331,8 +331,8 @@ gdata_access_handler_update_rule (GDataAccessHandler *self, GDataService *servic
 	g_assert (message->response_body->data != NULL);
 
 	/* Parse the XML; create and return a new GDataEntry of the same type as @entry */
-	updated_rule = GDATA_ACCESS_RULE (_gdata_entry_new_from_xml (G_OBJECT_TYPE (rule), message->response_body->data,
-								     message->response_body->length, error));
+	updated_rule = GDATA_ACCESS_RULE (gdata_parsable_new_from_xml (G_OBJECT_TYPE (rule), message->response_body->data,
+								       message->response_body->length, error));
 	g_object_unref (message);
 
 	return updated_rule;
diff --git a/gdata/gdata-access-rule.c b/gdata/gdata-access-rule.c
index 1778967..0df5904 100644
--- a/gdata/gdata-access-rule.c
+++ b/gdata/gdata-access-rule.c
@@ -134,27 +134,6 @@ gdata_access_rule_new (const gchar *id)
 	return g_object_new (GDATA_TYPE_ACCESS_RULE, "id", id, NULL);
 }
 
-/**
- * gdata_access_rule_new_from_xml:
- * @xml: an XML string
- * @length: the length in characters of @xml, or %-1
- * @error: a #GError, or %NULL
- *
- * Creates a new #GDataAccessRule from an XML string. If @length is %-1, the length of
- * the string will be calculated.
- *
- * Errors from #GDataParserError can be returned if problems are found in the XML.
- *
- * Return value: a new #GDataAccessRule, or %NULL; unref with g_object_unref()
- *
- * Since: 0.3.0
- **/
-GDataAccessRule *
-gdata_access_rule_new_from_xml (const gchar *xml, gint length, GError **error)
-{
-	return GDATA_ACCESS_RULE (_gdata_entry_new_from_xml (GDATA_TYPE_ACCESS_RULE, xml, length, error));
-}
-
 static void
 gdata_access_rule_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec)
 {
diff --git a/gdata/gdata-access-rule.h b/gdata/gdata-access-rule.h
index 5cb41a2..6c41d27 100644
--- a/gdata/gdata-access-rule.h
+++ b/gdata/gdata-access-rule.h
@@ -64,7 +64,6 @@ typedef struct {
 GType gdata_access_rule_get_type (void) G_GNUC_CONST;
 
 GDataAccessRule *gdata_access_rule_new (const gchar *id) G_GNUC_WARN_UNUSED_RESULT;
-GDataAccessRule *gdata_access_rule_new_from_xml (const gchar *xml, gint length, GError **error) G_GNUC_WARN_UNUSED_RESULT;
 
 const gchar *gdata_access_rule_get_role (GDataAccessRule *self);
 void gdata_access_rule_set_role (GDataAccessRule *self, const gchar *role);
diff --git a/gdata/gdata-entry.c b/gdata/gdata-entry.c
index 9fed168..3e1c22f 100644
--- a/gdata/gdata-entry.c
+++ b/gdata/gdata-entry.c
@@ -99,6 +99,7 @@ gdata_entry_class_init (GDataEntryClass *klass)
 	parsable_class->pre_get_xml = pre_get_xml;
 	parsable_class->get_xml = get_xml;
 	parsable_class->get_namespaces = get_namespaces;
+	parsable_class->element_name = "entry";
 
 	g_object_class_install_property (gobject_class, PROP_TITLE,
 				g_param_spec_string ("title",
@@ -334,7 +335,7 @@ parse_xml (GDataParsable *parsable, xmlDoc *doc, xmlNode *node, gpointer user_da
 		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, "category", doc, node, NULL, error));
+		GDataCategory *category = GDATA_CATEGORY (_gdata_parsable_new_from_xml_node (GDATA_TYPE_CATEGORY, doc, node, NULL, error));
 		if (category == NULL)
 			return FALSE;
 
@@ -348,14 +349,14 @@ parse_xml (GDataParsable *parsable, xmlDoc *doc, xmlNode *node, gpointer user_da
 		xmlFree (content);
 	} else if (xmlStrcmp (node->name, (xmlChar*) "link") == 0) {
 		/* atom:link */
-		GDataLink *link = GDATA_LINK (_gdata_parsable_new_from_xml_node (GDATA_TYPE_LINK, "link", doc, node, NULL, error));
+		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, "author", doc, node, NULL, error));
+		GDataAuthor *author = GDATA_AUTHOR (_gdata_parsable_new_from_xml_node (GDATA_TYPE_AUTHOR, doc, node, NULL, error));
 		if (author == NULL)
 			return FALSE;
 
@@ -395,15 +396,6 @@ post_parse_xml (GDataParsable *parsable, gpointer user_data, GError **error)
 	return TRUE;
 }
 
-GDataEntry *
-_gdata_entry_new_from_xml (GType entry_type, const gchar *xml, gint length, GError **error)
-{
-	g_return_val_if_fail (xml != NULL, NULL);
-	g_return_val_if_fail (g_type_is_a (entry_type, GDATA_TYPE_ENTRY) == TRUE, FALSE);
-
-	return GDATA_ENTRY (_gdata_parsable_new_from_xml (entry_type, "entry", xml, length, NULL, error));
-}
-
 static void
 pre_get_xml (GDataParsable *parsable, GString *xml_string)
 {
@@ -452,14 +444,23 @@ get_xml (GDataParsable *parsable, GString *xml_string)
 		g_free (content);
 	}
 
-	for (categories = priv->categories; categories != NULL; categories = categories->next)
-		g_string_append (xml_string, _gdata_parsable_get_xml (GDATA_PARSABLE (categories->data), "category", FALSE));
+	for (categories = priv->categories; categories != NULL; categories = categories->next) {
+		gchar *xml = _gdata_parsable_get_xml (GDATA_PARSABLE (categories->data), FALSE);
+		g_string_append (xml_string, xml);
+		g_free (xml);
+	}
 
-	for (links = priv->links; links != NULL; links = links->next)
-		g_string_append (xml_string, _gdata_parsable_get_xml (GDATA_PARSABLE (links->data), "link", FALSE));
+	for (links = priv->links; links != NULL; links = links->next) {
+		gchar *xml = _gdata_parsable_get_xml (GDATA_PARSABLE (links->data), FALSE);
+		g_string_append (xml_string, xml);
+		g_free (xml);
+	}
 
-	for (authors = priv->authors; authors != NULL; authors = authors->next)
-		g_string_append (xml_string, _gdata_parsable_get_xml (GDATA_PARSABLE (authors->data), "author", FALSE));
+	for (authors = priv->authors; authors != NULL; authors = authors->next) {
+		gchar *xml = _gdata_parsable_get_xml (GDATA_PARSABLE (authors->data), FALSE);
+		g_string_append (xml_string, xml);
+		g_free (xml);
+	}
 }
 
 static void
@@ -483,26 +484,6 @@ gdata_entry_new (const gchar *id)
 }
 
 /**
- * gdata_entry_new_from_xml:
- * @xml: the XML for just the entry, with full namespace declarations
- * @length: the length of @xml, or -1
- * @error: a #GError, or %NULL
- *
- * Creates a new #GDataEntry from the provided @xml.
- *
- * If @length is -1, @xml will be assumed to be nul-terminated.
- *
- * If an error occurs during parsing, a suitable error from #GDataParserError will be returned.
- *
- * Return value: a new #GDataEntry, or %NULL
- **/
-GDataEntry *
-gdata_entry_new_from_xml (const gchar *xml, gint length, GError **error)
-{
-	return GDATA_ENTRY (_gdata_parsable_new_from_xml (GDATA_TYPE_ENTRY, "entry", xml, length, NULL, error));
-}
-
-/**
  * gdata_entry_get_title:
  * @self: a #GDataEntry
  *
@@ -789,19 +770,3 @@ gdata_entry_is_inserted (GDataEntry *self)
 		return TRUE;
 	return FALSE;
 }
-
-/**
- * gdata_entry_get_xml:
- * @self: a #GDataEntry
- *
- * Builds an XML representation of the #GDataEntry in its current state, such that it could be inserted on the server.
- * The XML is guaranteed to have all its namespaces declared properly in a self-contained fashion. The root element is
- * guaranteed to be <literal>&lt;entry&gt;</literal>.
- *
- * Return value: the entry's XML; free with g_free()
- **/
-gchar *
-gdata_entry_get_xml (GDataEntry *self)
-{
-	return _gdata_parsable_get_xml (GDATA_PARSABLE (self), "entry", TRUE);
-}
diff --git a/gdata/gdata-entry.h b/gdata/gdata-entry.h
index 46329e3..50b85f3 100644
--- a/gdata/gdata-entry.h
+++ b/gdata/gdata-entry.h
@@ -62,7 +62,6 @@ typedef struct {
 GType gdata_entry_get_type (void) G_GNUC_CONST;
 
 GDataEntry *gdata_entry_new (const gchar *id) G_GNUC_WARN_UNUSED_RESULT;
-GDataEntry *gdata_entry_new_from_xml (const gchar *xml, gint length, GError **error) G_GNUC_WARN_UNUSED_RESULT;
 
 const gchar *gdata_entry_get_title (GDataEntry *self);
 void gdata_entry_set_title (GDataEntry *self, const gchar *title);
@@ -81,7 +80,6 @@ GDataLink *gdata_entry_look_up_link (GDataEntry *self, const gchar *rel);
 void gdata_entry_add_author (GDataEntry *self, GDataAuthor *author);
 
 gboolean gdata_entry_is_inserted (GDataEntry *self);
-gchar *gdata_entry_get_xml (GDataEntry *self) G_GNUC_WARN_UNUSED_RESULT;
 
 G_END_DECLS
 
diff --git a/gdata/gdata-feed.c b/gdata/gdata-feed.c
index 2b6a9c4..5a38c21 100644
--- a/gdata/gdata-feed.c
+++ b/gdata/gdata-feed.c
@@ -99,6 +99,7 @@ gdata_feed_class_init (GDataFeedClass *klass)
 	parsable_class->pre_parse_xml = pre_parse_xml;
 	parsable_class->parse_xml = parse_xml;
 	parsable_class->post_parse_xml = post_parse_xml;
+	parsable_class->element_name = "feed";
 
 	/**
 	 * GDataFeed:title:
@@ -397,7 +398,7 @@ parse_xml (GDataParsable *parsable, xmlDoc *doc, xmlNode *node, gpointer user_da
 
 	if (xmlStrcmp (node->name, (xmlChar*) "entry") == 0) {
 		/* atom:entry */
-		GDataEntry *entry = GDATA_ENTRY (_gdata_parsable_new_from_xml_node (data->entry_type, "entry", doc, node, NULL, error));
+		GDataEntry *entry = GDATA_ENTRY (_gdata_parsable_new_from_xml_node (data->entry_type, doc, node, NULL, error));
 		if (entry == NULL)
 			return FALSE;
 
@@ -458,7 +459,7 @@ parse_xml (GDataParsable *parsable, xmlDoc *doc, xmlNode *node, gpointer user_da
 		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, "category", doc, node, NULL, error));
+		GDataCategory *category = GDATA_CATEGORY (_gdata_parsable_new_from_xml_node (GDATA_TYPE_CATEGORY, doc, node, NULL, error));
 		if (category == NULL)
 			return FALSE;
 
@@ -471,14 +472,14 @@ parse_xml (GDataParsable *parsable, xmlDoc *doc, xmlNode *node, gpointer user_da
 		self->priv->logo = (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, "link", doc, node, NULL, error));
+		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, "author", doc, node, NULL, error));
+		GDataAuthor *author = GDATA_AUTHOR (_gdata_parsable_new_from_xml_node (GDATA_TYPE_AUTHOR, doc, node, NULL, error));
 		if (author == NULL)
 			return FALSE;
 
@@ -491,7 +492,7 @@ parse_xml (GDataParsable *parsable, xmlDoc *doc, xmlNode *node, gpointer user_da
 		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, "generator", doc, node, NULL, error));
+		generator = GDATA_GENERATOR (_gdata_parsable_new_from_xml_node (GDATA_TYPE_GENERATOR, doc, node, NULL, error));
 		if (generator == NULL)
 			return FALSE;
 
@@ -588,7 +589,7 @@ _gdata_feed_new_from_xml (GType feed_type, const gchar *xml, gint length, GType
 	data->progress_user_data = progress_user_data;
 	data->entry_i = 0;
 
-	feed = GDATA_FEED (_gdata_parsable_new_from_xml (feed_type, "feed", xml, length, data, error));
+	feed = GDATA_FEED (_gdata_parsable_new_from_xml (feed_type, xml, length, data, error));
 
 	g_slice_free (ParseData, data);
 
diff --git a/gdata/gdata-parsable.c b/gdata/gdata-parsable.c
index 71b5f3a..8fdd912 100644
--- a/gdata/gdata-parsable.c
+++ b/gdata/gdata-parsable.c
@@ -113,15 +113,41 @@ real_parse_xml (GDataParsable *parsable, xmlDoc *doc, xmlNode *node, gpointer us
 	return TRUE;
 }
 
+/**
+ * gdata_parsable_new_from_xml:
+ * @parsable_type: the type of the class represented by the XML
+ * @xml: the XML for just the parsable object, with full namespace declarations
+ * @length: the length of @xml, or -1
+ * @error: a #GError, or %NULL
+ *
+ * Creates a new #GDataParsable subclass (of the given @parsable_type) from the given @xml.
+ *
+ * An object of the given @parsable_type is created, and its <function>pre_parse_xml</function>, <function>parse_xml</function> and
+ * <function>post_parse_xml</function> class functions called on the XML tree obtained from @xml. <function>pre_parse_xml</function> and
+ * <function>post_parse_xml</function> are called once each on the root node of the tree, while <function>parse_xml</function> is called for each of the
+ * child nodes of the root node.
+ *
+ * If @length is -1, @xml will be assumed to be null-terminated.
+ *
+ * If an error occurs during parsing, a suitable error from #GDataParserError will be returned.
+ *
+ * Return value: a new #GDataParsable, or %NULL; unref with g_object_unref()
+ **/
 GDataParsable *
-_gdata_parsable_new_from_xml (GType parsable_type, const gchar *first_element, const gchar *xml, gint length, gpointer user_data, GError **error)
+gdata_parsable_new_from_xml (GType parsable_type, const gchar *xml, gint length, GError **error)
+{
+	return _gdata_parsable_new_from_xml (parsable_type, xml, length, NULL, error);
+}
+
+GDataParsable *
+_gdata_parsable_new_from_xml (GType parsable_type, const gchar *xml, gint length, gpointer user_data, GError **error)
 {
 	xmlDoc *doc;
 	xmlNode *node;
 
 	g_return_val_if_fail (g_type_is_a (parsable_type, GDATA_TYPE_PARSABLE) == TRUE, FALSE);
-	g_return_val_if_fail (first_element != NULL, NULL);
 	g_return_val_if_fail (xml != NULL, NULL);
+	g_return_val_if_fail (length >= -1, NULL);
 
 	if (length == -1)
 		length = strlen (xml);
@@ -149,18 +175,11 @@ _gdata_parsable_new_from_xml (GType parsable_type, const gchar *first_element, c
 		return NULL;
 	}
 
-	if (xmlStrcmp (node->name, (xmlChar*) first_element) != 0) {
-		/* No <entry> element (required) */
-		xmlFreeDoc (doc);
-		gdata_parser_error_required_element_missing (first_element, "root", error);
-		return NULL;
-	}
-
-	return _gdata_parsable_new_from_xml_node (parsable_type, first_element, doc, node, user_data, error);
+	return _gdata_parsable_new_from_xml_node (parsable_type, doc, node, user_data, error);
 }
 
 GDataParsable *
-_gdata_parsable_new_from_xml_node (GType parsable_type, const gchar *first_element, xmlDoc *doc, xmlNode *node, gpointer user_data, GError **error)
+_gdata_parsable_new_from_xml_node (GType parsable_type, xmlDoc *doc, xmlNode *node, gpointer user_data, GError **error)
 {
 	GDataParsable *parsable;
 	GDataParsableClass *klass;
@@ -168,7 +187,6 @@ _gdata_parsable_new_from_xml_node (GType parsable_type, const gchar *first_eleme
 	g_return_val_if_fail (g_type_is_a (parsable_type, GDATA_TYPE_PARSABLE) == TRUE, FALSE);
 	g_return_val_if_fail (doc != NULL, FALSE);
 	g_return_val_if_fail (node != NULL, FALSE);
-	g_return_val_if_fail (xmlStrcmp (node->name, (xmlChar*) first_element) == 0, FALSE);
 
 	parsable = g_object_new (parsable_type, NULL);
 
@@ -176,6 +194,15 @@ _gdata_parsable_new_from_xml_node (GType parsable_type, const gchar *first_eleme
 	if (klass->parse_xml == NULL)
 		return FALSE;
 
+	g_assert (klass->element_name != NULL);
+	if (xmlStrcmp (node->name, (xmlChar*) klass->element_name) != 0 ||
+	    (node->ns != NULL && xmlStrcmp (node->ns->prefix, (xmlChar*) klass->element_namespace) != 0)) {
+		/* No <entry> element (required) */
+		xmlFreeDoc (doc);
+		gdata_parser_error_required_element_missing (klass->element_name, "root", error);
+		return NULL;
+	}
+
 	/* Call the pre-parse function first */
 	if (klass->pre_parse_xml != NULL &&
 	    klass->pre_parse_xml (parsable, doc, node, user_data, error) == FALSE) {
@@ -217,8 +244,34 @@ filter_namespaces_cb (gchar *prefix, gchar *href, GHashTable *canonical_namespac
 	return FALSE;
 }
 
+/**
+ * gdata_parsable_get_xml:
+ * @self: a #GDataParsable
+ *
+ * Builds an XML representation of the #GDataParsable in its current state, such that it could be inserted on the server. The XML is guaranteed to have
+ * all its namespaces declared properly in a self-contained fashion, and is valid for stand-alone use.
+ *
+ * Return value: the object's XML; free with g_free()
+ **/
 gchar *
-_gdata_parsable_get_xml (GDataParsable *self, const gchar *first_element, gboolean at_top_level)
+gdata_parsable_get_xml (GDataParsable *self)
+{
+	return _gdata_parsable_get_xml (self, TRUE);
+}
+
+/*
+ * _gdata_parsable_get_xml:
+ * @self: a #GDataParsable
+ * @declare_namespaces: %TRUE if all the namespaces used in the outputted XML should be declared in the opening tag of the root element, %FALSE otherwise
+ *
+ * Builds an XML representation of the #GDataParsable in its current state, such that it could be inserted on the server. If @declare_namespaces is
+ * %TRUE, the XML is guaranteed to have all its namespaces declared properly in a self-contained fashion, and is valid for stand-alone use. If
+ * @declare_namespaces is %FALSE, none of the used namespaces are declared, and the XML is suitable for insertion into a larger XML tree.
+ *
+ * Return value: the object's XML; free with g_free()
+ */
+gchar *
+_gdata_parsable_get_xml (GDataParsable *self, gboolean declare_namespaces)
 {
 	GDataParsableClass *klass;
 	GString *xml_string;
@@ -226,9 +279,10 @@ _gdata_parsable_get_xml (GDataParsable *self, const gchar *first_element, gboole
 	GHashTable *namespaces = NULL; /* shut up, gcc */
 
 	klass = GDATA_PARSABLE_GET_CLASS (self);
+	g_assert (klass->element_name != NULL);
 
 	/* Get the namespaces the class uses */
-	if (at_top_level == TRUE && klass->get_namespaces != NULL) {
+	if (declare_namespaces == TRUE && klass->get_namespaces != NULL) {
 		namespaces = g_hash_table_new (g_str_hash, g_str_equal);
 		klass->get_namespaces (self, namespaces);
 
@@ -238,10 +292,13 @@ _gdata_parsable_get_xml (GDataParsable *self, const gchar *first_element, gboole
 
 	/* Build up the namespace list */
 	xml_string = g_string_sized_new (100);
-	g_string_append_printf (xml_string, "<%s", first_element);
+	if (klass->element_namespace != NULL)
+		g_string_append_printf (xml_string, "<%s:%s", klass->element_namespace, klass->element_name);
+	else
+		g_string_append_printf (xml_string, "<%s", klass->element_name);
 
 	/* We only include the normal namespaces if we're not at the top level of XML building */
-	if (at_top_level == TRUE) {
+	if (declare_namespaces == TRUE) {
 		g_string_append (xml_string, " xmlns='http://www.w3.org/2005/Atom'");
 		g_hash_table_foreach (namespaces, (GHFunc) build_namespaces_cb, xml_string);
 		g_hash_table_destroy (namespaces);
@@ -268,8 +325,10 @@ _gdata_parsable_get_xml (GDataParsable *self, const gchar *first_element, gboole
 	/* Close the element; either by self-closing the opening tag, or by writing out a closing tag */
 	if (xml_string->len == length)
 		g_string_overwrite (xml_string, length - 1, "/>");
+	else if (klass->element_namespace != NULL)
+		g_string_append_printf (xml_string, "</%s:%s>", klass->element_namespace, klass->element_name);
 	else
-		g_string_append_printf (xml_string, "</%s>", first_element);
+		g_string_append_printf (xml_string, "</%s>", klass->element_name);
 
 	return g_string_free (xml_string, FALSE);
 }
diff --git a/gdata/gdata-parsable.h b/gdata/gdata-parsable.h
index 76dd671..d2c801f 100644
--- a/gdata/gdata-parsable.h
+++ b/gdata/gdata-parsable.h
@@ -30,14 +30,12 @@ G_BEGIN_DECLS
  * GDataParserError:
  * @GDATA_PARSER_ERROR_PARSING_STRING: Error parsing the XML syntax itself
  * @GDATA_PARSER_ERROR_EMPTY_DOCUMENT: Empty document
- * @GDATA_PARSER_ERROR_UNHANDLED_XML_ELEMENT: Unknown or unhandled XML element (fatal error)
  *
  * Error codes for XML parsing operations.
  **/
 typedef enum {
 	GDATA_PARSER_ERROR_PARSING_STRING = 1,
-	GDATA_PARSER_ERROR_EMPTY_DOCUMENT,
-	GDATA_PARSER_ERROR_UNHANDLED_XML_ELEMENT
+	GDATA_PARSER_ERROR_EMPTY_DOCUMENT
 } GDataParserError;
 
 #define GDATA_PARSER_ERROR gdata_parser_error_quark ()
@@ -75,6 +73,8 @@ typedef struct {
  * XML node to be added to @xml_string
  * @get_xml: a function to build an XML representation of the #GDataParsable in its current state, appending it to the provided #GString
  * @get_namespaces: a function to return a string containing the namespace declarations used by the @parsable when represented in XML form
+ * @element_name: the name of the XML element which represents this parsable
+ * @element_namespace: the prefix of the XML namespace used for the parsable
  *
  * The class structure for the #GDataParsable class.
  *
@@ -90,10 +90,16 @@ typedef struct {
 	void (*pre_get_xml) (GDataParsable *parsable, GString *xml_string);
 	void (*get_xml) (GDataParsable *parsable, GString *xml_string);
 	void (*get_namespaces) (GDataParsable *parsable, GHashTable *namespaces);
+
+	const gchar *element_name;
+	const gchar *element_namespace;
 } GDataParsableClass;
 
 GType gdata_parsable_get_type (void) G_GNUC_CONST;
 
+GDataParsable *gdata_parsable_new_from_xml (GType parsable_type, const gchar *xml, gint length, GError **error) G_GNUC_WARN_UNUSED_RESULT;
+gchar *gdata_parsable_get_xml (GDataParsable *self) G_GNUC_WARN_UNUSED_RESULT;
+
 G_END_DECLS
 
 #endif /* !GDATA_PARSABLE_H */
diff --git a/gdata/gdata-private.h b/gdata/gdata-private.h
index 80faa5c..d2ad413 100644
--- a/gdata/gdata-private.h
+++ b/gdata/gdata-private.h
@@ -37,19 +37,16 @@ void _gdata_query_set_next_uri (GDataQuery *self, const gchar *next_uri);
 void _gdata_query_set_previous_uri (GDataQuery *self, const gchar *previous_uri);
 
 #include "gdata-parsable.h"
-GDataParsable *_gdata_parsable_new_from_xml (GType parsable_type, const gchar *first_element, const gchar *xml, gint length, gpointer user_data,
+GDataParsable *_gdata_parsable_new_from_xml (GType parsable_type, const gchar *xml, gint length, gpointer user_data,
 					     GError **error) G_GNUC_WARN_UNUSED_RESULT;
-GDataParsable *_gdata_parsable_new_from_xml_node (GType parsable_type, const gchar *first_element, xmlDoc *doc, xmlNode *node, gpointer user_data,
+GDataParsable *_gdata_parsable_new_from_xml_node (GType parsable_type, xmlDoc *doc, xmlNode *node, gpointer user_data,
 						  GError **error) G_GNUC_WARN_UNUSED_RESULT;
-gchar *_gdata_parsable_get_xml (GDataParsable *self, const gchar *first_element, gboolean at_top_level) G_GNUC_WARN_UNUSED_RESULT;
+gchar *_gdata_parsable_get_xml (GDataParsable *self, gboolean declare_namespaces) G_GNUC_WARN_UNUSED_RESULT;
 
 #include "gdata-feed.h"
 GDataFeed *_gdata_feed_new_from_xml (GType feed_type, const gchar *xml, gint length, GType entry_type,
 				     GDataQueryProgressCallback progress_callback, gpointer progress_user_data, GError **error) G_GNUC_WARN_UNUSED_RESULT;
 
-#include "gdata-entry.h"
-GDataEntry *_gdata_entry_new_from_xml (GType entry_type, const gchar *xml, gint length, GError **error) G_GNUC_WARN_UNUSED_RESULT;
-
 #include "gdata-parser.h"
 
 G_END_DECLS
diff --git a/gdata/gdata-service.c b/gdata/gdata-service.c
index d94d0ca..afcb67f 100644
--- a/gdata/gdata-service.c
+++ b/gdata/gdata-service.c
@@ -1216,7 +1216,7 @@ gdata_service_insert_entry (GDataService *self, const gchar *upload_uri, GDataEn
 		klass->append_query_headers (self, message);
 
 	/* Append the data */
-	upload_data = gdata_entry_get_xml (entry);
+	upload_data = gdata_parsable_get_xml (GDATA_PARSABLE (entry));
 	soup_message_set_request (message, "application/atom+xml", SOUP_MEMORY_TAKE, upload_data, strlen (upload_data));
 
 	/* Send the message */
@@ -1245,7 +1245,8 @@ gdata_service_insert_entry (GDataService *self, const gchar *upload_uri, GDataEn
 	g_assert (message->response_body->data != NULL);
 
 	/* Parse the XML; create and return a new GDataEntry of the same type as @entry */
-	updated_entry = _gdata_entry_new_from_xml (G_OBJECT_TYPE (entry), message->response_body->data, message->response_body->length, error);
+	updated_entry = GDATA_ENTRY (gdata_parsable_new_from_xml (G_OBJECT_TYPE (entry), message->response_body->data, message->response_body->length,
+								  error));
 	g_object_unref (message);
 
 	return updated_entry;
@@ -1392,7 +1393,7 @@ gdata_service_update_entry (GDataService *self, GDataEntry *entry, GCancellable
 		soup_message_headers_append (message->request_headers, "If-Match", gdata_entry_get_etag (entry));
 
 	/* Append the data */
-	upload_data = gdata_entry_get_xml (entry);
+	upload_data = gdata_parsable_get_xml (GDATA_PARSABLE (entry));
 	soup_message_set_request (message, "application/atom+xml", SOUP_MEMORY_TAKE, upload_data, strlen (upload_data));
 
 	/* Send the message */
@@ -1421,7 +1422,8 @@ gdata_service_update_entry (GDataService *self, GDataEntry *entry, GCancellable
 	g_assert (message->response_body->data != NULL);
 
 	/* Parse the XML; create and return a new GDataEntry of the same type as @entry */
-	updated_entry = _gdata_entry_new_from_xml (G_OBJECT_TYPE (entry), message->response_body->data, message->response_body->length, error);
+	updated_entry = GDATA_ENTRY (gdata_parsable_new_from_xml (G_OBJECT_TYPE (entry), message->response_body->data, message->response_body->length,
+								  error));
 	g_object_unref (message);
 
 	return updated_entry;
diff --git a/gdata/gdata.symbols b/gdata/gdata.symbols
index 17446fc..be406c1 100644
--- a/gdata/gdata.symbols
+++ b/gdata/gdata.symbols
@@ -3,7 +3,6 @@ gdata_color_from_hexadecimal
 gdata_color_to_hexadecimal
 gdata_entry_get_type
 gdata_entry_new
-gdata_entry_new_from_xml
 gdata_entry_get_title
 gdata_entry_set_title
 gdata_entry_get_summary
@@ -20,7 +19,6 @@ gdata_entry_add_link
 gdata_entry_look_up_link
 gdata_entry_add_author
 gdata_entry_is_inserted
-gdata_entry_get_xml
 gdata_feed_get_type
 gdata_feed_get_entries
 gdata_feed_look_up_entry
@@ -109,7 +107,6 @@ gdata_youtube_service_get_developer_key
 gdata_youtube_service_get_youtube_user
 gdata_youtube_video_get_type
 gdata_youtube_video_new
-gdata_youtube_video_new_from_xml
 gdata_youtube_video_get_view_count
 gdata_youtube_video_get_favorite_count
 gdata_youtube_video_get_location
@@ -167,7 +164,6 @@ gdata_youtube_query_get_uploader
 gdata_youtube_query_set_uploader
 gdata_calendar_calendar_get_type
 gdata_calendar_calendar_new
-gdata_calendar_calendar_new_from_xml
 gdata_calendar_calendar_get_timezone
 gdata_calendar_calendar_set_timezone
 gdata_calendar_calendar_get_times_cleaned
@@ -181,7 +177,6 @@ gdata_calendar_calendar_get_access_level
 gdata_calendar_calendar_get_edited
 gdata_calendar_event_get_type
 gdata_calendar_event_new
-gdata_calendar_event_new_from_xml
 gdata_calendar_event_get_edited
 gdata_calendar_event_get_status
 gdata_calendar_event_set_status
@@ -265,7 +260,6 @@ gdata_contacts_query_get_group
 gdata_contacts_query_set_group
 gdata_contacts_contact_get_type
 gdata_contacts_contact_new
-gdata_contacts_contact_new_from_xml
 gdata_contacts_contact_get_edited
 gdata_contacts_contact_add_email_address
 gdata_contacts_contact_get_email_addresses
@@ -300,12 +294,13 @@ gdata_access_handler_update_rule
 gdata_access_handler_delete_rule
 gdata_access_rule_get_type
 gdata_access_rule_new
-gdata_access_rule_new_from_xml
 gdata_access_rule_get_role
 gdata_access_rule_set_role
 gdata_access_rule_get_scope
 gdata_access_rule_set_scope
 gdata_parsable_get_type
+gdata_parsable_new_from_xml
+gdata_parsable_get_xml
 gdata_calendar_feed_get_type
 gdata_calendar_feed_get_timezone
 gdata_calendar_feed_get_times_cleaned
@@ -486,7 +481,6 @@ gdata_youtube_state_get_help_uri
 gdata_youtube_state_get_message
 gdata_picasaweb_album_get_type
 gdata_picasaweb_album_new
-gdata_picasaweb_album_new_from_xml
 gdata_picasaweb_album_get_user
 gdata_picasaweb_album_get_nickname
 gdata_picasaweb_album_get_edited
@@ -511,7 +505,6 @@ gdata_picasaweb_album_get_contents
 gdata_picasaweb_album_get_thumbnails
 gdata_picasaweb_file_get_type
 gdata_picasaweb_file_new
-gdata_picasaweb_file_new_from_xml
 gdata_picasaweb_file_get_edited
 gdata_picasaweb_file_get_version
 gdata_picasaweb_file_get_position
diff --git a/gdata/media/gdata-media-category.c b/gdata/media/gdata-media-category.c
index f6ff195..3dab2f0 100644
--- a/gdata/media/gdata-media-category.c
+++ b/gdata/media/gdata-media-category.c
@@ -76,6 +76,8 @@ gdata_media_category_class_init (GDataMediaCategoryClass *klass)
 	parsable_class->pre_get_xml = pre_get_xml;
 	parsable_class->get_xml = get_xml;
 	parsable_class->get_namespaces = get_namespaces;
+	parsable_class->element_name = "category";
+	parsable_class->element_namespace = "media";
 
 	/**
 	 * GDataMediaCategory:category:
diff --git a/gdata/media/gdata-media-content.c b/gdata/media/gdata-media-content.c
index de10bdf..a3cc96b 100644
--- a/gdata/media/gdata-media-content.c
+++ b/gdata/media/gdata-media-content.c
@@ -81,6 +81,8 @@ gdata_media_content_class_init (GDataMediaContentClass *klass)
 
 	parsable_class->pre_parse_xml = pre_parse_xml;
 	parsable_class->get_namespaces = get_namespaces;
+	parsable_class->element_name = "content";
+	parsable_class->element_namespace = "media";
 
 	/**
 	 * GDataMediaContent:uri:
diff --git a/gdata/media/gdata-media-credit.c b/gdata/media/gdata-media-credit.c
index 5af0cbd..1df98c6 100644
--- a/gdata/media/gdata-media-credit.c
+++ b/gdata/media/gdata-media-credit.c
@@ -70,6 +70,8 @@ gdata_media_credit_class_init (GDataMediaCreditClass *klass)
 	parsable_class->pre_parse_xml = pre_parse_xml;
 	parsable_class->parse_xml = parse_xml;
 	parsable_class->get_namespaces = get_namespaces;
+	parsable_class->element_name = "credit";
+	parsable_class->element_namespace = "media";
 
 	/**
 	 * GDataMediaCredit:credit:
diff --git a/gdata/media/gdata-media-group.c b/gdata/media/gdata-media-group.c
index f2d66c2..0b44341 100644
--- a/gdata/media/gdata-media-group.c
+++ b/gdata/media/gdata-media-group.c
@@ -80,6 +80,8 @@ gdata_media_group_class_init (GDataMediaGroupClass *klass)
 	parsable_class->parse_xml = parse_xml;
 	parsable_class->get_xml = get_xml;
 	parsable_class->get_namespaces = get_namespaces;
+	parsable_class->element_name = "group";
+	parsable_class->element_namespace = "media";
 }
 
 static void
@@ -155,7 +157,7 @@ parse_xml (GDataParsable *parsable, xmlDoc *doc, xmlNode *node, gpointer user_da
 		xmlFree (keywords);
 	} 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, "category", doc,
+		GDataMediaCategory *category = GDATA_MEDIA_CATEGORY (_gdata_parsable_new_from_xml_node (GDATA_TYPE_MEDIA_CATEGORY, doc,
 													node, NULL, error));
 		if (category == NULL)
 			return FALSE;
@@ -163,16 +165,14 @@ parse_xml (GDataParsable *parsable, xmlDoc *doc, xmlNode *node, gpointer user_da
 		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, "content", doc,
-												     node, NULL, error));
+		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, "credit", doc,
-												  node, NULL, error));
+		GDataMediaCredit *credit = GDATA_MEDIA_CREDIT (_gdata_parsable_new_from_xml_node (GDATA_TYPE_MEDIA_CREDIT, doc, node, NULL, error));
 		if (credit == NULL)
 			return FALSE;
 
@@ -243,7 +243,7 @@ parse_xml (GDataParsable *parsable, xmlDoc *doc, xmlNode *node, gpointer user_da
 		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, "thumbnail", doc,
+		GDataMediaThumbnail *thumb = GDATA_MEDIA_THUMBNAIL (_gdata_parsable_new_from_xml_node (GDATA_TYPE_MEDIA_THUMBNAIL, doc,
 												       node, NULL, error));
 		if (thumb == NULL)
 			return FALSE;
@@ -264,7 +264,7 @@ get_xml (GDataParsable *parsable, GString *xml_string)
 
 	/* Media category */
 	if (priv->category != NULL) {
-		gchar *xml = _gdata_parsable_get_xml (GDATA_PARSABLE (priv->category), "media:category", FALSE);
+		gchar *xml = _gdata_parsable_get_xml (GDATA_PARSABLE (priv->category), FALSE);
 		g_string_append (xml_string, xml);
 		g_free (xml);
 	}
diff --git a/gdata/media/gdata-media-thumbnail.c b/gdata/media/gdata-media-thumbnail.c
index 0fe2392..e9a531d 100644
--- a/gdata/media/gdata-media-thumbnail.c
+++ b/gdata/media/gdata-media-thumbnail.c
@@ -70,6 +70,8 @@ gdata_media_thumbnail_class_init (GDataMediaThumbnailClass *klass)
 
 	parsable_class->pre_parse_xml = pre_parse_xml;
 	parsable_class->get_namespaces = get_namespaces;
+	parsable_class->element_name = "thumbnail";
+	parsable_class->element_namespace = "media";
 
 	/**
 	 * GDataMediaThumbnail:uri:
diff --git a/gdata/services/calendar/gdata-calendar-calendar.c b/gdata/services/calendar/gdata-calendar-calendar.c
index 670955c..ebacbc6 100644
--- a/gdata/services/calendar/gdata-calendar-calendar.c
+++ b/gdata/services/calendar/gdata-calendar-calendar.c
@@ -279,25 +279,6 @@ gdata_calendar_calendar_new (const gchar *id)
 	return g_object_new (GDATA_TYPE_CALENDAR_CALENDAR, "id", id, NULL);
 }
 
-/**
- * gdata_calendar_calendar_new_from_xml:
- * @xml: an XML string
- * @length: the length in characters of @xml, or %-1
- * @error: a #GError, or %NULL
- *
- * Creates a new #GDataCalendarCalendar from an XML string. If @length is %-1, the length of
- * the string will be calculated.
- *
- * Errors from #GDataParserError can be returned if problems are found in the XML.
- *
- * Return value: a new #GDataCalendarCalendar, or %NULL; unref with g_object_unref()
- **/
-GDataCalendarCalendar *
-gdata_calendar_calendar_new_from_xml (const gchar *xml, gint length, GError **error)
-{
-	return GDATA_CALENDAR_CALENDAR (_gdata_entry_new_from_xml (GDATA_TYPE_CALENDAR_CALENDAR, xml, length, error));
-}
-
 static gboolean
 parse_xml (GDataParsable *parsable, xmlDoc *doc, xmlNode *node, gpointer user_data, GError **error)
 {
diff --git a/gdata/services/calendar/gdata-calendar-calendar.h b/gdata/services/calendar/gdata-calendar-calendar.h
index e714093..d54e659 100644
--- a/gdata/services/calendar/gdata-calendar-calendar.h
+++ b/gdata/services/calendar/gdata-calendar-calendar.h
@@ -60,7 +60,6 @@ typedef struct {
 GType gdata_calendar_calendar_get_type (void) G_GNUC_CONST;
 
 GDataCalendarCalendar *gdata_calendar_calendar_new (const gchar *id) G_GNUC_WARN_UNUSED_RESULT;
-GDataCalendarCalendar *gdata_calendar_calendar_new_from_xml (const gchar *xml, gint length, GError **error) G_GNUC_WARN_UNUSED_RESULT;
 
 const gchar *gdata_calendar_calendar_get_timezone (GDataCalendarCalendar *self);
 void gdata_calendar_calendar_set_timezone (GDataCalendarCalendar *self, const gchar *_timezone);
diff --git a/gdata/services/calendar/gdata-calendar-event.c b/gdata/services/calendar/gdata-calendar-event.c
index 6086969..c802091 100644
--- a/gdata/services/calendar/gdata-calendar-event.c
+++ b/gdata/services/calendar/gdata-calendar-event.c
@@ -444,25 +444,6 @@ gdata_calendar_event_new (const gchar *id)
 	return g_object_new (GDATA_TYPE_CALENDAR_EVENT, "id", id, NULL);
 }
 
-/**
- * gdata_calendar_event_new_from_xml:
- * @xml: an XML string
- * @length: the length in characters of @xml, or %-1
- * @error: a #GError, or %NULL
- *
- * Creates a new #GDataCalendarEvent from an XML string. If @length is %-1, the length of
- * the string will be calculated.
- *
- * Errors from #GDataParserError can be returned if problems are found in the XML.
- *
- * Return value: a new #GDataCalendarEvent, or %NULL; unref with g_object_unref()
- **/
-GDataCalendarEvent *
-gdata_calendar_event_new_from_xml (const gchar *xml, gint length, GError **error)
-{
-	return GDATA_CALENDAR_EVENT (_gdata_entry_new_from_xml (GDATA_TYPE_CALENDAR_EVENT, xml, length, error));
-}
-
 static gboolean
 parse_xml (GDataParsable *parsable, xmlDoc *doc, xmlNode *node, gpointer user_data, GError **error)
 {
@@ -553,7 +534,7 @@ parse_xml (GDataParsable *parsable, xmlDoc *doc, xmlNode *node, gpointer user_da
 		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, "when", doc, node, NULL, error));
+		GDataGDWhen *when = GDATA_GD_WHEN (_gdata_parsable_new_from_xml_node (GDATA_TYPE_GD_WHEN, doc, node, NULL, error));
 		if (when == NULL)
 			return FALSE;
 
@@ -588,14 +569,14 @@ parse_xml (GDataParsable *parsable, xmlDoc *doc, xmlNode *node, gpointer user_da
 		xmlFree (value);
 	} 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, "who", doc, node, NULL, error));
+		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, "where", doc, node, NULL, error));
+		GDataGDWhere *where = GDATA_GD_WHERE (_gdata_parsable_new_from_xml_node (GDATA_TYPE_GD_WHERE, doc, node, NULL, error));
 		if (where == NULL)
 			return FALSE;
 
@@ -622,10 +603,21 @@ parse_xml (GDataParsable *parsable, xmlDoc *doc, xmlNode *node, gpointer user_da
 }
 
 static void
+get_child_xml (GList *list, GString *xml_string)
+{
+	GList *i;
+
+	for (i = list; i != NULL; i = i->next) {
+		gchar *xml = _gdata_parsable_get_xml (GDATA_PARSABLE (i->data), FALSE);
+		g_string_append (xml_string, xml);
+		g_free (xml);
+	}
+}
+
+static void
 get_xml (GDataParsable *parsable, GString *xml_string)
 {
 	GDataCalendarEventPrivate *priv = GDATA_CALENDAR_EVENT (parsable)->priv;
-	GList *i;
 
 	/* Chain up to the parent class */
 	GDATA_PARSABLE_CLASS (gdata_calendar_event_parent_class)->get_xml (parsable, xml_string);
@@ -672,14 +664,9 @@ get_xml (GDataParsable *parsable, GString *xml_string)
 	if (priv->recurrence != NULL)
 		g_string_append_printf (xml_string, "<gd:recurrence>%s</gd:recurrence>", priv->recurrence);
 
-	for (i = priv->times; i != NULL; i = i->next)
-		g_string_append (xml_string, _gdata_parsable_get_xml (GDATA_PARSABLE (i->data), "gd:when", FALSE));
-
-	for (i = priv->people; i != NULL; i = i->next)
-		g_string_append (xml_string, _gdata_parsable_get_xml (GDATA_PARSABLE (i->data), "gd:who", FALSE));
-
-	for (i = priv->places; i != NULL; i = i->next)
-		g_string_append (xml_string, _gdata_parsable_get_xml (GDATA_PARSABLE (i->data), "gd:where", FALSE));
+	get_child_xml (priv->times, xml_string);
+	get_child_xml (priv->people, xml_string);
+	get_child_xml (priv->places, xml_string);
 
 	/* TODO:
 	 * - Finish supporting all tags
diff --git a/gdata/services/calendar/gdata-calendar-event.h b/gdata/services/calendar/gdata-calendar-event.h
index b336cdf..74fc8be 100644
--- a/gdata/services/calendar/gdata-calendar-event.h
+++ b/gdata/services/calendar/gdata-calendar-event.h
@@ -63,7 +63,6 @@ typedef struct {
 GType gdata_calendar_event_get_type (void) G_GNUC_CONST;
 
 GDataCalendarEvent *gdata_calendar_event_new (const gchar *id) G_GNUC_WARN_UNUSED_RESULT;
-GDataCalendarEvent *gdata_calendar_event_new_from_xml (const gchar *xml, gint length, GError **error) G_GNUC_WARN_UNUSED_RESULT;
 
 void gdata_calendar_event_get_edited (GDataCalendarEvent *self, GTimeVal *edited);
 const gchar *gdata_calendar_event_get_status (GDataCalendarEvent *self);
diff --git a/gdata/services/contacts/gdata-contacts-contact.c b/gdata/services/contacts/gdata-contacts-contact.c
index 34b438e..28a41de 100644
--- a/gdata/services/contacts/gdata-contacts-contact.c
+++ b/gdata/services/contacts/gdata-contacts-contact.c
@@ -232,27 +232,6 @@ gdata_contacts_contact_new (const gchar *id)
 	return g_object_new (GDATA_TYPE_CONTACTS_CONTACT, "id", id, NULL);
 }
 
-/**
- * gdata_contacts_contact_new_from_xml:
- * @xml: an XML string
- * @length: the length in characters of @xml, or %-1
- * @error: a #GError, or %NULL
- *
- * Creates a new #GDataContactsContact from an XML string. If @length is %-1, the length of
- * the string will be calculated.
- *
- * Errors from #GDataParserError can be returned if problems are found in the XML.
- *
- * Return value: a new #GDataContactsContact, or %NULL; unref with g_object_unref()
- *
- * Since: 0.2.0
- **/
-GDataContactsContact *
-gdata_contacts_contact_new_from_xml (const gchar *xml, gint length, GError **error)
-{
-	return GDATA_CONTACTS_CONTACT (_gdata_entry_new_from_xml (GDATA_TYPE_CONTACTS_CONTACT, xml, length, error));
-}
-
 static gboolean
 parse_xml (GDataParsable *parsable, xmlDoc *doc, xmlNode *node, gpointer user_data, GError **error)
 {
@@ -277,7 +256,7 @@ parse_xml (GDataParsable *parsable, xmlDoc *doc, xmlNode *node, gpointer user_da
 		xmlFree (edited);
 	} 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, "email", doc,
+		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;
@@ -285,14 +264,14 @@ parse_xml (GDataParsable *parsable, xmlDoc *doc, xmlNode *node, gpointer user_da
 		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, "im", doc, node, NULL, error));
+		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, "phoneNumber", doc,
+		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;
@@ -301,7 +280,7 @@ parse_xml (GDataParsable *parsable, xmlDoc *doc, xmlNode *node, gpointer user_da
 	} else if (xmlStrcmp (node->name, (xmlChar*) "postalAddress") == 0) {
 		/* gd:postalAddress */
 		GDataGDPostalAddress *address = GDATA_GD_POSTAL_ADDRESS (_gdata_parsable_new_from_xml_node (GDATA_TYPE_GD_POSTAL_ADDRESS,
-													    "postalAddress", doc, node, NULL, error));
+													    doc, node, NULL, error));
 		if (address == NULL)
 			return FALSE;
 
@@ -309,7 +288,7 @@ parse_xml (GDataParsable *parsable, xmlDoc *doc, xmlNode *node, gpointer user_da
 	} 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,
-													      "organization", doc, node, NULL, error));
+													      doc, node, NULL, error));
 		if (organization == NULL)
 			return FALSE;
 
@@ -391,6 +370,18 @@ parse_xml (GDataParsable *parsable, xmlDoc *doc, xmlNode *node, gpointer user_da
 }
 
 static void
+get_child_xml (GList *list, GString *xml_string)
+{
+	GList *i;
+
+	for (i = list; i != NULL; i = i->next) {
+		gchar *xml = _gdata_parsable_get_xml (GDATA_PARSABLE (i->data), FALSE);
+		g_string_append (xml_string, xml);
+		g_free (xml);
+	}
+}
+
+static void
 get_extended_property_xml_cb (const gchar *name, const gchar *value, GString *xml_string)
 {
 	g_string_append_printf (xml_string, "<gd:extendedProperty name='%s'>%s</gd:extendedProperty>", name, value);
@@ -406,30 +397,16 @@ static void
 get_xml (GDataParsable *parsable, GString *xml_string)
 {
 	GDataContactsContactPrivate *priv = GDATA_CONTACTS_CONTACT (parsable)->priv;
-	GList *i;
 
 	/* Chain up to the parent class */
 	GDATA_PARSABLE_CLASS (gdata_contacts_contact_parent_class)->get_xml (parsable, xml_string);
 
-	/* E-mail addresses */
-	for (i = priv->email_addresses; i != NULL; i = i->next)
-		g_string_append (xml_string, _gdata_parsable_get_xml (GDATA_PARSABLE (i->data), "gd:email", FALSE));
-
-	/* IM addresses */
-	for (i = priv->im_addresses; i != NULL; i = i->next)
-		g_string_append (xml_string, _gdata_parsable_get_xml (GDATA_PARSABLE (i->data), "gd:im", FALSE));
-
-	/* Phone numbers */
-	for (i = priv->phone_numbers; i != NULL; i = i->next)
-		g_string_append (xml_string, _gdata_parsable_get_xml (GDATA_PARSABLE (i->data), "gd:phoneNumber", FALSE));
-
-	/* Postal addresses */
-	for (i = priv->postal_addresses; i != NULL; i = i->next)
-		g_string_append (xml_string, _gdata_parsable_get_xml (GDATA_PARSABLE (i->data), "gd:postalAddress", FALSE));
-
-	/* Organisations */
-	for (i = priv->organizations; i != NULL; i = i->next)
-		g_string_append (xml_string, _gdata_parsable_get_xml (GDATA_PARSABLE (i->data), "gd:organization", FALSE));
+	/* Lists of stuff */
+	get_child_xml (priv->email_addresses, xml_string);
+	get_child_xml (priv->im_addresses, xml_string);
+	get_child_xml (priv->phone_numbers, xml_string);
+	get_child_xml (priv->postal_addresses, xml_string);
+	get_child_xml (priv->organizations, xml_string);
 
 	/* Extended properties */
 	g_hash_table_foreach (priv->extended_properties, (GHFunc) get_extended_property_xml_cb, xml_string);
diff --git a/gdata/services/contacts/gdata-contacts-contact.h b/gdata/services/contacts/gdata-contacts-contact.h
index c540bf1..d3d7798 100644
--- a/gdata/services/contacts/gdata-contacts-contact.h
+++ b/gdata/services/contacts/gdata-contacts-contact.h
@@ -64,7 +64,6 @@ typedef struct {
 GType gdata_contacts_contact_get_type (void) G_GNUC_CONST;
 
 GDataContactsContact *gdata_contacts_contact_new (const gchar *id) G_GNUC_WARN_UNUSED_RESULT;
-GDataContactsContact *gdata_contacts_contact_new_from_xml (const gchar *xml, gint length, GError **error) G_GNUC_WARN_UNUSED_RESULT;
 
 void gdata_contacts_contact_get_edited (GDataContactsContact *self, GTimeVal *edited);
 gboolean gdata_contacts_contact_is_deleted (GDataContactsContact *self);
diff --git a/gdata/services/picasaweb/gdata-picasaweb-album.c b/gdata/services/picasaweb/gdata-picasaweb-album.c
index 2e20033..dd4e2cb 100644
--- a/gdata/services/picasaweb/gdata-picasaweb-album.c
+++ b/gdata/services/picasaweb/gdata-picasaweb-album.c
@@ -476,8 +476,7 @@ parse_xml (GDataParsable *parsable, xmlDoc *doc, xmlNode *node, gpointer user_da
 
 	if (xmlStrcmp (node->name, (xmlChar*) "group") == 0) {
 		/* media:group */
-		GDataMediaGroup *group = GDATA_MEDIA_GROUP (_gdata_parsable_new_from_xml_node (GDATA_TYPE_MEDIA_GROUP, "group", doc,
-											       node, NULL, error));
+		GDataMediaGroup *group = GDATA_MEDIA_GROUP (_gdata_parsable_new_from_xml_node (GDATA_TYPE_MEDIA_GROUP, doc, node, NULL, error));
 		if (group == NULL)
 			return FALSE;
 
@@ -635,7 +634,7 @@ get_xml (GDataParsable *parsable, GString *xml_string)
 		g_string_append (xml_string, "<gphoto:commentingEnabled>true</gphoto:commentingEnabled>");
 
 	/* media:group */
-	xml = _gdata_parsable_get_xml (GDATA_PARSABLE (priv->media_group), "media:group", FALSE);
+	xml = _gdata_parsable_get_xml (GDATA_PARSABLE (priv->media_group), FALSE);
 	g_string_append (xml_string, xml);
 	g_free (xml);
 
@@ -681,27 +680,6 @@ gdata_picasaweb_album_new (const gchar *id)
 }
 
 /**
- * gdata_picasaweb_album_new_from_xml:
- * @xml: an XML string
- * @length: the length in characters of @xml, or %-1
- * @error: a #GError, or %NULL
- *
- * Creates a new #GDataPicasaWebAlbum from an XML string. If @length is %-1, the length of
- * the string will be calculated.
- *
- * Errors from #GDataParserError can be returned if problems are found in the XML.
- *
- * Return value: a new #GDataPicasaWebAlbum, or %NULL; unref with g_object_unref()
- *
- * Since: 0.4.0
- **/
-GDataPicasaWebAlbum *
-gdata_picasaweb_album_new_from_xml (const gchar *xml, gint length, GError **error)
-{
-	return GDATA_PICASAWEB_ALBUM (_gdata_entry_new_from_xml (GDATA_TYPE_PICASAWEB_ALBUM, xml, length, error));
-}
-
-/**
  * gdata_picasaweb_album_get_user:
  * @self: a #GDataPicasaWebAlbum
  *
diff --git a/gdata/services/picasaweb/gdata-picasaweb-album.h b/gdata/services/picasaweb/gdata-picasaweb-album.h
index efc57ef..27a04d2 100644
--- a/gdata/services/picasaweb/gdata-picasaweb-album.h
+++ b/gdata/services/picasaweb/gdata-picasaweb-album.h
@@ -79,7 +79,6 @@ typedef struct {
 GType gdata_picasaweb_album_get_type (void) G_GNUC_CONST;
 
 GDataPicasaWebAlbum *gdata_picasaweb_album_new (const gchar *id) G_GNUC_WARN_UNUSED_RESULT;
-GDataPicasaWebAlbum *gdata_picasaweb_album_new_from_xml (const gchar *xml, gint length, GError **error) G_GNUC_WARN_UNUSED_RESULT;
 
 const gchar *gdata_picasaweb_album_get_user (GDataPicasaWebAlbum *self);
 const gchar *gdata_picasaweb_album_get_nickname (GDataPicasaWebAlbum *self);
diff --git a/gdata/services/picasaweb/gdata-picasaweb-file.c b/gdata/services/picasaweb/gdata-picasaweb-file.c
index 9a89f74..c42adb9 100644
--- a/gdata/services/picasaweb/gdata-picasaweb-file.c
+++ b/gdata/services/picasaweb/gdata-picasaweb-file.c
@@ -577,8 +577,7 @@ parse_xml (GDataParsable *parsable, xmlDoc *doc, xmlNode *node, gpointer user_da
 
 	if (xmlStrcmp (node->name, (xmlChar*) "group") == 0) {
 		/* media:group */
-		GDataMediaGroup *group = GDATA_MEDIA_GROUP (_gdata_parsable_new_from_xml_node (GDATA_TYPE_MEDIA_GROUP, "group", doc,
-											       node, NULL, error));
+		GDataMediaGroup *group = GDATA_MEDIA_GROUP (_gdata_parsable_new_from_xml_node (GDATA_TYPE_MEDIA_GROUP, doc, node, NULL, error));
 		if (group == NULL)
 			return FALSE;
 
@@ -729,7 +728,7 @@ get_xml (GDataParsable *parsable, GString *xml_string)
 		g_string_append_printf (xml_string, "<gphoto:rotation>%u</gphoto:rotation>", priv->rotation);
 
 	/* media:group */
-	xml = _gdata_parsable_get_xml (GDATA_PARSABLE (priv->media_group), "media:group", FALSE);
+	xml = _gdata_parsable_get_xml (GDATA_PARSABLE (priv->media_group), FALSE);
 	g_string_append (xml_string, xml);
 	g_free (xml);
 
@@ -774,27 +773,6 @@ gdata_picasaweb_file_new (const gchar *id)
 }
 
 /**
- * gdata_picasaweb_file_new_from_xml:
- * @xml: an XML string
- * @length: the length in characters of @xml, or %-1
- * @error: a #GError, or %NULL
- *
- * Creates a new #GDataPicasaWebFile from an XML string. If @length is %-1, the length of
- * the string will be calculated.
- *
- * Errors from #GDataParserError can be returned if problems are found in the XML.
- *
- * Return value: a new #GDataPicasaWebFile, or %NULL; unref with g_object_unref()
- *
- * Since: 0.4.0
- **/
-GDataPicasaWebFile *
-gdata_picasaweb_file_new_from_xml (const gchar *xml, gint length, GError **error)
-{
-	return GDATA_PICASAWEB_FILE (_gdata_entry_new_from_xml (GDATA_TYPE_PICASAWEB_FILE, xml, length, error));
-}
-
-/**
  * gdata_picasaweb_file_get_edited:
  * @self: a #GDataPicasaWebFile
  * @edited: a #GTimeVal
diff --git a/gdata/services/picasaweb/gdata-picasaweb-file.h b/gdata/services/picasaweb/gdata-picasaweb-file.h
index a7f1763..e3d3c8f 100644
--- a/gdata/services/picasaweb/gdata-picasaweb-file.h
+++ b/gdata/services/picasaweb/gdata-picasaweb-file.h
@@ -65,7 +65,6 @@ typedef struct {
 GType gdata_picasaweb_file_get_type (void) G_GNUC_CONST;
 
 GDataPicasaWebFile *gdata_picasaweb_file_new (const gchar *id) G_GNUC_WARN_UNUSED_RESULT;
-GDataPicasaWebFile *gdata_picasaweb_file_new_from_xml (const gchar *xml, gint length, GError **error) G_GNUC_WARN_UNUSED_RESULT;
 
 void gdata_picasaweb_file_get_edited (GDataPicasaWebFile *self, GTimeVal *edited);
 const gchar *gdata_picasaweb_file_get_version (GDataPicasaWebFile *self);
diff --git a/gdata/services/picasaweb/gdata-picasaweb-service.c b/gdata/services/picasaweb/gdata-picasaweb-service.c
index c343a4a..a8ffa6b 100644
--- a/gdata/services/picasaweb/gdata-picasaweb-service.c
+++ b/gdata/services/picasaweb/gdata-picasaweb-service.c
@@ -306,7 +306,7 @@ gdata_picasaweb_service_upload_file (GDataPicasaWebService *self, GDataPicasaWeb
 		return NULL;
 	}
 
-	entry_xml = gdata_entry_get_xml (GDATA_ENTRY (file));
+	entry_xml = gdata_parsable_get_xml (GDATA_PARSABLE (file));
 
 	/* Check for cancellation */
 	if (g_cancellable_set_error_if_cancelled (cancellable, error) == TRUE) {
@@ -393,5 +393,6 @@ gdata_picasaweb_service_upload_file (GDataPicasaWebService *self, GDataPicasaWeb
 
 	g_assert (message->response_body->data != NULL);
 
-	return gdata_picasaweb_file_new_from_xml (message->response_body->data, (gint) message->response_body->length, error);
+	return GDATA_PICASAWEB_FILE (gdata_parsable_new_from_xml (GDATA_TYPE_PICASAWEB_FILE, message->response_body->data,
+								  (gint) message->response_body->length, error));
 }
diff --git a/gdata/services/youtube/gdata-youtube-control.c b/gdata/services/youtube/gdata-youtube-control.c
index 9821dc8..a45cb13 100644
--- a/gdata/services/youtube/gdata-youtube-control.c
+++ b/gdata/services/youtube/gdata-youtube-control.c
@@ -70,6 +70,8 @@ gdata_youtube_control_class_init (GDataYouTubeControlClass *klass)
 	parsable_class->parse_xml = parse_xml;
 	parsable_class->get_xml = get_xml;
 	parsable_class->get_namespaces = get_namespaces;
+	parsable_class->element_name = "control";
+	parsable_class->element_namespace = "app";
 }
 
 static void
@@ -106,8 +108,7 @@ parse_xml (GDataParsable *parsable, xmlDoc *doc, xmlNode *node, gpointer user_da
 		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, "state", doc,
-												   node, NULL, error));
+		GDataYouTubeState *state = GDATA_YOUTUBE_STATE (_gdata_parsable_new_from_xml_node (GDATA_TYPE_YOUTUBE_STATE, doc, node, NULL, error));
 		if (state == NULL)
 			return FALSE;
 
diff --git a/gdata/services/youtube/gdata-youtube-group.c b/gdata/services/youtube/gdata-youtube-group.c
index df11a74..8e90617 100644
--- a/gdata/services/youtube/gdata-youtube-group.c
+++ b/gdata/services/youtube/gdata-youtube-group.c
@@ -93,7 +93,7 @@ parse_xml (GDataParsable *parsable, xmlDoc *doc, xmlNode *node, gpointer user_da
 
 	if (xmlStrcmp (node->name, (xmlChar*) "content") == 0) {
 		/* media:content */
-		GDataYouTubeContent *content = GDATA_YOUTUBE_CONTENT (_gdata_parsable_new_from_xml_node (GDATA_TYPE_YOUTUBE_CONTENT, "content", doc,
+		GDataYouTubeContent *content = GDATA_YOUTUBE_CONTENT (_gdata_parsable_new_from_xml_node (GDATA_TYPE_YOUTUBE_CONTENT, doc,
 													 node, NULL, error));
 		if (content == NULL)
 			return FALSE;
@@ -101,7 +101,7 @@ parse_xml (GDataParsable *parsable, xmlDoc *doc, xmlNode *node, gpointer user_da
 		_gdata_media_group_add_content (GDATA_MEDIA_GROUP (self), GDATA_MEDIA_CONTENT (content));
 	} 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, "credit", doc,
+		GDataYouTubeCredit *credit = GDATA_YOUTUBE_CREDIT (_gdata_parsable_new_from_xml_node (GDATA_TYPE_YOUTUBE_CREDIT, doc,
 												      node, NULL, error));
 		if (credit == NULL)
 			return FALSE;
diff --git a/gdata/services/youtube/gdata-youtube-service.c b/gdata/services/youtube/gdata-youtube-service.c
index 2fd82cd..855bda4 100644
--- a/gdata/services/youtube/gdata-youtube-service.c
+++ b/gdata/services/youtube/gdata-youtube-service.c
@@ -648,7 +648,7 @@ gdata_youtube_service_upload_video (GDataYouTubeService *self, GDataYouTubeVideo
 		return NULL;
 	}
 
-	entry_xml = gdata_entry_get_xml (GDATA_ENTRY (video));
+	entry_xml = gdata_parsable_get_xml (GDATA_PARSABLE (video));
 
 	/* Check for cancellation */
 	if (g_cancellable_set_error_if_cancelled (cancellable, error) == TRUE) {
@@ -735,7 +735,8 @@ gdata_youtube_service_upload_video (GDataYouTubeService *self, GDataYouTubeVideo
 
 	g_assert (message->response_body->data != NULL);
 
-	return gdata_youtube_video_new_from_xml (message->response_body->data, (gint) message->response_body->length, error);
+	return GDATA_YOUTUBE_VIDEO (gdata_parsable_new_from_xml (GDATA_TYPE_YOUTUBE_VIDEO, message->response_body->data,
+								 (gint) message->response_body->length, error));
 }
 
 /**
diff --git a/gdata/services/youtube/gdata-youtube-state.c b/gdata/services/youtube/gdata-youtube-state.c
index eee7952..80f722c 100644
--- a/gdata/services/youtube/gdata-youtube-state.c
+++ b/gdata/services/youtube/gdata-youtube-state.c
@@ -71,6 +71,8 @@ gdata_youtube_state_class_init (GDataYouTubeStateClass *klass)
 	parsable_class->pre_parse_xml = pre_parse_xml;
 	parsable_class->parse_xml = parse_xml;
 	parsable_class->get_namespaces = get_namespaces;
+	parsable_class->element_name = "state";
+	parsable_class->element_namespace = "yt";
 
 	/**
 	 * GDataYouTubeState:name:
diff --git a/gdata/services/youtube/gdata-youtube-video.c b/gdata/services/youtube/gdata-youtube-video.c
index f6c7561..d8e8fd6 100644
--- a/gdata/services/youtube/gdata-youtube-video.c
+++ b/gdata/services/youtube/gdata-youtube-video.c
@@ -590,25 +590,6 @@ gdata_youtube_video_new (const gchar *id)
 	return video;
 }
 
-/**
- * gdata_youtube_video_new_from_xml:
- * @xml: an XML string
- * @length: the length in characters of @xml, or %-1
- * @error: a #GError, or %NULL
- *
- * Creates a new #GDataYouTubeVideo from an XML string. If @length is %-1, the length of
- * the string will be calculated.
- *
- * Errors from #GDataParserError can be returned if problems are found in the XML.
- *
- * Return value: a new #GDataYouTubeVideo, or %NULL; unref with g_object_unref()
- **/
-GDataYouTubeVideo *
-gdata_youtube_video_new_from_xml (const gchar *xml, gint length, GError **error)
-{
-	return GDATA_YOUTUBE_VIDEO (_gdata_entry_new_from_xml (GDATA_TYPE_YOUTUBE_VIDEO, xml, length, error));
-}
-
 static gboolean
 parse_xml (GDataParsable *parsable, xmlDoc *doc, xmlNode *node, gpointer user_data, GError **error)
 {
@@ -616,8 +597,7 @@ parse_xml (GDataParsable *parsable, xmlDoc *doc, xmlNode *node, gpointer user_da
 
 	if (xmlStrcmp (node->name, (xmlChar*) "group") == 0) {
 		/* media:group */
-		GDataMediaGroup *group = GDATA_MEDIA_GROUP (_gdata_parsable_new_from_xml_node (GDATA_TYPE_YOUTUBE_GROUP, "group", doc,
-											       node, NULL, error));
+		GDataMediaGroup *group = GDATA_MEDIA_GROUP (_gdata_parsable_new_from_xml_node (GDATA_TYPE_YOUTUBE_GROUP, doc, node, NULL, error));
 		if (group == NULL)
 			return FALSE;
 
@@ -742,7 +722,7 @@ parse_xml (GDataParsable *parsable, xmlDoc *doc, xmlNode *node, gpointer user_da
 		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, "control", doc,
+		GDataYouTubeControl *control = GDATA_YOUTUBE_CONTROL (_gdata_parsable_new_from_xml_node (GDATA_TYPE_YOUTUBE_CONTROL, doc,
 													 node, NULL, error));
 		if (control == NULL)
 			return FALSE;
@@ -779,13 +759,16 @@ post_parse_xml (GDataParsable *parsable, gpointer user_data, GError **error)
 static void
 get_xml (GDataParsable *parsable, GString *xml_string)
 {
+	gchar *xml;
 	GDataYouTubeVideoPrivate *priv = GDATA_YOUTUBE_VIDEO (parsable)->priv;
 
 	/* Chain up to the parent class */
 	GDATA_PARSABLE_CLASS (gdata_youtube_video_parent_class)->get_xml (parsable, xml_string);
 
 	/* media:group */
-	g_string_append (xml_string, _gdata_parsable_get_xml (GDATA_PARSABLE (priv->media_group), "media:group", FALSE));
+	xml = _gdata_parsable_get_xml (GDATA_PARSABLE (priv->media_group), FALSE);
+	g_string_append (xml_string, xml);
+	g_free (xml);
 
 	if (priv->location != NULL) {
 		gchar *location = g_markup_escape_text (priv->location, -1);
@@ -803,7 +786,9 @@ get_xml (GDataParsable *parsable, GString *xml_string)
 		g_string_append (xml_string, "<yt:noembed/>");
 
 	/* app:control */
-	g_string_append (xml_string, _gdata_parsable_get_xml (GDATA_PARSABLE (priv->youtube_control), "app:control", FALSE));
+	xml = _gdata_parsable_get_xml (GDATA_PARSABLE (priv->youtube_control), FALSE);
+	g_string_append (xml_string, xml);
+	g_free (xml);
 
 	/* TODO:
 	 * - georss:where
diff --git a/gdata/services/youtube/gdata-youtube-video.h b/gdata/services/youtube/gdata-youtube-video.h
index f886ff8..37396b1 100644
--- a/gdata/services/youtube/gdata-youtube-video.h
+++ b/gdata/services/youtube/gdata-youtube-video.h
@@ -63,7 +63,6 @@ typedef struct {
 GType gdata_youtube_video_get_type (void) G_GNUC_CONST;
 
 GDataYouTubeVideo *gdata_youtube_video_new (const gchar *id) G_GNUC_WARN_UNUSED_RESULT;
-GDataYouTubeVideo *gdata_youtube_video_new_from_xml (const gchar *xml, gint length, GError **error) G_GNUC_WARN_UNUSED_RESULT;
 
 guint gdata_youtube_video_get_view_count (GDataYouTubeVideo *self);
 guint gdata_youtube_video_get_favorite_count (GDataYouTubeVideo *self);
diff --git a/gdata/tests/calendar.c b/gdata/tests/calendar.c
index 0bd07b5..dd4a305 100644
--- a/gdata/tests/calendar.c
+++ b/gdata/tests/calendar.c
@@ -267,7 +267,7 @@ test_insert_simple (void)
 	g_object_unref (when);
 
 	/* Check the XML */
-	xml = gdata_entry_get_xml (GDATA_ENTRY (event));
+	xml = gdata_parsable_get_xml (GDATA_PARSABLE (event));
 	g_assert_cmpstr (xml, ==,
 			 "<entry xmlns='http://www.w3.org/2005/Atom' "
 			 	"xmlns:gd='http://schemas.google.com/g/2005' "
@@ -312,7 +312,7 @@ test_xml_dates (void)
 	gchar *xml;
 	GError *error = NULL;
 
-	event = gdata_calendar_event_new_from_xml (
+	event = GDATA_CALENDAR_EVENT (gdata_parsable_new_from_xml (GDATA_TYPE_CALENDAR_EVENT,
 		"<entry xmlns='http://www.w3.org/2005/Atom' "
 		 	"xmlns:gd='http://schemas.google.com/g/2005' "
 		 	"xmlns:gCal='http://schemas.google.com/gCal/2005' "
@@ -323,7 +323,7 @@ test_xml_dates (void)
 		 	"<gd:when startTime='2009-04-17'/>"
 		 	"<gd:when startTime='2009-04-17T15:00:00Z'/>"
 		 	"<gd:when startTime='2009-04-27' endTime='20090506'/>"
-		 "</entry>", -1, &error);
+		 "</entry>", -1, &error));
 	g_assert_no_error (error);
 	g_assert (GDATA_IS_ENTRY (event));
 	g_clear_error (&error);
@@ -373,7 +373,7 @@ test_xml_dates (void)
 	g_assert (gdata_gd_when_get_reminders (when) == NULL);
 
 	/* Check the XML */
-	xml = gdata_entry_get_xml (GDATA_ENTRY (event));
+	xml = gdata_parsable_get_xml (GDATA_PARSABLE (event));
 	g_assert_cmpstr (xml, ==,
 			 "<entry xmlns='http://www.w3.org/2005/Atom' "
 			 	"xmlns:gd='http://schemas.google.com/g/2005' "
@@ -402,7 +402,7 @@ test_xml_recurrence (void)
 	GError *error = NULL;
 	gchar *id, *uri;
 
-	event = gdata_calendar_event_new_from_xml (
+	event = GDATA_CALENDAR_EVENT (gdata_parsable_new_from_xml (GDATA_TYPE_CALENDAR_EVENT,
 		"<entry xmlns='http://www.w3.org/2005/Atom' "
 		 	"xmlns:gd='http://schemas.google.com/g/2005' "
 		 	"xmlns:gCal='http://schemas.google.com/gCal/2005' "
@@ -442,7 +442,7 @@ test_xml_recurrence (void)
 			"</gd:when>"
 			"<gd:who rel='http://schemas.google.com/g/2005#event.organizer' valueString='GData Test' email='libgdata test googlemail com'/>"
 			"<gd:where valueString=''/>"
-		"</entry>", -1, &error);
+		"</entry>", -1, &error));
 	g_assert_no_error (error);
 	g_assert (GDATA_IS_ENTRY (event));
 	g_clear_error (&error);
@@ -577,7 +577,7 @@ test_acls_insert_rule (void)
 	g_assert_cmpstr (scope_value, ==, "darcy gmail com");
 
 	/* Check the XML */
-	xml = gdata_entry_get_xml (GDATA_ENTRY (rule));
+	xml = gdata_parsable_get_xml (GDATA_PARSABLE (rule));
 	g_assert_cmpstr (xml, ==,
 			 "<entry xmlns='http://www.w3.org/2005/Atom' "
 			 	"xmlns:gd='http://schemas.google.com/g/2005' "
diff --git a/gdata/tests/contacts.c b/gdata/tests/contacts.c
index fc3873b..b3cc5eb 100644
--- a/gdata/tests/contacts.c
+++ b/gdata/tests/contacts.c
@@ -169,7 +169,7 @@ test_insert_simple (void)
 	g_object_unref (postal_address);
 
 	/* Check the XML */
-	xml = gdata_entry_get_xml (GDATA_ENTRY (contact));
+	xml = gdata_parsable_get_xml (GDATA_PARSABLE (contact));
 	g_assert_cmpstr (xml, ==,
 			 "<entry xmlns='http://www.w3.org/2005/Atom' "
 			 	"xmlns:gd='http://schemas.google.com/g/2005' "
@@ -249,7 +249,7 @@ test_parser_minimal (void)
 
 	g_test_bug ("580330");
 
-	contact = gdata_contacts_contact_new_from_xml (
+	contact = GDATA_CONTACTS_CONTACT (gdata_parsable_new_from_xml (GDATA_TYPE_CONTACTS_CONTACT,
 		"<entry xmlns='http://www.w3.org/2005/Atom' "
 			"xmlns:gd='http://schemas.google.com/g/2005' "
 			"gd:etag='&quot;QngzcDVSLyp7ImA9WxJTFkoITgU.&quot;'>"
@@ -262,7 +262,7 @@ test_parser_minimal (void)
 			"<link rel='self' type='application/atom+xml' href='http://www.google.com/m8/feeds/contacts/libgdata test googlemail com/full/1b46cdd20bfbee3b'/>"
 			"<link rel='edit' type='application/atom+xml' href='http://www.google.com/m8/feeds/contacts/libgdata test googlemail com/full/1b46cdd20bfbee3b'/>"
 			"<gd:email rel='http://schemas.google.com/g/2005#other' address='bob example com'/>"
-		"</entry>", -1, &error);
+		"</entry>", -1, &error));
 	g_assert_no_error (error);
 	g_assert (GDATA_IS_ENTRY (contact));
 	g_clear_error (&error);
@@ -284,7 +284,7 @@ test_photo_has_photo (void)
 	gchar *content_type = NULL;
 	GError *error = NULL;
 
-	contact = gdata_contacts_contact_new_from_xml (
+	contact = GDATA_CONTACTS_CONTACT (gdata_parsable_new_from_xml (GDATA_TYPE_CONTACTS_CONTACT,
 		"<entry xmlns='http://www.w3.org/2005/Atom' "
 			"xmlns:gd='http://schemas.google.com/g/2005'>"
 			"<id>http://www.google.com/m8/feeds/contacts/libgdata test googlemail com/base/1b46cdd20bfbee3b</id>"
@@ -293,7 +293,7 @@ test_photo_has_photo (void)
 			"<title></title>" /* Here's where it all went wrong */
 			"<link rel='http://schemas.google.com/contacts/2008/rel#photo' type='image/*' "
 				"href='http://www.google.com/m8/feeds/photos/media/libgdata test googlemail com/1b46cdd20bfbee3b'/>"
-		"</entry>", -1, &error);
+		"</entry>", -1, &error));
 	g_assert_no_error (error);
 	g_assert (GDATA_IS_ENTRY (contact));
 	g_clear_error (&error);
@@ -310,7 +310,7 @@ test_photo_has_photo (void)
 	g_object_unref (contact);
 
 	/* Try again with a photo */
-	contact = gdata_contacts_contact_new_from_xml (
+	contact = GDATA_CONTACTS_CONTACT (gdata_parsable_new_from_xml (GDATA_TYPE_CONTACTS_CONTACT,
 		"<entry xmlns='http://www.w3.org/2005/Atom' "
 			"xmlns:gd='http://schemas.google.com/g/2005'>"
 			"<id>http://www.google.com/m8/feeds/contacts/libgdata test googlemail com/base/1b46cdd20bfbee3b</id>"
@@ -320,7 +320,7 @@ test_photo_has_photo (void)
 			"<link rel='http://schemas.google.com/contacts/2008/rel#photo' type='image/*' "
 				"href='http://www.google.com/m8/feeds/photos/media/libgdata test googlemail com/1b46cdd20bfbee3b' "
 				"gd:etag='&quot;QngzcDVSLyp7ImA9WxJTFkoITgU.&quot;'/>"
-		"</entry>", -1, &error);
+		"</entry>", -1, &error));
 	g_assert_no_error (error);
 	g_assert (GDATA_IS_ENTRY (contact));
 	g_clear_error (&error);
diff --git a/gdata/tests/general.c b/gdata/tests/general.c
index 3d2e1bc..34297ce 100644
--- a/gdata/tests/general.c
+++ b/gdata/tests/general.c
@@ -82,7 +82,7 @@ test_entry_get_xml (void)
 	g_object_unref (author);
 
 	/* Check the generated XML's OK */
-	xml = gdata_entry_get_xml (entry);
+	xml = gdata_parsable_get_xml (GDATA_PARSABLE (entry));
 	g_assert_cmpstr (xml, ==,
 			 "<entry xmlns='http://www.w3.org/2005/Atom' xmlns:gd='http://schemas.google.com/g/2005'>"
 				 "<title type='text'>Testing title &amp; escaping</title>"
@@ -101,7 +101,7 @@ test_entry_get_xml (void)
 			 "</entry>");
 
 	/* Check again by re-parsing the XML to a GDataEntry */
-	entry2 = gdata_entry_new_from_xml (xml, -1, &error);
+	entry2 = GDATA_ENTRY (gdata_parsable_new_from_xml (GDATA_TYPE_ENTRY, xml, -1, &error));
 	g_assert_no_error (error);
 	g_assert (GDATA_IS_ENTRY (entry2));
 	g_clear_error (&error);
@@ -135,7 +135,7 @@ test_entry_parse_xml (void)
 	GError *error = NULL;
 
 	/* Create an entry from XML with unhandled elements */
-	entry = gdata_entry_new_from_xml (
+	entry = GDATA_ENTRY (gdata_parsable_new_from_xml (GDATA_TYPE_ENTRY,
 		"<entry xmlns='http://www.w3.org/2005/Atom' xmlns:ns='http://example.com/'>"
 			"<title type='text'>Testing unhandled XML</title>"
 			"<updated>2009-01-25T14:07:37.880860Z</updated>"
@@ -144,13 +144,13 @@ test_entry_parse_xml (void)
 			"<foobar>Test!</foobar>"
 			"<barfoo shizzle='zing'/>"
 			"<ns:barfoo shizzle='zing' fo='shizzle'>How about some charactersâ?½</ns:barfoo>"
-		 "</entry>", -1, &error);
+		 "</entry>", -1, &error));
 	g_assert_no_error (error);
 	g_assert (GDATA_IS_ENTRY (entry));
 	g_clear_error (&error);
 
 	/* Now check the outputted XML from the entry still has the unhandled elements */
-	xml = gdata_entry_get_xml (entry);
+	xml = gdata_parsable_get_xml (GDATA_PARSABLE (entry));
 	g_assert_cmpstr (xml, ==,
 			 "<entry xmlns='http://www.w3.org/2005/Atom' xmlns:gd='http://schemas.google.com/g/2005' xmlns:ns='http://example.com/'>"
 				"<title type='text'>Testing unhandled XML</title>"
diff --git a/gdata/tests/picasaweb.c b/gdata/tests/picasaweb.c
index d31edc9..983bfca 100644
--- a/gdata/tests/picasaweb.c
+++ b/gdata/tests/picasaweb.c
@@ -116,7 +116,7 @@ test_upload_simple (void)
 	gdata_entry_add_category (GDATA_ENTRY (photo), category);
 
 	/* Check the XML */
-	xml = gdata_entry_get_xml (GDATA_ENTRY (photo));
+	xml = gdata_parsable_get_xml (GDATA_PARSABLE (photo));
 	g_assert_cmpstr (xml, ==,
 			 "<entry "
 				"xmlns='http://www.w3.org/2005/Atom' "
@@ -299,8 +299,8 @@ test_photo_feed_entry (void)
 
 	g_assert_cmpstr (gdata_entry_get_content (photo_entry), ==,
 			 "http://lh3.ggpht.com/_1kdcGyvOb8c/SfQFWPnuovI/AAAAAAAAAB0/MI0L4Sd11Eg/100_0269.jpg";);
-	g_assert_cmpstr (gdata_entry_get_xml (photo_entry), !=, NULL);
-	g_assert_cmpuint (strlen (gdata_entry_get_xml (photo_entry)), >, 0);
+	g_assert_cmpstr (gdata_parsable_get_xml (GDATA_PARSABLE (photo_entry)), !=, NULL);
+	g_assert_cmpuint (strlen (gdata_parsable_get_xml (GDATA_PARSABLE (photo_entry))), >, 0);
 }
 
 static void
@@ -424,7 +424,7 @@ test_album_feed_entry (void)
 	// g_assert_cmpstr (gdata_entry_get_content (entry), !=, NULL);
 	/* TODO */
 	printf("** WARNING:%s:%d: gdata_entry_get_content(entry) returns null; valid?\n", __FILE__, __LINE__);
-	xml = gdata_entry_get_xml (entry);
+	xml = gdata_parsable_get_xml (GDATA_PARSABLE (entry));
 	g_assert_cmpstr (xml, !=, NULL);
 	g_assert_cmpuint (strlen (xml), >, 0);
 	g_free (xml);
diff --git a/gdata/tests/youtube.c b/gdata/tests/youtube.c
index 55458cc..d80c3cc 100644
--- a/gdata/tests/youtube.c
+++ b/gdata/tests/youtube.c
@@ -148,7 +148,7 @@ get_video_for_related (void)
 	GDataYouTubeVideo *video;
 	GError *error = NULL;
 
-	video = gdata_youtube_video_new_from_xml (
+	video = GDATA_YOUTUBE_VIDEO (gdata_parsable_new_from_xml (GDATA_TYPE_YOUTUBE_VIDEO,
 		"<entry xmlns='http://www.w3.org/2005/Atom' "
 			"xmlns:media='http://search.yahoo.com/mrss/' "
 			"xmlns:yt='http://gdata.youtube.com/schemas/2007' "
@@ -203,7 +203,7 @@ get_video_for_related (void)
 			"<gd:comments>"
 				"<gd:feedLink href='http://gdata.youtube.com/feeds/api/videos/q1UPMEmCqZo/comments' countHint='13021'/>"
 			"</gd:comments>"
-		"</entry>", -1, &error);
+		"</entry>", -1, &error));
 	g_assert_no_error (error);
 	g_assert (GDATA_IS_YOUTUBE_VIDEO (video));
 	g_clear_error (&error);
@@ -288,7 +288,7 @@ test_upload_simple (void)
 	gdata_youtube_video_set_keywords (video, "toast, wedding");
 
 	/* Check the XML */
-	xml = gdata_entry_get_xml (GDATA_ENTRY (video));
+	xml = gdata_parsable_get_xml (GDATA_PARSABLE (video));
 	g_assert_cmpstr (xml, ==,
 			 "<entry xmlns='http://www.w3.org/2005/Atom' "
 				"xmlns:media='http://search.yahoo.com/mrss/' "
@@ -327,7 +327,7 @@ test_parsing_app_control (void)
 	GDataYouTubeState *state;
 	GError *error = NULL;
 
-	video = gdata_youtube_video_new_from_xml (
+	video = GDATA_YOUTUBE_VIDEO (gdata_parsable_new_from_xml (GDATA_TYPE_YOUTUBE_VIDEO,
 		"<entry xmlns='http://www.w3.org/2005/Atom' "
 			"xmlns:media='http://search.yahoo.com/mrss/' "
 			"xmlns:yt='http://gdata.youtube.com/schemas/2007' "
@@ -353,7 +353,7 @@ test_parsing_app_control (void)
 				"<media:credit role='uploader' scheme='urn:youtube'>eluves</media:credit>"
 				"<media:category label='Music' scheme='http://gdata.youtube.com/schemas/2007/categories.cat'>Music</media:category>"
 			"</media:group>"
-		"</entry>", -1, &error);
+		"</entry>", -1, &error));
 	g_assert_no_error (error);
 	g_assert (GDATA_IS_YOUTUBE_VIDEO (video));
 	g_clear_error (&error);
@@ -380,7 +380,7 @@ test_parsing_yt_recorded (void)
 	gchar *xml;
 	GError *error = NULL;
 
-	video = gdata_youtube_video_new_from_xml (
+	video = GDATA_YOUTUBE_VIDEO (gdata_parsable_new_from_xml (GDATA_TYPE_YOUTUBE_VIDEO,
 		"<entry xmlns='http://www.w3.org/2005/Atom' "
 			"xmlns:media='http://video.search.yahoo.com/mrss' "
 			"xmlns:yt='http://gdata.youtube.com/schemas/2007' "
@@ -403,7 +403,7 @@ test_parsing_yt_recorded (void)
 				"<media:category label='Music' scheme='http://gdata.youtube.com/schemas/2007/categories.cat'>Music</media:category>"
 			"</media:group>"
 			"<yt:recorded>2003-08-03</yt:recorded>"
-		"</entry>", -1, &error);
+		"</entry>", -1, &error));
 	g_assert_no_error (error);
 	g_assert (GDATA_IS_YOUTUBE_VIDEO (video));
 	g_clear_error (&error);
@@ -418,7 +418,7 @@ test_parsing_yt_recorded (void)
 	gdata_youtube_video_set_recorded (video, &recorded);
 
 	/* Check the XML */
-	xml = gdata_entry_get_xml (GDATA_ENTRY (video));
+	xml = gdata_parsable_get_xml (GDATA_PARSABLE (video));
 	g_assert_cmpstr (xml, ==,
 			 "<entry xmlns='http://www.w3.org/2005/Atom' "
 				"xmlns:media='http://video.search.yahoo.com/mrss' "
@@ -460,7 +460,7 @@ test_parsing_comments_feed_link (void)
 	GDataGDFeedLink *feed_link;
 	GError *error = NULL;
 
-	video = gdata_youtube_video_new_from_xml (
+	video = gdata_parsable_new_from_xml (GDATA_TYPE_YOUTUBE_VIDEO,
 		"<entry xmlns='http://www.w3.org/2005/Atom' "
 			"xmlns:media='http://search.yahoo.com/mrss/' "
 			"xmlns:yt='http://gdata.youtube.com/schemas/2007' "



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