apr_xml_to_text: Add style APR_XML_X2T_PARSED to maintain a consistent namespace prefix.


git-svn-id: https://svn.apache.org/repos/asf/apr/apr/trunk@1747941 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/CHANGES b/CHANGES
index 94b992f..80b970d 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,6 +1,10 @@
                                                      -*- coding: utf-8 -*-
 Changes for APR 2.0.0
 
+  *) apr_xml_to_text: Add style APR_XML_X2T_PARSED to maintain a
+     consistent namespace prefix. [Jari Urpalainen
+     <jari.urpalainen nokia.com>]
+
   *) apr_os_proc_mutex-unix: For consistency with other OS native to APR
      types constructors/_put()ers and non-unix mutex mechanisms, always
      destroy the underlying native mutex when apr_proc_mutex_destroy() is
diff --git a/include/apr_xml.h b/include/apr_xml.h
index ffd6716..bd0b100 100644
--- a/include/apr_xml.h
+++ b/include/apr_xml.h
@@ -276,6 +276,7 @@
  *     APR_XML_X2T_INNER               contents only 
  *     APR_XML_X2T_LANG_INNER          xml:lang + inner contents 
  *     APR_XML_X2T_FULL_NS_LANG        FULL + ns defns + xml:lang 
+ *     APR_XML_X2T_PARSED              original prefixes
  * </PRE>
  * @param namespaces The namespace of the current XML element
  * @param ns_map Namespace mapping
@@ -292,6 +293,7 @@
 #define APR_XML_X2T_INNER        1	/**< contents only */
 #define APR_XML_X2T_LANG_INNER   2	/**< xml:lang + inner contents */
 #define APR_XML_X2T_FULL_NS_LANG 3	/**< FULL + ns defns + xml:lang */
