[xml] xmlwriter and namespaces



Attatched is a patch for xmlwriter to prevent the creation of malformed documents due to the allowance of the same namespace declaration being output multiple times on an element start tag. For example:

xmlTextWriterStartElementNS(ptr, "foo", "baz", "urn::bar");
xmlTextWriterWriteAttributeNS(ptr, "foo", "abc", "urn::bar", "content");
xmlTextWriterWriteAttributeNS(ptr, "foo", "def", "urn::bar", "content");

Ends up creating:
<foo:baz xmlns:foo="urn::bar" foo:abc="content" xmlns:foo="urn::bar" foo:def="content" xmlns:foo="urn::bar"> . . .

rather than:
<foo:baz foo:abc="content" foo:def="content" xmlns:foo="urn::bar">

For performance reasons, unlike .NET, this change only tracks the namespace on the starting element tag rather than within the entire scope of the element the namespace was declared on.

Rob
Index: xmlwriter.c
===================================================================
--- xmlwriter.c (revision 3622)
+++ xmlwriter.c (working copy)
@@ -97,6 +97,7 @@
 static void xmlFreeTextWriterStackEntry(xmlLinkPtr lk);
 static int xmlCmpTextWriterStackEntry(const void *data0,
                                       const void *data1);
+static int xmlTextWriterOutputNSDecl(xmlTextWriterPtr writer);
 static void xmlFreeTextWriterNsStackEntry(xmlLinkPtr lk);
 static int xmlCmpTextWriterNsStackEntry(const void *data0,
                                         const void *data1);
@@ -734,6 +735,11 @@
                 case XML_TEXTWRITER_NONE:
                     break;
                 case XML_TEXTWRITER_NAME:
+                                       /* Output namespace declarations */
+                                       count = xmlTextWriterOutputNSDecl(writer);
+                                       if (count < 0)
+                                               return -1;
+                                       sum += count;
                     count = xmlOutputBufferWriteString(writer->out, ">");
                     if (count < 0)
                         return -1;
@@ -965,6 +971,11 @@
                                        sum += count;
                                        /* fallthrough */
                 case XML_TEXTWRITER_NAME:
+                                       /* Output namespace declarations */
+                                       count = xmlTextWriterOutputNSDecl(writer);
+                                       if (count < 0)
+                                               return -1;
+                                       sum += count;
                     count = xmlOutputBufferWriteString(writer->out, ">");
                     if (count < 0)
                         return -1;
@@ -1055,17 +1066,31 @@
     sum += count;
 
     if (namespaceURI != 0) {
+               xmlTextWriterNsStackEntry *p = (xmlTextWriterNsStackEntry *)
+                       xmlMalloc(sizeof(xmlTextWriterNsStackEntry));
+               if (p == 0) {
+                       xmlWriterErrMsg(writer, XML_ERR_NO_MEMORY,
+                                                       "xmlTextWriterStartElementNS : out of memory!\n");
+                       return -1;
+               }
+
         buf = xmlStrdup(BAD_CAST "xmlns");
         if (prefix != 0) {
             buf = xmlStrcat(buf, BAD_CAST ":");
             buf = xmlStrcat(buf, prefix);
         }
 
-        count = xmlTextWriterWriteAttribute(writer, buf, namespaceURI);
-        xmlFree(buf);
-        if (count < 0)
-            return -1;
-        sum += count;
+               p->prefix = buf;
+               p->uri = xmlStrdup(namespaceURI);
+               if (p->uri == 0) {
+                       xmlWriterErrMsg(writer, XML_ERR_NO_MEMORY,
+                                                       "xmlTextWriterStartElementNS : out of memory!\n");
+                       xmlFree(p);
+                       return -1;
+               }
+               p->elem = xmlListFront(writer->nodes);
+
+               xmlListPushFront(writer->nsstack, p);
     }
 
     return sum;
@@ -1091,22 +1116,37 @@
         return -1;
 
     lk = xmlListFront(writer->nodes);
