commit f78de785ab5488561080293a34eac5fc38993bd3
Author: Nick Wellnhofer <wellnhofer@aevum.de>
Date:   Sat Apr 30 17:08:24 2016 +0200

    Fix sort order of XPath namespace nodes
    
    Namespace nodes were simply ignored in the comparison functions.
    
    Fixes bug #314788:
    
    https://bugzilla.gnome.org/show_bug.cgi?id=314788

diff --git a/result/XPath/tests/nssimple b/result/XPath/tests/nssimple
index 8f0dd0e3..5409a86a 100644
--- a/result/XPath/tests/nssimple
+++ b/result/XPath/tests/nssimple
@@ -10,9 +10,9 @@ Set contains 1 nodes:
 Expression: /doc/elem/namespace::*/self::node()[true()]
 Object is a Node Set :
 Set contains 3 nodes:
-1  namespace xml href=http://www.w3.org/XML/1998/namespace
-2  namespace ns1 href=nsuri1
-3  namespace ns2 href=nsuri2
+1  namespace ns1 href=nsuri1
+2  namespace ns2 href=nsuri2
+3  namespace xml href=http://www.w3.org/XML/1998/namespace
 
 ========================
 Expression: //*[namespace::ns1]
diff --git a/xpath.c b/xpath.c
index 58464c12..746e7d17 100644
--- a/xpath.c
+++ b/xpath.c
@@ -182,7 +182,7 @@ xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
 	    }
 	    break;
 	case XML_ATTRIBUTE_NODE:
-	    precedence1 = 1; /* element is owner */
+	    precedence1 = 2; /* element is owner */
 	    miscNode1 = node1;
 	    node1 = node1->parent;
 	    misc = 1;
@@ -199,11 +199,11 @@ xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
 		do {
 		    node1 = node1->prev;
 		    if (node1->type == XML_ELEMENT_NODE) {
-			precedence1 = 3; /* element in prev-sibl axis */
+			precedence1 = 4; /* element in prev-sibl axis */
 			break;
 		    }
 		    if (node1->prev == NULL) {
-			precedence1 = 2; /* element is parent */
+			precedence1 = 3; /* element is parent */
 			/*
 			* URGENT TODO: Are there any cases, where the
 			* parent of such a node is not an element node?
@@ -213,7 +213,7 @@ xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
 		    }
 		} while (1);
 	    } else {
-		precedence1 = 2; /* element is parent */
+		precedence1 = 3; /* element is parent */
 		node1 = node1->parent;
 	    }
 	    if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE) ||
@@ -228,10 +228,14 @@ xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
 	}
 	    break;
 	case XML_NAMESPACE_DECL:
-	    /*
-	    * TODO: why do we return 1 for namespace nodes?
-	    */
-	    return(1);
+	    precedence1 = 1; /* element is owner */
+	    miscNode1 = node1;
+            /* Namespace node parent hack. */
+	    node1 = (xmlNodePtr) ((xmlNsPtr)node1)->next;
+            if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE))
+                return (-2);
+	    misc = 1;
+	    break;
 	default:
 	    break;
     }
@@ -239,7 +243,7 @@ xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
 	case XML_ELEMENT_NODE:
 	    break;
 	case XML_ATTRIBUTE_NODE:
-	    precedence2 = 1; /* element is owner */
+	    precedence2 = 2; /* element is owner */
 	    miscNode2 = node2;
 	    node2 = node2->parent;
 	    misc = 1;
@@ -253,17 +257,17 @@ xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
 		do {
 		    node2 = node2->prev;
 		    if (node2->type == XML_ELEMENT_NODE) {
-			precedence2 = 3; /* element in prev-sibl axis */
+			precedence2 = 4; /* element in prev-sibl axis */
 			break;
 		    }
 		    if (node2->prev == NULL) {
-			precedence2 = 2; /* element is parent */
+			precedence2 = 3; /* element is parent */
 			node2 = node2->parent;
 			break;
 		    }
 		} while (1);
 	    } else {
-		precedence2 = 2; /* element is parent */
+		precedence2 = 3; /* element is parent */
 		node2 = node2->parent;
 	    }
 	    if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) ||
@@ -276,7 +280,14 @@ xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
 	}
 	    break;
 	case XML_NAMESPACE_DECL:
-	    return(1);
+	    precedence2 = 1; /* element is owner */
+	    miscNode2 = node2;
+            /* Namespace node parent hack. */
+	    node2 = (xmlNodePtr) ((xmlNsPtr)node2)->next;
+            if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE))
+                return (-2);
+	    misc = 1;
+	    break;
 	default:
 	    break;
     }
@@ -287,15 +298,26 @@ xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
 		* The ugly case; but normally there aren't many
 		* adjacent non-element nodes around.
 		*/
