[libgdata/gxml] * now with namespace support



commit 82fb4ee684a09c11761218524c8e3b14e487845d
Author: Richard Schwarting <aquarichy gmail com>
Date:   Mon Aug 15 18:31:30 2011 +0200

    * now with namespace support

 gdata/gdata-parsable.c                         |   43 ++----
 gdata/services/youtube/gdata-youtube-service.c |    6 +-
 gdata/tests/common.c                           |  168 ++++++++++++++----------
 3 files changed, 112 insertions(+), 105 deletions(-)
---
diff --git a/gdata/gdata-parsable.c b/gdata/gdata-parsable.c
index 9430723..073af18 100644
--- a/gdata/gdata-parsable.c
+++ b/gdata/gdata-parsable.c
@@ -150,7 +150,7 @@ static gboolean
 real_parse_xml (GDataParsable *parsable, GXmlDomDocument *doc, GXmlDomXNode *node, gpointer user_data, GError **error)
 {
 	gchar *str;
-	xmlNs **namespaces, **namespace;
+	const gchar *prefix, *uri;
 
 	/* Unhandled XML */
 	str = gxml_dom_xnode_to_string (node, 0, 0);
@@ -160,21 +160,15 @@ real_parse_xml (GDataParsable *parsable, GXmlDomDocument *doc, GXmlDomXNode *nod
 	g_message ("Unhandled XML in %s: %s", G_OBJECT_TYPE_NAME (parsable), str);
 
 	/* Get the namespaces */
-	/* TODO:GXML: how do we want to support namespaces? Check higher Core levels? */
-	/* namespaces = xmlGetNsList (doc, node); */
-	/* if (namespaces == NULL) */
-	/* 	return TRUE; */
-
-	/* for (namespace = namespaces; *namespace != NULL; namespace++) { */
-	/* 	if ((*namespace)->prefix != NULL) { */
-	/* 		/\* NOTE: These two g_strdup()s leak, but it's probably acceptable, given that it saves us */
-	/* 		 * g_strdup()ing every other namespace we put in @extra_namespaces. *\/ */
-	/* 		g_hash_table_insert (parsable->priv->extra_namespaces, */
-	/* 		                     g_strdup ((gchar*) ((*namespace)->prefix)), */
-	/* 		                     g_strdup ((gchar*) ((*namespace)->href))); */
-	/* 	} */
-	/* } */
-	/* xmlFree (namespaces); */
+	uri = gxml_dom_xnode_get_namespace_uri (node);
+	prefix = gxml_dom_xnode_get_prefix (node);
+
+	if (uri == NULL || prefix == NULL) {
+		return TRUE;
+	}
+
+	g_hash_table_insert (parsable->priv->extra_namespaces,
+			     g_strdup (prefix), g_strdup (uri));
 
 	return TRUE;
 }
@@ -218,30 +212,19 @@ _gdata_parsable_new_from_xml (GType parsable_type, const gchar *xml, gint length
 	GXmlDomDocument *doc;
 	GXmlDomXNode *node;
 	GDataParsable *parsable;
-	static gboolean libxml_initialised = FALSE;
 
 	g_return_val_if_fail (g_type_is_a (parsable_type, GDATA_TYPE_PARSABLE), NULL);
 	g_return_val_if_fail (xml != NULL && *xml != '\0', NULL);
 	g_return_val_if_fail (length >= -1, NULL);
 	g_return_val_if_fail (error == NULL || *error == NULL, NULL);
 
-	// TODO:GXML: won't need the below anymore!
-	/* /\* Set up libxml. We do this here to avoid introducing a libgdata setup function, which would be unnecessary hassle. This is the only place */
-	/*  * that libxml can be initialised in the library. *\/ */
-	/* if (libxml_initialised == FALSE) { */
-	/* 	/\* Change the libxml memory allocation functions to be GLib's. This means we don't have to re-allocate all the strings we get from */
-	/* 	 * libxml, which cuts down on strdup() calls dramatically. *\/ */
-	/* 	xmlMemSetup ((xmlFreeFunc) g_free, (xmlMallocFunc) g_malloc, (xmlReallocFunc) g_realloc, (xmlStrdupFunc) g_strdup); */
-	/* 	libxml_initialised = TRUE; */
-	/* } */
-
 	if (length == -1)
 		length = strlen (xml);
 
 	/* Parse the XML */
 	GError *error2 = NULL;
 	doc = gxml_dom_document_new_from_string (xml, &error2); // TODO:GXML: do we want to include params for a URL, for encoding, like xmlReadMemory() ?
-	if (error2 != NULL) { // if (doc == NULL) { // TODO:GXML: check if error was set instead?
+	if (error2 != NULL) {
 		g_set_error (error, GDATA_PARSER_ERROR, GDATA_PARSER_ERROR_PARSING_STRING,
 		             /* Translators: the parameter is an error message */
 		             _("Error parsing XML: %s"),
@@ -253,7 +236,7 @@ _gdata_parsable_new_from_xml (GType parsable_type, const gchar *xml, gint length
 	node = GXML_DOM_XNODE (gxml_dom_document_get_document_element (doc));
 	if (node == NULL) {
 		/* XML document's empty */
-		// xmlFreeDoc (doc); // TODO:GXML: should vala->c code have _unref's automatically?  Do I need finalise style methods?
+		g_object_unref (doc);
 		g_set_error (error, GDATA_PARSER_ERROR, GDATA_PARSER_ERROR_EMPTY_DOCUMENT,
 		             _("Error parsing XML: %s"),
 		             /* Translators: this is a dummy error message to be substituted into "Error parsing XML: %s". */
@@ -262,7 +245,7 @@ _gdata_parsable_new_from_xml (GType parsable_type, const gchar *xml, gint length
 	}
 
 	parsable = _gdata_parsable_new_from_xml_node (parsable_type, doc, node, user_data, error);
-	// xmlFreeDoc (doc); // TODO:GXML: unref it?
+	g_object_unref (doc);
 
 	return parsable;
 }
diff --git a/gdata/services/youtube/gdata-youtube-service.c b/gdata/services/youtube/gdata-youtube-service.c
index 0607cb5..4bf5342 100644
--- a/gdata/services/youtube/gdata-youtube-service.c
+++ b/gdata/services/youtube/gdata-youtube-service.c
@@ -360,7 +360,7 @@ parse_error_response (GDataService *self, GDataOperationType operation_type, gui
 	node = GXML_DOM_XNODE (gxml_dom_document_get_document_element (doc));
 	if (node == NULL) {
 		/* XML document's empty; chain up to the parent class */
-		// xmlFreeDoc (doc);
+		g_object_unref (doc);
 		goto parent;
 	}
 
@@ -368,7 +368,7 @@ parse_error_response (GDataService *self, GDataOperationType operation_type, gui
 
 	if (g_strcmp0 (node_name, "errors") != 0) {
 		/* No <errors> element (required); chain up to the parent class */
-		// xmlFreeDoc (doc); //TODO:GXML: figure out what to do with freeing these, g_object_unref?
+		g_object_unref (doc);
 		goto parent;
 	}
 
@@ -408,7 +408,7 @@ parse_error_response (GDataService *self, GDataOperationType operation_type, gui
 				g_free (domain);
 				g_free (code);
 				g_free (location);
-				//xmlFreeDoc (doc);
+				g_object_unref (doc);
 				goto check_error;
 			}
 
diff --git a/gdata/tests/callgrind b/gdata/tests/callgrind
old mode 100755
new mode 100644
diff --git a/gdata/tests/common.c b/gdata/tests/common.c
index a4b0573..90c119c 100644
--- a/gdata/tests/common.c
+++ b/gdata/tests/common.c
@@ -21,8 +21,7 @@
 #include <glib-object.h>
 #include <stdio.h>
 #include <string.h>
-#include <libxml/parser.h>
-#include <libxml/xmlsave.h>
+#include <gxml.h>
 
 #include "common.h"
 
@@ -390,29 +389,30 @@ gdata_test_batch_operation_run_finish (GDataBatchOperation *operation, GAsyncRes
 }
 
 static gboolean
-compare_xml_namespaces (xmlNs *ns1, xmlNs *ns2)
+compare_xml_namespaces (GXmlDomXNode *node1, GXmlDomXNode *node2)
 {
-	if (ns1 == ns2)
+	if (node1 == node2)
 		return TRUE;
 
 	/* Compare various simple properties */
-	if (ns1->type != ns2->type ||
-	    xmlStrcmp (ns1->href, ns2->href) != 0 ||
-	    xmlStrcmp (ns1->prefix, ns2->prefix) != 0 ||
-	    ns1->context != ns2->context) {
+	if (g_strcmp0 (gxml_dom_xnode_get_namespace_uri (node1),
+		       gxml_dom_xnode_get_namespace_uri (node2)) != 0 ||
+	    g_strcmp0 (gxml_dom_xnode_get_prefix (node1),
+		       gxml_dom_xnode_get_prefix (node2)) != 0 ||
+	    gxml_dom_xnode_get_owner_document (node1) != gxml_dom_xnode_get_owner_document (node2)) {
 		return FALSE;
 	}
 
 	return TRUE;
 }
 
-static gboolean compare_xml_nodes (xmlNode *node1, xmlNode *node2);
+static gboolean compare_xml_nodes (GXmlDomXNode *node1, GXmlDomXNode *node2);
 
 static gboolean
-compare_xml_node_lists (xmlNode *list1, xmlNode *list2)
+compare_xml_node_lists (GXmlDomNodeList *list1, GXmlDomNodeList *list2)
 {
 	GHashTable *table;
-	xmlNode *child;
+	GXmlDomXNode *child;
 
 	/* Compare their child elements. We iterate through the first linked list and, for each child node, iterate through the second linked list
 	 * comparing it against each node there. We keep a hashed set of nodes in the second linked list which have already been visited and compared
@@ -424,11 +424,11 @@ compare_xml_node_lists (xmlNode *list1, xmlNode *list2)
 	 * be OK. */
 	table = g_hash_table_new (g_direct_hash, g_direct_equal);
 
-	for (child = list1; child != NULL; child = child->next) {
-		xmlNode *other_child;
+	for (child = gxml_dom_node_list_first (list1); child != NULL; child = gxml_dom_xnode_get_next_sibling (child)) {
+		GXmlDomXNode *other_child;
 		gboolean matched = FALSE;
 
-		for (other_child = list2; other_child != NULL; other_child = other_child->next) {
+		for (other_child = gxml_dom_node_list_first (list2); other_child != NULL; other_child = gxml_dom_xnode_get_next_sibling (other_child)) {
 			if (g_hash_table_lookup (table, other_child) != NULL)
 				continue;
 
@@ -445,7 +445,7 @@ compare_xml_node_lists (xmlNode *list1, xmlNode *list2)
 		}
 	}
 
-	for (child = list2; child != NULL; child = child->next) {
+	for (child = gxml_dom_node_list_first (list2); child != NULL; child = gxml_dom_xnode_get_next_sibling (child)) {
 		if (g_hash_table_lookup (table, child) == NULL) {
 			g_hash_table_destroy (table);
 			return FALSE;
@@ -458,79 +458,101 @@ compare_xml_node_lists (xmlNode *list1, xmlNode *list2)
 }
 
 static gboolean
-compare_xml_nodes (xmlNode *node1, xmlNode *node2)
+compare_xml_nodes (GXmlDomXNode *node1, GXmlDomXNode *node2)
 {
-	GHashTable *table;
-	xmlAttr *attr1, *attr2;
-	xmlNs *ns;
+	GXmlDomXNode *attr1, *attr2;
+	gchar *attr1name;
+	GList *key1;
 
 	if (node1 == node2)
 		return TRUE;
 
 	/* Compare various simple properties */
-	if (node1->type != node2->type ||
-	    xmlStrcmp (node1->name, node2->name) != 0 ||
-	    compare_xml_namespaces (node1->ns, node2->ns) == FALSE ||
-	    xmlStrcmp (node1->content, node2->content) != 0) {
+	if (gxml_dom_xnode_get_node_type (node1) != gxml_dom_xnode_get_node_type (node2) ||
+	    g_strcmp0 (gxml_dom_xnode_get_node_name (node1), gxml_dom_xnode_get_node_name (node2)) != 0 ||
+	    compare_xml_namespaces (node1, node2) == FALSE ||
+	    g_strcmp0 (gxml_dom_element_get_content (GXML_DOM_ELEMENT (node1)),
+		       gxml_dom_element_get_content (GXML_DOM_ELEMENT (node2))) != 0) {
 		return FALSE;
 	}
-
-	/* Compare their attributes. This is done in document order, which isn't strictly correct, since XML specifically does not apply an ordering
-	 * over attributes. However, it suffices for our needs. */
-	for (attr1 = node1->properties, attr2 = node2->properties; attr1 != NULL && attr2 != NULL; attr1 = attr1->next, attr2 = attr2->next) {
-		/* Compare various simple properties */
-		if (attr1->type != attr2->type ||
-		    xmlStrcmp (attr1->name, attr2->name) != 0 ||
-		    compare_xml_namespaces (attr1->ns, attr2->ns) == FALSE ||
-		    attr1->atype != attr2->atype) {
-			return FALSE;
-		}
-
-		/* Compare their child nodes (values represented as text and entity nodes) */
-		if (compare_xml_node_lists (attr1->children, attr2->children) == FALSE)
-			return FALSE;
+	
+	/* Compare their attributes. This is done in document order,
+	 * which isn't strictly correct, since XML specifically does
+	 * not apply an ordering over attributes. However, it suffices
+	 * for our needs. */
+
+	/* This used to iterate over the attributes of node1 and node2 in parallel
+	     if two attrs types did not match,
+	     or their names did not match
+	     or their namespaces did not match
+	     or their atypes did not match
+	       FAIL
+	     if their nodelists (children, an attrs value) do not match
+	       FAIL
+	*/
+	GHashTable *attrs1;
+	GHashTable *attrs2;
+
+	GList *keys1;
+
+	attrs1 = gxml_dom_xnode_get_attributes (node1);
+	attrs2 = gxml_dom_xnode_get_attributes (node2);
+
+	if (g_hash_table_size (attrs1) != g_hash_table_size (attrs2)) {
+		return FALSE;
 	}
 
-	/* Stragglers? */
-	if (attr1 != NULL || attr2 != NULL)
-		return FALSE;
+	keys1 = g_hash_table_get_keys (attrs1);
 
-	/* Compare their namespace definitions regardless of order. Do this by inserting all the definitions from node1 into a hash table, then running
-	 * through the  definitions in node2 and ensuring they exist in the hash table, removing each one from the table as we go. Check there aren't
-	 * any left in the hash table afterwards. */
-	table = g_hash_table_new (g_str_hash, g_str_equal);
+	for (key1 = keys1; key1 != NULL; key1 = key1->next) {
+		attr1name = (gchar*)key1->data;
 
-	for (ns = node1->nsDef; ns != NULL; ns = ns->next) {
-		/* Prefixes should be unique, but I trust libxml about as far as I can throw it. */
-		if (g_hash_table_lookup (table, ns->prefix ? ns->prefix : (gpointer) "") != NULL) {
-			g_hash_table_destroy (table);
+		attr1 = (GXmlDomXNode*)g_hash_table_lookup (attrs1 ,attr1name);
+		attr2 = (GXmlDomXNode*)g_hash_table_lookup (attrs2 ,attr1name);
+
+		if (attr1 == NULL || attr2 == NULL) {
 			return FALSE;
 		}
-
-		g_hash_table_insert (table, ns->prefix ? (gpointer) ns->prefix : (gpointer) "", ns);
-	}
-
-	for (ns = node2->nsDef; ns != NULL; ns = ns->next) {
-		xmlNs *original_ns = g_hash_table_lookup (table, ns->prefix ? ns->prefix : (gpointer) "");
-
-		if (original_ns == NULL ||
-		    compare_xml_namespaces (original_ns, ns) == FALSE) {
-			g_hash_table_destroy (table);
+		
+		if (g_strcmp0 (gxml_dom_xnode_get_node_name (attr1),
+			       gxml_dom_xnode_get_node_name (attr2)) != 0
+		    || compare_xml_namespaces (attr1, attr2) == FALSE) {
 			return FALSE;
 		}
-
-		g_hash_table_remove (table, ns->prefix ? ns->prefix : (gpointer) "");
+		
+		if (compare_xml_node_lists (gxml_dom_xnode_get_child_nodes (attr1),
+					    gxml_dom_xnode_get_child_nodes (attr2)) == FALSE)
+			return FALSE;
 	}
-
-	if (g_hash_table_size (table) != 0) {
-		g_hash_table_destroy (table);
+	
+	// no straglers like we once had, since we now check list size
+
+	/* /\* Compare their namespace definitions regardless of order. Do this by inserting all the definitions from node1 into a hash table, then running */
+	/*  * through the  definitions in node2 and ensuring they exist in the hash table, removing each one from the table as we go. Check there aren't */
+	/*  * any left in the hash table afterwards. *\/ */
+
+	/* The above doesn't reply for now, because, because we only
+	   have one namespace per node right now, while the code here
+	   used to iterate over a list of namespaces.  Here is what we
+	   used to do: 
+  	     made sure all the prefixes used by node1 were unique
+	     remembered them all
+	     went through all the prefixes for node2
+	     if one was not used by node1,
+	       FAIL
+	     if one was also used by node1,
+	       compare namespace
+	       if FAIL
+	         FAIL
+	*/
+	if (compare_xml_namespaces (node1, node2) == FALSE) {
 		return FALSE;
 	}
 
-	g_hash_table_destroy (table);
 
 	/* Compare their child nodes */
-	if (compare_xml_node_lists (node1->children, node2->children) == FALSE)
+	if (compare_xml_node_lists (gxml_dom_xnode_get_child_nodes (node1),
+				    gxml_dom_xnode_get_child_nodes (node2)) == FALSE)
 		return FALSE;
 
 	/* Success! */
@@ -542,26 +564,28 @@ gdata_test_compare_xml (GDataParsable *parsable, const gchar *expected_xml, gboo
 {
 	gboolean success;
 	gchar *parsable_xml;
-	xmlDoc *parsable_doc, *expected_doc;
+	GXmlDomDocument *parsable_doc, *expected_doc;
+	GError *error = NULL;
 
 	/* Get an XML string for the GDataParsable */
 	parsable_xml = gdata_parsable_get_xml (parsable);
 
 	/* Parse both the XML strings */
-	parsable_doc = xmlReadMemory (parsable_xml, strlen (parsable_xml), "/dev/null", NULL, 0);
-	expected_doc = xmlReadMemory (expected_xml, strlen (expected_xml), "/dev/null", NULL, 0);
+	parsable_doc = gxml_dom_document_new_from_string (parsable_xml, &error);
+	expected_doc = gxml_dom_document_new_from_string (expected_xml, &error); // TODO:GXML; grep for 'gxml.*_new_' and make sure we g_object_unref () everything! 
 
 	g_assert (parsable_doc != NULL && expected_doc != NULL);
 
 	/* Recursively compare the two XML trees */
-	success = compare_xml_nodes (xmlDocGetRootElement (parsable_doc), xmlDocGetRootElement (expected_doc));
+	success = compare_xml_nodes (GXML_DOM_XNODE (gxml_dom_document_get_document_element (parsable_doc)),
+				     GXML_DOM_XNODE (gxml_dom_document_get_document_element (expected_doc)));
 	if (success == FALSE && print_error == TRUE) {
 		/* The comparison has failed, so print out the two XML strings for ease of debugging */
 		g_message ("\n\nParsable: %s\n\nExpected: %s\n\n", parsable_xml, expected_xml);
 	}
 
-	xmlFreeDoc (expected_doc);
-	xmlFreeDoc (parsable_doc);
+	g_object_unref (expected_doc);
+	g_object_unref (parsable_doc);
 	g_free (parsable_xml);
 
 	return success;
diff --git a/gdata/tests/massif b/gdata/tests/massif
old mode 100755
new mode 100644
diff --git a/gdata/tests/memcheck b/gdata/tests/memcheck
old mode 100755
new mode 100644



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