-    if (lk == 0)
+    if (lk == 0) {
+        xmlListDelete(writer->nsstack);
+               writer->nsstack = NULL;
         return -1;
+    }
 
     p = (xmlTextWriterStackEntry *) xmlLinkGetData(lk);
-    if (p == 0)
+    if (p == 0) {
+        xmlListDelete(writer->nsstack);
+               writer->nsstack = NULL;
         return -1;
+    }
 
     sum = 0;
     switch (p->state) {
         case XML_TEXTWRITER_ATTRIBUTE:
             count = xmlTextWriterEndAttribute(writer);
-            if (count < 0)
+                       if (count < 0) {
+                xmlListDelete(writer->nsstack);
+                               writer->nsstack = NULL;
                 return -1;
+                       }
             sum += count;
             /* fallthrough */
         case XML_TEXTWRITER_NAME:
+                       /* Output namespace declarations */
+                       count = xmlTextWriterOutputNSDecl(writer);
+            if (count < 0)
+                return -1;
+            sum += count;
+
             if (writer->indent) /* next element needs indent */
                 writer->doindent = 1;
             count = xmlOutputBufferWriteString(writer->out, "/>");
@@ -1184,6 +1224,12 @@
             sum += count;
             /* fallthrough */
         case XML_TEXTWRITER_NAME:
+                       /* Output namespace declarations */
+                       count = xmlTextWriterOutputNSDecl(writer);
+            if (count < 0)
+                return -1;
+            sum += count;
+
             count = xmlOutputBufferWriteString(writer->out, ">");
             if (count < 0)
                 return -1;
@@ -1767,6 +1813,56 @@
     if ((writer == NULL) || (name == NULL) || (*name == '\0'))
         return -1;
 
+       /* Handle namespace first in case of error */
+    if (namespaceURI != 0) {
+               xmlTextWriterNsStackEntry nsentry, *curns;
+
+        buf = xmlStrdup(BAD_CAST "xmlns");
+        if (prefix != 0) {
+            buf = xmlStrcat(buf, BAD_CAST ":");
+            buf = xmlStrcat(buf, prefix);
+        }
+
+               nsentry.prefix = buf;
+        nsentry.uri = (xmlChar *)namespaceURI;
+               nsentry.elem = xmlListFront(writer->nodes);
+
+               curns = (xmlTextWriterNsStackEntry *)xmlListSearch(writer->nsstack, (void *)&nsentry);
+               if ((curns != NULL)) {
+                       xmlFree(buf);
+                       if (xmlStrcmp(curns->uri, namespaceURI) == 0) {
+                               /* Namespace already defined on element skip */
+                               buf = NULL;
+                       } else {
+                               /* Prefix mismatch so error out */
+                               return -1;
+                       }
+               }
+
+               /* Do not add namespace decl to list - it is already there */
+               if (buf != NULL) {
+                       p = (xmlTextWriterNsStackEntry *)
+                               xmlMalloc(sizeof(xmlTextWriterNsStackEntry));
+                       if (p == 0) {
+                               xmlWriterErrMsg(writer, XML_ERR_NO_MEMORY,
+                                                               "xmlTextWriterStartAttributeNS : out of 
memory!\n");
+                               return -1;
+                       }
+
+                       p->prefix = buf;
+                       p->uri = xmlStrdup(namespaceURI);
+                       if (p->uri == 0) {
+                               xmlWriterErrMsg(writer, XML_ERR_NO_MEMORY,
+                                                               "xmlTextWriterStartAttributeNS : out of 
memory!\n");
+                               xmlFree(p);
+                               return -1;
+                       }
+                       p->elem = xmlListFront(writer->nodes);
+
+                       xmlListPushFront(writer->nsstack, p);
+               }
+    }
+
     buf = NULL;
     if (prefix != 0) {
         buf = xmlStrdup(prefix);
@@ -1781,34 +1877,6 @@
         return -1;
     sum += count;
 
-    if (namespaceURI != 0) {
-        buf = xmlStrdup(BAD_CAST "xmlns");
-        if (prefix != 0) {
-            buf = xmlStrcat(buf, BAD_CAST ":");
-            buf = xmlStrcat(buf, prefix);
-        }
-
-        p = (xmlTextWriterNsStackEntry *)
-            xmlMalloc(sizeof(xmlTextWriterNsStackEntry));
-        if (p == 0) {
-            xmlWriterErrMsg(writer, XML_ERR_NO_MEMORY,
-                            "xmlTextWriterStartAttributeNS : out of memory!\n");
-            return -1;
-        }
-
-        p->prefix = buf;
-        p->uri = xmlStrdup(namespaceURI);
-        if (p->uri == 0) {
-            xmlWriterErrMsg(writer, XML_ERR_NO_MEMORY,
-                            "xmlTextWriterStartAttributeNS : out of memory!\n");
-            xmlFree(p);
-            return -1;
-        }
-        p->elem = xmlListFront(writer->nodes);
-
-        xmlListPushFront(writer->nsstack, p);
-    }
-
     return sum;
 }
 
@@ -1827,22 +1895,17 @@
     int sum;
     xmlLinkPtr lk;
     xmlTextWriterStackEntry *p;
-    xmlTextWriterNsStackEntry *np;
 
     if (writer == NULL)
         return -1;
 
     lk = xmlListFront(writer->nodes);
     if (lk == 0) {
-        xmlListDelete(writer->nsstack);
-       writer->nsstack = NULL;
         return -1;
     }
 
     p = (xmlTextWriterStackEntry *) xmlLinkGetData(lk);
     if (p == 0) {
-        xmlListDelete(writer->nsstack);
-       writer->nsstack = NULL;
         return -1;
     }
 
@@ -1853,45 +1916,11 @@
 
             count = xmlOutputBufferWrite(writer->out, 1, &writer->qchar);
             if (count < 0) {
-                xmlListDelete(writer->nsstack);
-               writer->nsstack = NULL;
                 return -1;
             }
             sum += count;
-
-            while (!xmlListEmpty(writer->nsstack)) {
-               xmlChar *namespaceURI = NULL;
-               xmlChar *prefix = NULL;
-
-                lk = xmlListFront(writer->nsstack);
-                np = (xmlTextWriterNsStackEntry *) xmlLinkGetData(lk);
-
-               if (np != 0) {
-                   namespaceURI = xmlStrdup(np->uri);
-                   prefix = xmlStrdup(np->prefix);
-               }
-
-               xmlListPopFront(writer->nsstack);
-
-                if (np != 0) {
-                    count =
-                        xmlTextWriterWriteAttribute(writer, prefix,
-                                                    namespaceURI);
-                   xmlFree(namespaceURI);
-                   xmlFree(prefix);
-
-                    if (count < 0) {
-                        xmlListDelete(writer->nsstack);
-                       writer->nsstack = NULL;
-                        return -1;
-                    }
-                    sum += count;
-                }
-            }
             break;
-
         default:
-            xmlListClear(writer->nsstack);
             return -1;
     }
 
@@ -2080,38 +2109,24 @@
 {
     int count;
     int sum;
-    xmlChar *buf;
 
     if ((writer == NULL) || (name == NULL) || (*name == '\0'))
         return -1;
 
-    buf = NULL;
-    if (prefix != NULL) {
-        buf = xmlStrdup(prefix);
-        buf = xmlStrcat(buf, BAD_CAST ":");
-    }
-    buf = xmlStrcat(buf, name);
-
     sum = 0;
-    count = xmlTextWriterWriteAttribute(writer, buf, content);
-    xmlFree(buf);
+    count = xmlTextWriterStartAttributeNS(writer, prefix, name, namespaceURI);
     if (count < 0)
         return -1;
     sum += count;
+    count = xmlTextWriterWriteString(writer, content);
+    if (count < 0)
+        return -1;
+    sum += count;
+    count = xmlTextWriterEndAttribute(writer);
+    if (count < 0)
+        return -1;
+    sum += count;
 
-    if (namespaceURI != NULL) {
-        buf = NULL;
-        buf = xmlStrdup(BAD_CAST "xmlns");
-        if (prefix != NULL) {
-            buf = xmlStrcat(buf, BAD_CAST ":");
-            buf = xmlStrcat(buf, prefix);
-        }
-        count = xmlTextWriterWriteAttribute(writer, buf, namespaceURI);
-        xmlFree(buf);
-        if (count < 0)
-            return -1;
-        sum += count;
-    }
     return sum;
 }
 
@@ -2358,6 +2373,11 @@
                     sum += count;
                     /* fallthrough */
                 case XML_TEXTWRITER_NAME:
+                                       /* Output namespace declarations */
+                                       count = xmlTextWriterOutputNSDecl(writer);
+                                       if (count < 0)
+                                               return -1;
+                                       sum += count;
                     count = xmlOutputBufferWriteString(writer->out, ">");
                     if (count < 0)
                         return -1;
@@ -2592,6 +2612,11 @@
                     sum += count;
                     /* fallthrough */
                 case XML_TEXTWRITER_NAME:
+                                       /* Output namespace declarations */
+                                       count = xmlTextWriterOutputNSDecl(writer);
+                                       if (count < 0)
+                                               return -1;
+                                       sum += count;
                     count = xmlOutputBufferWriteString(writer->out, ">");
                     if (count < 0)
                         return -1;
@@ -4248,6 +4273,51 @@
  */
 
 /**
+ * xmlTextWriterOutputNSDecl:
+ * @writer:  the xmlTextWriterPtr
+ *
+ * Output the current namespace declarations.
+ */
+static int
+xmlTextWriterOutputNSDecl(xmlTextWriterPtr writer)
+{
+    xmlLinkPtr lk;
+    xmlTextWriterNsStackEntry *np;
+    int count;
+    int sum;
+
+       sum = 0;
+       while (!xmlListEmpty(writer->nsstack)) {
+               xmlChar *namespaceURI = NULL;
+               xmlChar *prefix = NULL;
+
+               lk = xmlListFront(writer->nsstack);
+               np = (xmlTextWriterNsStackEntry *) xmlLinkGetData(lk);
+
+               if (np != 0) {
+                       namespaceURI = xmlStrdup(np->uri);
+                       prefix = xmlStrdup(np->prefix);
+               }
+
+               xmlListPopFront(writer->nsstack);
+
+               if (np != 0) {
+                       count = xmlTextWriterWriteAttribute(writer, prefix, namespaceURI);
+                       xmlFree(namespaceURI);
+                       xmlFree(prefix);
+
+                       if (count < 0) {
+                               xmlListDelete(writer->nsstack);
+                               writer->nsstack = NULL;
+                               return -1;
+                       }
+                       sum += count;
+               }
+       }
+       return sum;
+}
+
+/**
  * xmlFreeTextWriterNsStackEntry:
  * @lk:  the xmlLinkPtr
  *
@@ -4300,8 +4370,8 @@
 
     rc = xmlStrcmp(p0->prefix, p1->prefix);
 
-    if (rc == 0)
-        rc = p0->elem == p1->elem;
+       if ((rc != 0) || (p0->elem != p1->elem))
+               rc = -1;
 
     return rc;
 }
@@ -4568,6 +4638,11 @@
         sum = 0;
         switch (p->state) {
             case XML_TEXTWRITER_NAME:
+                               /* Output namespace declarations */
+                               count = xmlTextWriterOutputNSDecl(writer);
+                               if (count < 0)
+                                       return -1;
+                               sum += count;
                 extra[0] = '>';
                 p->state = XML_TEXTWRITER_TEXT;
                 break;


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