[xml] [PATCH 6/6] When sorting, also do DOCTYPE contents.



Puts a "canonical" order on XML_ELEMENT_DECL, XML_ATTRIBUTE_DECL and
XML_ENTITY_DECL nodes.
---
 xmlsave.c |  143 +++++++++++++++++++++++++++++++++++++++++++++++++------------
 1 files changed, 115 insertions(+), 28 deletions(-)

diff --git a/xmlsave.c b/xmlsave.c
index 5e9d1eb..e298559 100644
--- a/xmlsave.c
+++ b/xmlsave.c
@@ -525,6 +525,33 @@ xmlOutputBufferWriteWSNonSig(xmlSaveCtxtPtr ctxt, int extra)
 }
 
 /**
+ * xmlStrPrefixCmp:
+ * @prea: Prefix for first string
+ * @a:    First string
+ * @preb: Prefix for second string
+ * @b:    Second string
+ *
+ * Compare two strings with prefixes, similar to strcmp(3). Strings with
+ * NULL prefixes sort before strings with non-NULL prefixes.
+ */
+static int
+xmlStrPrefixCmp(xmlChar const * prea, xmlChar const * a, xmlChar const * preb, xmlChar const * b)
+{
+    int i;
+    if ((prea != NULL)
+            && (preb == NULL))
+        return +1;
+    if ((preb != NULL)
+            && (prea == NULL))
+        return -1;
+    if ((prea != NULL)
+            && (preb != NULL)
+            && (i = strcmp((char const *) prea, (char const *) preb)) != 0)
+        return i;
+    return strcmp((char const *) a, (char const *) b);
+}
+
+/**
  * xmlNsPtrCmp:
  * @a: pointer to first xmlNsPtr to compare
  * @b: pointer to second xmlNsPtr to compare
@@ -538,19 +565,7 @@ xmlNsPtrCmp(void const * a, void const * b)
 {
     xmlNsPtr x = *((xmlNsPtr *) a);
     xmlNsPtr y = *((xmlNsPtr *) b);
-    int i;
-    if ((x->prefix != NULL)
-            && (y->prefix == NULL))
-        return +1;
-    if ((y->prefix != NULL)
-            && (x->prefix == NULL))
-        return -1;
-    if ((x->prefix != NULL)
-            && (y->prefix != NULL)
-            && (i = strcmp((char const *) x->prefix,
-                    (char const *) y->prefix)) != 0)
-        return i;
-    return strcmp((char const *) x->href, (char const *) y->href);
+    return xmlStrPrefixCmp(x->prefix, x->href, y->prefix, y->href);
 }
 
 /**
@@ -720,19 +735,8 @@ xmlAttrPtrCmp(void const * a, void const * b)
 {
     xmlAttrPtr x = *((xmlAttrPtr *) a);
     xmlAttrPtr y = *((xmlAttrPtr *) b);
-    int i;
-    if ((x->ns != NULL) && (x->ns->prefix != NULL)
-            && ((y->ns == NULL) || (y->ns->prefix == NULL)))
-        return +1;
-    if ((y->ns != NULL) && (y->ns->prefix != NULL)
-            && ((x->ns == NULL) || (x->ns->prefix == NULL)))
-        return -1;
-    if ((x->ns != NULL) && (x->ns->prefix != NULL)
-            && (y->ns != NULL) && (y->ns->prefix != NULL)
-            && (i = strcmp((char const *) x->ns->prefix,
-                    (char const *) y->ns->prefix)) != 0)
-        return i;
-    return strcmp((char const *) x->name, (char const *) y->name);
+    return xmlStrPrefixCmp(x->ns != NULL ? x->ns->prefix : NULL, x->name,
+            y->ns != NULL ? y->ns->prefix : NULL, y->name);
 }
 
 /**
@@ -802,6 +806,56 @@ xmlAttrListDumpOutput(xmlSaveCtxtPtr ctxt, xmlAttrPtr cur) {
 
 
 /**
+ * xmlNodePtrCmp:
+ * @a: pointer to first xmlNodePtr to compare
+ * @b: pointer to second xmlNodePtr to compare
+ *
+ * Compare two xmlNodePtrs whose order in XML documents does not matter, as for
+ * qsort(3). This includes nodes of type XML_ELEMENT_DECL, XML_ATTRIBUTE_DECL
+ * and XML_ENTITY_DECL, to put them in that order, and then order each type
+ * by name.
+ */
+static int
+xmlNodePtrCmp(void const * a, void const * b)
+{
+    xmlNodePtr x = *((xmlNodePtr *) a);
+    xmlNodePtr y = *((xmlNodePtr *) b);
+
+    if (x->type != y->type) {
+        if (x->type == XML_ELEMENT_DECL)
+            return -1;
+        if (y->type == XML_ELEMENT_DECL)
+            return +1;
+        if (x->type == XML_ATTRIBUTE_DECL)
+            return -1;
+        if (y->type == XML_ATTRIBUTE_DECL)
+            return +1;
+        if (x->type == XML_ENTITY_DECL)
+            return -1;
+        if (y->type == XML_ENTITY_DECL)
+            return +1;
+    }
+
+    if (x->type == XML_ELEMENT_DECL) {
+        xmlElementPtr ex = (xmlElementPtr) x;
+        xmlElementPtr ey = (xmlElementPtr) y;
+        return xmlStrPrefixCmp(ex->prefix, ex->name, ey->prefix, ey->name);
+    }
+    else if (x->type == XML_ATTRIBUTE_DECL) {
+        xmlAttributePtr ax = (xmlAttributePtr) x;
+        xmlAttributePtr ay = (xmlAttributePtr) y;
+        return xmlStrPrefixCmp(ax->prefix, ax->name, ay->prefix, ay->name);
+    }
+    else if (x->type == XML_ENTITY_DECL) {
+        xmlEntityPtr ex = (xmlEntityPtr) x;
+        xmlEntityPtr ey = (xmlEntityPtr) y;
+        return strcmp((char const *) ex->name, (char const *) ey->name);
+    }
+
+    return 0;
+}
+
+/**
  * xmlNodeDumpOutputInternalFormatted
  * @ctxt: the context to dump to
  * @cur:  the node to dump
@@ -837,8 +891,41 @@ static void
 xmlNodeListDumpOutput(xmlSaveCtxtPtr ctxt, xmlNodePtr cur) {
     if (cur == NULL) return;
     while (cur != NULL) {
-       xmlNodeDumpOutputInternalFormatted(ctxt, cur);
-       cur = cur->next;
+        if ((ctxt->options & XML_SAVE_SORT) &&
+            ((cur->type == XML_ELEMENT_DECL) ||
+             (cur->type == XML_ATTRIBUTE_DECL) ||
+             (cur->type == XML_ENTITY_DECL)))
+        {
+            int n;
+            int i;
+            xmlNodePtr node;
+            xmlNodePtr next;
+
+            n = 0;
+            for (node = cur;
+                    node != NULL &&
+                    ((node->type == XML_ELEMENT_DECL) ||
+                     (node->type == XML_ATTRIBUTE_DECL) ||
+                     (node->type == XML_ENTITY_DECL));
+                    node = node->next)
+            {
+                ++n;
+            }
+            next = node;
+            xmlNodePtr nodes[n];
+            for (node = cur, i = 0; i < n; node = node->next, ++i) {
+                nodes[i] = node;
+            }
+            qsort(nodes, n, sizeof(nodes[0]), xmlNodePtrCmp);
+            for (i = 0; i < n; ++i) {
+                xmlNodeDumpOutputInternalFormatted(ctxt, nodes[i]);
+            }
+            cur = next;
+        }
+        else {
+            xmlNodeDumpOutputInternalFormatted(ctxt, cur);
+            cur = cur->next;
+        }
     }
 }
 
-- 
1.7.1




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