[gxml] Improved TwDocument writer default namespaces handling



commit 295d6c0c613aa8db4669e4398b9d66088d0008b9
Author: Daniel Espinosa <esodan gmail com>
Date:   Wed May 13 15:49:20 2015 -0500

    Improved TwDocument writer default namespaces handling
    
    * On GXml.Element with a default namespace (prefix = NULL)
      all children are set to use it
    * Detects if a given namespace is already declared in parent
      nodes to avoid to declare more than once

 gxml/TwDocument.vala    |   74 ++++++++++++++++++++++++++-------
 test/TwElementTest.vala |  104 +++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 162 insertions(+), 16 deletions(-)
---
diff --git a/gxml/TwDocument.vala b/gxml/TwDocument.vala
index 7f6bdcc..11cf037 100644
--- a/gxml/TwDocument.vala
+++ b/gxml/TwDocument.vala
@@ -109,10 +109,11 @@ public class GXml.TwDocument : GXml.TwNode, GXml.Document
     if (root == null) {
       tw.end_document ();
     }
+    var dns = new ArrayList<string> ();
 #if DEBUG
     GLib.message ("Starting writting Document Root node");
 #endif
-    start_node (tw, root, true);
+    start_node (tw, root, true, ref dns);
 #if DEBUG
     GLib.message ("Ending writting Document Root node");
 #endif
@@ -123,7 +124,7 @@ public class GXml.TwDocument : GXml.TwNode, GXml.Document
     tw.end_document ();
     tw.flush ();
   }