+#define APR_XML_X2T_PARSED       4	/**< original prefixes */
 
 /**
  * empty XML element
diff --git a/xml/apr_xml.c b/xml/apr_xml.c
index 8ea2b32..82791f4 100644
--- a/xml/apr_xml.c
+++ b/xml/apr_xml.c
@@ -97,6 +97,25 @@
     return APR_XML_NS_ERROR_UNKNOWN_PREFIX;
 }
 
+/* return original prefix given ns index */
+static const char * find_prefix_name(const apr_xml_elem *elem, int ns, int parent)
+{
+    /*
+    ** Walk up the tree, looking for a namespace scope that defines this
+    ** prefix.
+    */
+    for (; elem; elem = parent ? elem->parent : NULL) {
+       apr_xml_ns_scope *ns_scope = elem->ns_scope;
+
+       for (; ns_scope; ns_scope = ns_scope->next) {
+           if (ns_scope->ns == ns)
+               return ns_scope->prefix;
+       }
+    }
+    /* not found */
+    return "";
+}
+
 static void start_handler(void *userdata, const char *name, const char **attrs)
 {
     apr_xml_parser *parser = userdata;
@@ -538,7 +557,8 @@
 {
     apr_size_t size;
 
-    if (style == APR_XML_X2T_FULL || style == APR_XML_X2T_FULL_NS_LANG) {
+    if (style == APR_XML_X2T_FULL || style == APR_XML_X2T_FULL_NS_LANG ||
+        style == APR_XML_X2T_PARSED) {
         const apr_xml_attr *attr;
 
         size = 0;
@@ -562,11 +582,29 @@
                 size += 11 + strlen(elem->lang) + 1;
             }
         }
+        else if (style == APR_XML_X2T_PARSED) {
+            apr_xml_ns_scope *ns_scope = elem->ns_scope;
+
+            /* compute size of: ' xmlns:%s="%s"' */
+            for (; ns_scope; ns_scope = ns_scope->next) {
+                size += 10 + strlen(find_prefix_name(elem, ns_scope->ns, 0)) +
+                             strlen(APR_XML_GET_URI_ITEM(namespaces, ns_scope->ns));
+            }
+
+            if (elem->lang != NULL) {
+                /* compute size of: ' xml:lang="%s"' */
+                size += 11 + strlen(elem->lang) + 1;
+            }
+        }
 
         if (elem->ns == APR_XML_NS_NONE) {
             /* compute size of: <%s> */
             size += 1 + strlen(elem->name) + 1;
         }
+        else if (style == APR_XML_X2T_PARSED) {
+            /* compute size of: <%s:%s> */
+            size += 3 + strlen(find_prefix_name(elem, elem->ns, 1)) + strlen(elem->name);
+        }
         else {
             int ns = ns_map ? ns_map[elem->ns] : elem->ns;
 
@@ -592,6 +630,10 @@
                 /* compute size of: ' %s="%s"' */
                 size += 1 + strlen(attr->name) + 2 + strlen(attr->value) + 1;
             }
+            else if (style == APR_XML_X2T_PARSED) {
+                /* compute size of: ' %s:%s="%s"' */
+                size += 5 + strlen(find_prefix_name(elem, attr->ns, 1)) + strlen(attr->name) + strlen(attr->value);
+            }
             else {
                 /* compute size of: ' ns%d:%s="%s"' */
                 int ns = ns_map ? ns_map[attr->ns] : attr->ns;
@@ -625,7 +667,7 @@
 
     for (elem = elem->first_child; elem; elem = elem->next) {
         /* the size of the child element plus the CDATA that follows it */
-        size += (elem_size(elem, APR_XML_X2T_FULL, NULL, ns_map) +
+        size += (elem_size(elem, style == APR_XML_X2T_PARSED ? APR_XML_X2T_PARSED : APR_XML_X2T_FULL, NULL, ns_map) +
                  text_size(elem->following_cdata.first));
     }
 
@@ -649,13 +691,17 @@
     apr_size_t len;
     int ns;
 
-    if (style == APR_XML_X2T_FULL || style == APR_XML_X2T_FULL_NS_LANG) {
+    if (style == APR_XML_X2T_FULL || style == APR_XML_X2T_FULL_NS_LANG ||
+        style == APR_XML_X2T_PARSED) {
         int empty = APR_XML_ELEM_IS_EMPTY(elem);
         const apr_xml_attr *attr;
 
         if (elem->ns == APR_XML_NS_NONE) {
             len = sprintf(s, "<%s", elem->name);
         }
+        else if (style == APR_XML_X2T_PARSED) {
+            len = sprintf(s, "<%s:%s", find_prefix_name(elem, elem->ns, 1), elem->name);
+        }
         else {
             ns = ns_map ? ns_map[elem->ns] : elem->ns;
             len = sprintf(s, "<ns%d:%s", ns, elem->name);
@@ -663,8 +709,13 @@
         s += len;
 
         for (attr = elem->attr; attr; attr = attr->next) {
-            if (attr->ns == APR_XML_NS_NONE)
+            if (attr->ns == APR_XML_NS_NONE) {
                 len = sprintf(s, " %s=\"%s\"", attr->name, attr->value);
+            }
+            else if (style == APR_XML_X2T_PARSED) {
+                len = sprintf(s, " %s:%s=\"%s\"",
+                              find_prefix_name(elem, attr->ns, 1), attr->name, attr->value);
+            }
             else {
                 ns = ns_map ? ns_map[attr->ns] : attr->ns;
                 len = sprintf(s, " ns%d:%s=\"%s\"", ns, attr->name, attr->value);
@@ -692,6 +743,19 @@
             }
         }
 
+        else if (style == APR_XML_X2T_PARSED) {
+            apr_xml_ns_scope *ns_scope = elem->ns_scope;
+
+            for (; ns_scope; ns_scope = ns_scope->next) {
+                const char *prefix = find_prefix_name(elem, ns_scope->ns, 0);
+
+                len = sprintf(s, " xmlns%s%s=\"%s\"",
+                              *prefix ? ":" : "", *prefix ? prefix : "",
+                              APR_XML_GET_URI_ITEM(namespaces, ns_scope->ns));
+                s += len;
+            }
+        }
+
         /* no more to do. close it up and go. */
         if (empty) {
             *s++ = '/';
@@ -715,14 +779,20 @@
     s = write_text(s, elem->first_cdata.first);
 
     for (child = elem->first_child; child; child = child->next) {
-        s = write_elem(s, child, APR_XML_X2T_FULL, NULL, ns_map);
+        s = write_elem(s, child,
+                       style == APR_XML_X2T_PARSED ? APR_XML_X2T_PARSED : APR_XML_X2T_FULL,
+                       NULL, ns_map);
         s = write_text(s, child->following_cdata.first);
     }
 
-    if (style == APR_XML_X2T_FULL || style == APR_XML_X2T_FULL_NS_LANG) {
+    if (style == APR_XML_X2T_FULL || style == APR_XML_X2T_FULL_NS_LANG ||
+        style == APR_XML_X2T_PARSED) {
         if (elem->ns == APR_XML_NS_NONE) {
             len = sprintf(s, "</%s>", elem->name);
         }
+        else if (style == APR_XML_X2T_PARSED) {
+            len = sprintf(s, "</%s:%s>", find_prefix_name(elem, elem->ns, 1), elem->name);
+        }
         else {
             ns = ns_map ? ns_map[elem->ns] : elem->ns;
             len = sprintf(s, "</ns%d:%s>", ns, elem->name);