-		cur = miscNode2->prev;
-		while (cur != NULL) {
-		    if (cur == miscNode1)
-			return(1);
-		    if (cur->type == XML_ELEMENT_NODE)
-			return(-1);
-		    cur = cur->prev;
-		}
-		return (-1);
+                if (precedence1 != 1) {
+                    cur = miscNode2->prev;
+                    while (cur != NULL) {
+                        if (cur == miscNode1)
+                            return(1);
+                        if (cur->type == XML_ELEMENT_NODE)
+                            return(-1);
+                        cur = cur->prev;
+                    }
+                    return (-1);
+                }
+                else {
+                    /*
+                     * The order of namespace nodes was lost by repurposing
+                     * the ->next pointer, but any consistent order will do.
+                     */
+                    xmlNsPtr ns1 = (xmlNsPtr) miscNode1;
+                    xmlNsPtr ns2 = (xmlNsPtr) miscNode2;
+                    return (xmlStrcmp(ns2->prefix, ns1->prefix));
+                }
 	    } else {
 		/*
 		* Evaluate based on higher precedence wrt to the element.
@@ -312,12 +334,12 @@ xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
 	* Special case: One of the helper-elements is contained by the other.
 	* <foo>
 	*   <node2>
-	*     <node1>Text-1(precedence1 == 2)</node1>
+	*     <node1>Text-1(precedence1 == 3)</node1>
 	*   </node2>
-	*   Text-6(precedence2 == 3)
+	*   Text-6(precedence2 == 4)
 	* </foo>
 	*/
-	if ((precedence2 == 3) && (precedence1 > 1)) {
+	if ((precedence2 == 4) && (precedence1 > 2)) {
 	    cur = node1->parent;
 	    while (cur) {
 		if (cur == node2)
@@ -325,7 +347,7 @@ xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
 		cur = cur->parent;
 	    }
 	}
-	if ((precedence1 == 3) && (precedence2 > 1)) {
+	if ((precedence1 == 4) && (precedence2 > 2)) {
 	    cur = node2->parent;
 	    while (cur) {
 		if (cur == node1)
@@ -3276,7 +3298,7 @@ int
 xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
     int depth1, depth2;
     int attr1 = 0, attr2 = 0;
-    xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
+    xmlNodePtr miscNode1 = NULL, miscNode2 = NULL;
     xmlNodePtr cur, root;
 
     if ((node1 == NULL) || (node2 == NULL))
@@ -3287,36 +3309,57 @@ xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
     if (node1 == node2)		/* trivial case */
 	return(0);
     if (node1->type == XML_ATTRIBUTE_NODE) {
+	attr1 = 2;
+	miscNode1 = node1;
+	node1 = node1->parent;
+    }
+    else if (node1->type == XML_NAMESPACE_DECL) {
 	attr1 = 1;
-	attrNode1 = node1;
-	node1 = node1->parent;
+	miscNode1 = node1;
+        /* Namespace node parent hack. */
+        node1 = (xmlNodePtr) ((xmlNsPtr)node1)->next;
+        if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE))
+            return (-2);
     }
     if (node2->type == XML_ATTRIBUTE_NODE) {
+	attr2 = 2;
+	miscNode2 = node2;
+	node2 = node2->parent;
+    }
+    else if (node2->type == XML_NAMESPACE_DECL) {
 	attr2 = 1;
-	attrNode2 = node2;
-	node2 = node2->parent;
+	miscNode2 = node2;
+        /* Namespace node parent hack. */
+        node2 = (xmlNodePtr) ((xmlNsPtr)node2)->next;
+        if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE))
+            return (-2);
     }
     if (node1 == node2) {
 	if (attr1 == attr2) {
-	    /* not required, but we keep attributes in order */
-	    if (attr1 != 0) {
-	        cur = attrNode2->prev;
+	    if (attr1 == 2) {
+	        /* not required, but we keep attributes in order */
+	        cur = miscNode2->prev;
 		while (cur != NULL) {
-		    if (cur == attrNode1)
+		    if (cur == miscNode1)
 		        return (1);
 		    cur = cur->prev;
 		}
 		return (-1);
+	    } else if (attr1 == 1) {
+                /*
+                 * The order of namespace nodes was lost by repurposing the
+                 * ->next pointer, but any consistent order will do.
+                 */
+                xmlNsPtr ns1 = (xmlNsPtr) miscNode1;
+                xmlNsPtr ns2 = (xmlNsPtr) miscNode2;
+                return (xmlStrcmp(ns2->prefix, ns1->prefix));
 	    }
 	    return(0);
 	}
-	if (attr2 == 1)
+	if (attr1 < attr2)
 	    return(1);
 	return(-1);
     }
-    if ((node1->type == XML_NAMESPACE_DECL) ||
-        (node2->type == XML_NAMESPACE_DECL))
-	return(1);
     if (node1 == node2->prev)
 	return(1);
     if (node1 == node2->next)