-  public virtual void start_node (Xml.TextWriter tw, GXml.Node node, bool root)
+  public virtual void start_node (Xml.TextWriter tw, GXml.Node node, bool root, ref Gee.ArrayList<string> 
declared_ns)
   {
     int size = 0;
 #if DEBUG
@@ -139,20 +140,34 @@ public class GXml.TwDocument : GXml.TwNode, GXml.Document
         if (node.document.namespaces.size > 0) {
           var dns = node.document.namespaces.get (0);
           assert (dns != null);
-          if (prefix_default_ns)
+          if (prefix_default_ns) {
             tw.start_element_ns (dns.prefix, node.name, dns.uri);
+            declared_ns.add (dns.uri);
+#if DEBUG
+              GLib.message (@"Declared NS: '$(dns.uri)' Total declared = $(declared_ns.size.to_string ())");
+#endif
+          }
           else {
-            // Write default namespace no prefix
             tw.start_element (node.name);
             if (dns.prefix == null)
-              tw.write_attribute ("xmlns",dns.uri);
+              tw.write_attribute ("xmlns",dns.uri);// Write default namespace no prefix
             else
               tw.write_attribute ("xmlns:"+dns.prefix,dns.uri);
+            // Add to declared namespaces
+            declared_ns.add (dns.uri);
+#if DEBUG
+              GLib.message (@"Declared NS: $(dns.uri) Total declared = $(declared_ns.size.to_string ())");
+#endif
           }
           if (node.document.namespaces.size > 1 && node.document.ns_top) {
             for (int i = 1; i < node.document.namespaces.size; i++) {
               GXml.Namespace ns = node.document.namespaces.get (i);
+              if (ns.prefix == null) continue;
               tw.write_attribute ("xmlns:"+ns.prefix, ns.uri);
+              declared_ns.add (ns.uri);
+#if DEBUG
+              GLib.message (@"Declared NS: '$(ns.uri)' Total declared = $(declared_ns.size.to_string ())");
+#endif
             }
           }
         }
@@ -162,22 +177,43 @@ public class GXml.TwDocument : GXml.TwNode, GXml.Document
       else {
         if (node.namespaces.size > 0) {
 #if DEBUG
-      GLib.message ("Starting Element: start with NS");
+      GLib.message (@"Starting Element: '$(node.name)' start with NS");
+#endif
+          if (node.document.ns_uri () == node.ns_uri ()) {
+#if DEBUG
+      GLib.message (@"Node '$(node.name)' Have Default NS");
 #endif
-          if (node.document.namespaces.first ().uri == node.ns_uri ()) {
             if (node.document.prefix_default_ns)  // Default NS at root element
               tw.start_element_ns (node.ns_prefix (), node.name, null);
             else // Don't prefix. Using default namespace and prefix_default_ns = false
               tw.start_element (node.name);
           }
-          else
-            if (node.document.ns_top)
-              tw.start_element_ns (node.ns_prefix (), node.name, null);
-            else
+          else {
+#if DEBUG
+      GLib.message (@"No default NS in use for Node '$(node.name)'. Ns = '$(node.ns_uri ())'");
+#endif
+            if (node.ns_prefix () == null && !declared_ns.contains (node.ns_uri ())) {// Its a default ns 
for children
               tw.start_element_ns (node.ns_prefix (), node.name, node.ns_uri ());
+              declared_ns.add (node.ns_uri ());
+#if DEBUG
+              GLib.message (@"Declared NS: '$(node.ns_uri ())' Total declared = $(declared_ns.size.to_string 
())");
+#endif
+            }
+            else {
+              if (node.document.ns_top || declared_ns.contains (node.ns_uri ()))
+                tw.start_element_ns (node.ns_prefix (), node.name, null);
+              else {
+                tw.start_element_ns (node.ns_prefix (), node.name, node.ns_uri ());
+                declared_ns.add (node.ns_uri ());
+#if DEBUG
+              GLib.message (@"Declared NS: $(node.ns_uri ()) Total declared = $(declared_ns.size.to_string 
())");
+#endif
+              }
+            }
+          }
         } else {
 #if DEBUG
-      GLib.message ("Starting Element: start no NS: Check for default prefix_default_ns enabled");
+      GLib.message (@"Starting Element: '$(node.name)' : start no NS: Check for default prefix_default_ns 
enabled");
 #endif
           if (node.document.prefix_default_ns)
             tw.start_element_ns (node.document.ns_prefix (), node.name, null);
@@ -186,18 +222,18 @@ public class GXml.TwDocument : GXml.TwNode, GXml.Document
         }
       }
 #if DEBUG
-    GLib.message ("Starting Element: writting attributes");
+    GLib.message (@"Starting Element '$(node.name)': writting attributes");
 #endif
       foreach (GXml.Node attr in node.attrs.values) {
         if (attr.namespaces.size > 0) {
 #if DEBUG
-    GLib.message ("Starting Element: write attribute with NS");
+    GLib.message (@"Starting Element '$(node.name)': write attribute '$(attr.name)' with NS");
 #endif
           size += tw.write_attribute_ns (attr.ns_prefix (), attr.name, attr.ns_uri (), attr.value);
         }
         else {
 #if DEBUG
-    GLib.message ("Starting Element: write attribute no NS");
+    GLib.message (@"Starting Element '$(node.name)': write attribute '$(attr.name)' no NS");
 #endif
           size += tw.write_attribute (attr.name, attr.value);
         }
@@ -215,7 +251,13 @@ public class GXml.TwDocument : GXml.TwNode, GXml.Document
 #if DEBUG
     GLib.message (@"Starting Child Element: writting Node '$(n.name)'");
 #endif
-          start_node (tw, n, false);
+          if (node.namespaces.size > 0) {
+            if (node.document.namespaces.size > 0)
+              if (node.ns_uri () != node.document.ns_uri ())
+                if (n.namespaces.size == 0 && node.ns_prefix == null) // Apply parent ns
+                  n.set_namespace (node.ns_uri (), node.ns_prefix ());
+          }
+          start_node (tw, n, false, ref declared_ns);
           size += tw.end_element ();
           if (size > 1500)
             tw.flush ();
diff --git a/test/TwElementTest.vala b/test/TwElementTest.vala
index 48cf64a..fad0b82 100644
--- a/test/TwElementTest.vala
+++ b/test/TwElementTest.vala
@@ -359,6 +359,110 @@ class TwElementTest : GXmlTest {
                        assert ("</ns:nons>" in str);
                        assert ("</dg:child>" in str);
                });
+               Test.add_func ("/gxml/tw-element/multiple-namespaces/child-default", () => {
+                       var d = new TwDocument ();
+                       var r = d.create_element ("root");
+                       d.childs.add (r);
+                       // Default NS
+                       d.set_namespace ("http://git.gnome.org/browse/gxml";, null);
+                       // All namespaces declaration should be on root node
+                       d.ns_top = true;
+                       var e = d.create_element ("child");
+                       r.childs.add (e);
+                       assert (d.namespaces.size == 1);
+                       e.set_namespace ("http://developer.gnome.org/";, "dg");
+                       assert (e.namespaces.size == 1);
+                       assert (d.namespaces.size == 2);
+                       var e2 = d.create_element ("children");
+                       e.childs.add (e2);
+                       assert (e.namespaces.size == 1);
+                       assert (e2.namespaces.size == 0);
+                       assert (d.namespaces.size == 2);
+                       var e3 = d.create_element ("nons");
+                       e.childs.add (e3);
+                       e3.set_namespace ("http://www.gnome.org/";, null);
+                       assert (e.namespaces.size == 1);
+                       assert (e2.namespaces.size == 0);
+                       assert (e3.namespaces.size == 1);
+                       assert (d.namespaces.size == 3);
+                       // This child should use http://www.gnome.org/ namespace by default, no prefix
+                       var e4 = d.create_element ("childrenons");
+                       e3.childs.add (e4);
+                       assert (e.namespaces.size == 1);
+                       assert (e2.namespaces.size == 0);
+                       assert (e3.namespaces.size == 1);
+                       assert (e4.namespaces.size == 0);
+                       assert (d.namespaces.size == 3);
+                       var c2 = d.create_element ("soup");
+                       d.root.childs.add (c2);
+                       // apply default namespace, should avoid prefix
+                       c2.set_namespace ("http://git.gnome.org/browse/gxml";, null);
+                       string str = d.to_string ();
+#if DEBUG
+                       GLib.message (@"$d");
+#endif
+                       assert ("<root xmlns=\"http://git.gnome.org/browse/gxml\"; 
xmlns:dg=\"http://developer.gnome.org/\";>" in str);
+                       assert ("<soup/>" in str);
+                       assert ("</root>" in str);
+                       assert ("<dg:child>" in str);
+                       assert ("<children/>" in str);
+                       assert ("<nons xmlns=\"http://www.gnome.org/\";>" in str);
+                       assert ("<childrenons/>" in str);
+                       assert ("</nons>" in str);
+                       assert ("</dg:child>" in str);
+               });
+               Test.add_func ("/gxml/tw-element/multiple-namespaces/child-default/enable-prefix_default_ns", 
() => {
+                       var d = new TwDocument ();
+                       var r = d.create_element ("root");
+                       d.childs.add (r);
+                       // Default NS
+                       d.set_namespace ("http://git.gnome.org/browse/gxml";, null);
+                       d.prefix_default_ns = true;
+                       var e = d.create_element ("child");
+                       r.childs.add (e);
+                       assert (d.namespaces.size == 1);
+                       e.set_namespace ("http://developer.gnome.org/";, "dg");
+                       assert (e.namespaces.size == 1);
+                       assert (d.namespaces.size == 2);
+                       var e2 = d.create_element ("children");
+                       e.childs.add (e2);
+                       assert (e.namespaces.size == 1);
+                       assert (e2.namespaces.size == 0);
+                       assert (d.namespaces.size == 2);
+                       var e3 = d.create_element ("nons");
+                       e.childs.add (e3);
+                       e3.set_namespace ("http://www.gnome.org/";, "ns");
+                       assert (e.namespaces.size == 1);
+                       assert (e2.namespaces.size == 0);
+                       assert (e3.namespaces.size == 1);
+                       assert (d.namespaces.size == 3);
+                       // This child should use http://www.gnome.org/ namespace by default, no prefix
+                       var e4 = d.create_element ("childrenons");
+                       e3.childs.add (e4);
+                       e4.set_namespace ("http://www.gnome.org/";, "ns");
+                       assert (e.namespaces.size == 1);
+                       assert (e2.namespaces.size == 0);
+                       assert (e3.namespaces.size == 1);
+                       assert (e4.namespaces.size == 1);
+                       assert (d.namespaces.size == 3);
+                       var c2 = d.create_element ("soup");
+                       d.root.childs.add (c2);
+                       // apply default namespace, should avoid prefix
+                       c2.set_namespace ("http://git.gnome.org/browse/gxml";, null);
+                       string str = d.to_string ();
+#if DEBUG
+                       GLib.message (@"$d");
+#endif
+                       assert ("<root xmlns=\"http://git.gnome.org/browse/gxml\";>" in str);
+                       assert ("<soup/>" in str);
+                       assert ("</root>" in str);
+                       assert ("<dg:child xmlns:dg=\"http://developer.gnome.org/\";>" in str);
+                       assert ("<children/>" in str);
+                       assert ("<ns:nons xmlns:ns=\"http://www.gnome.org/\";>" in str);
+                       assert ("<ns:childrenons/>" in str);
+                       assert ("</ns:nons>" in str);
+                       assert ("</dg:child>" in str);
+               });
                Test.add_func ("/gxml/tw-element/multiple-namespaces/default/enable-prefix_default_ns", () => 
{
                        var d = new TwDocument ();
                        var r = d.create_element ("root");


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