[gxml] GomObject-XParser: Search for object properties



commit 961b9b19051eae856fbcef120bd23079eaa4a272
Author: Daniel Espinosa <esodan gmail com>
Date:   Sat Nov 5 20:20:25 2016 -0600

    GomObject-XParser: Search for object properties
    
    XParser searchs if a node is an object's property
    if current XML element node's name is one of
    expected for current TextReader found node. If so,
    it is used to set object's property by deserializing
    it.

 gxml/GomNode.vala              |    2 +-
 gxml/GomObject.vala            |   21 +++++-
 gxml/XParser.vala              |  155 ++++++++++++++++++++++++----------------
 test/GomSerializationTest.vala |   17 +++++
 4 files changed, 129 insertions(+), 66 deletions(-)
---
diff --git a/gxml/GomNode.vala b/gxml/GomNode.vala
index 140713c..cf2f44c 100644
--- a/gxml/GomNode.vala
+++ b/gxml/GomNode.vala
@@ -248,7 +248,7 @@ public class GXml.GomNode : Object,
     if ((node is DomText && this is DomDocument)
           || (node is DomDocumentType && !(this is DomDocument)))
       throw new DomError.HIERARCHY_REQUEST_ERROR
-                  (_("Invalid attempt to insert a document's type or text node to a invalid parent"));
+                  (_("Invalid attempt to insert a document or text type to a invalid parent node"));
     //FIXME: We should follow steps for DOM4 observers in https://www.w3.org/TR/dom/#concept-node-pre-insert
     if (child != null) {
       int i = this.child_nodes.index_of (child as GXml.DomNode);
diff --git a/gxml/GomObject.vala b/gxml/GomObject.vala
index 804655e..b81cd83 100644
--- a/gxml/GomObject.vala
+++ b/gxml/GomObject.vala
@@ -41,8 +41,7 @@ public interface GXml.GomObject : GLib.Object,
   public virtual bool use_nick_name () { return true; }
 
   /**
-   * Returns a hash table with key as property's nick with out "::" if have it
-   * and value as property's name, for all nicks with a prefix "::". Nick name,
+   * Returns a list with all properties nick with "::" prefix. Nick name,
    * without "::" will be used on serialization to an attribute's name.
    */
   public virtual List<string> get_properties_list () {
@@ -56,8 +55,8 @@ public interface GXml.GomObject : GLib.Object,
     return l;
   }
   /**
-   * Returns property's name based on given nick. This function is no
-   * case sensitive.
+   * Returns property's name based on given nick. This function is
+   * case insensitive.
    */
   public virtual string? find_property_name (string nick) {
     foreach (ParamSpec spec in this.get_class ().list_properties ()) {
@@ -72,6 +71,20 @@ public interface GXml.GomObject : GLib.Object,
     return null;
   }
   /**
+   * Returns a list of names for all {@link DomElement}
+   * present as object's properties.
+   */
+  public virtual List<ParamSpec> get_property_element_list () {
+    var l = new List<ParamSpec> ();
+    foreach (ParamSpec spec in this.get_class ().list_properties ()) {
+      if (spec.value_type.is_a (typeof (GomObject))) {
+        GLib.message ("Object Name: "+spec.name+ " Nick: "+spec.get_nick ());
+        l.append (spec);
+      }
+    }
+    return l;
+  }
+  /**
    * Search for properties in objects, it should be
    * an {@link GLib.Object}'s property. If found a
    * property with given name its value is returned
diff --git a/gxml/XParser.vala b/gxml/XParser.vala
index f284984..27a7514 100644
--- a/gxml/XParser.vala
+++ b/gxml/XParser.vala
@@ -104,21 +104,26 @@ public class GXml.XParser : Object, GXml.Parser {
     while (read_current_node (_node, true));
   }
 
-  public bool read_current_node (DomNode node, bool read_current = false)
+  public bool read_current_node (DomNode node,
+                                bool read_current = false,
+                                bool read_property = false)
                                 throws GLib.Error {
     GXml.DomNode n = node;
     string prefix = null, nsuri = null;
+    int res = 1;
 #if DEBUG
     GLib.message ("ReadNode: Current Node:"+node.node_name);
 #endif
-    int res = tr.read ();
-    if (res == -1)
-      throw new ParserError.INVALID_DATA_ERROR (_("Can't read node data"));
+    if (!read_property) {
+      res = tr.read ();
+      if (res == -1)
+        throw new ParserError.INVALID_DATA_ERROR (_("Can't read node data"));
 #if DEBUG
-    if (res == 0)
-      GLib.message ("ReadNode: No more nodes");
+      if (res == 0)
+        GLib.message ("ReadNode: No more nodes");
 #endif
-    if (res == 0) return false;
+      if (res == 0) return false;
+    }
     var t = tr.node_type ();
     switch (t) {
     case Xml.ReaderType.NONE:
@@ -130,7 +135,29 @@ public class GXml.XParser : Object, GXml.Parser {
         throw new ParserError.INVALID_DATA_ERROR (_("Can't read node data"));
       break;
     case Xml.ReaderType.ELEMENT:
+      bool isproperty = false;
       bool isempty = (tr.is_empty_element () == 1);
+      if (!read_current && !read_property
+          && node is DomElement
+          && tr.const_local_name () != (node as DomElement).local_name) {
+        GLib.message ("Searching for Properties Nodes for:"+
+                      tr.const_local_name ());
+        foreach (ParamSpec pspec in
+                  (node as GomObject).get_property_element_list ()) {
+          var obj = Object.new (pspec.value_type,
+                                "document", node.owner_document);
+          if ((obj as DomElement).local_name.down ()
+                 == tr.const_local_name ().down ()) {
+            Value v = Value (pspec.value_type);
+            read_current_node (obj as DomNode, true, true);
+            node.append_child (obj as DomNode);
+            v.set_object (obj);
+            node.set_property (pspec.name, v);
+            isproperty = true;
+            break;
+          }
+        }
+      }
       if (node is DomElement) {
         if (read_current
             && tr.const_local_name ().down ()
@@ -139,71 +166,77 @@ public class GXml.XParser : Object, GXml.Parser {
                     (_("Invalid element node name. Expected %s")
                         .printf ((node as DomElement).local_name));
       }
-      if (node is DomDocument || !read_current) {
-#if DEBUG
-        if (isempty) GLib.message ("Is Empty node:"+node.node_name);
-        GLib.message ("ReadNode: Element: "+tr.const_local_name ());
-#endif
-        prefix = tr.prefix ();
-        if (prefix != null) {
-          GLib.message ("Is namespaced element");
-          nsuri = tr.lookup_namespace (prefix);
-          n = _document.create_element_ns (nsuri, tr.prefix () +":"+ tr.const_local_name ());
-        } else
-          n = _document.create_element (tr.const_local_name ());
-        node.append_child (n);
-      }
-      var nattr = tr.attribute_count ();
+      if (!isproperty) {
+        GLib.message ("Not property is set");
+        if (node is DomDocument || !read_current) {
+          GLib.message ("No deserializing current node");
+#if DEBUG
+          if (isempty) GLib.message ("Is Empty node:"+node.node_name);
+          GLib.message ("ReadNode: Element: "+tr.const_local_name ());
+#endif
+          if (!isproperty) {
+            prefix = tr.prefix ();
+            if (prefix != null) {
+              GLib.message ("Is namespaced element");
+              nsuri = tr.lookup_namespace (prefix);
+              n = _document.create_element_ns (nsuri, tr.prefix () +":"+ tr.const_local_name ());
+            } else
+              n = _document.create_element (tr.const_local_name ());
+            node.append_child (n);
+          }
+        }
+        var nattr = tr.attribute_count ();
 #if DEBUG
-      GLib.message ("Number of Attributes:"+nattr.to_string ());
+        GLib.message ("Number of Attributes:"+nattr.to_string ());
 #endif
-      for (int i = 0; i < nattr; i++) {
-        var c = tr.move_to_attribute_no (i);
+        for (int i = 0; i < nattr; i++) {
+          var c = tr.move_to_attribute_no (i);
 #if DEBUG
-        GLib.message ("Current Attribute: "+i.to_string ());
+          GLib.message ("Current Attribute: "+i.to_string ());
 #endif
-        if (c != 1) {
-          throw new DomError.HIERARCHY_REQUEST_ERROR (_("Parsing ERROR: Fail to move to attribute number: 
%i").printf (i));
-        }
-        if (tr.is_namespace_decl () == 1) {
-//#if DEBUG
-          GLib.message ("Is Namespace Declaration...");
-//#endif
-          string nsp = tr.const_local_name ();
-          string aprefix = tr.prefix ();
-          tr.read_attribute_value ();
-          if (tr.node_type () == Xml.ReaderType.TEXT) {
-            string ansuri = tr.read_string ();
-            GLib.message ("Read: "+aprefix+":"+nsp+"="+ansuri);
-            string ansp = nsp;
-            if (nsp != "xmlns")
-              ansp = aprefix+":"+nsp;
-            GLib.message ("To append: "+ansp+"="+ansuri);
-            (n as DomElement).set_attribute_ns ("http://www.w3.org/2000/xmlns/";,
-                                                 ansp, ansuri);
+          if (c != 1) {
+            throw new DomError.HIERARCHY_REQUEST_ERROR (_("Parsing ERROR: Fail to move to attribute number: 
%i").printf (i));
           }
-        } else {
-          var attrname = tr.const_local_name ();
-          prefix = tr.prefix ();
-#if DEBUG
-          GLib.message ("Attribute: "+tr.const_local_name ());
-#endif
-          tr.read_attribute_value ();
-          if (tr.node_type () == Xml.ReaderType.TEXT) {
-            var attrval = tr.read_string ();
-#if DEBUG
-            GLib.message ("Attribute:"+attrname+" Value: "+attrval);
-#endif
-            bool processed = (n as GomObject).set_attribute (attrname, attrval);
-            if (prefix != null && !processed) {
-              GLib.message ("Prefix found: "+prefix);
-              if (prefix == "xml")
-                nsuri = "http://www.w3.org/2000/xmlns/";;
-              else
-                nsuri = tr.lookup_namespace (prefix);
-              (n as DomElement).set_attribute_ns (nsuri, prefix+":"+attrname, attrval);
-            } else if (!processed)
-              (n as DomElement).set_attribute (attrname, attrval);
+          if (tr.is_namespace_decl () == 1) {
+  //#if DEBUG
+            GLib.message ("Is Namespace Declaration...");
+  //#endif
+            string nsp = tr.const_local_name ();
+            string aprefix = tr.prefix ();
+            tr.read_attribute_value ();
+            if (tr.node_type () == Xml.ReaderType.TEXT) {
+              string ansuri = tr.read_string ();
+              GLib.message ("Read: "+aprefix+":"+nsp+"="+ansuri);
+              string ansp = nsp;
+              if (nsp != "xmlns")
+                ansp = aprefix+":"+nsp;
+              GLib.message ("To append: "+ansp+"="+ansuri);
+              (n as DomElement).set_attribute_ns ("http://www.w3.org/2000/xmlns/";,
+                                                   ansp, ansuri);
+            }
+          } else {
+            var attrname = tr.const_local_name ();
+            prefix = tr.prefix ();
+#if DEBUG
+            GLib.message ("Attribute: "+tr.const_local_name ());
+#endif
+            tr.read_attribute_value ();
+            if (tr.node_type () == Xml.ReaderType.TEXT) {
+              var attrval = tr.read_string ();
+#if DEBUG
+              GLib.message ("Attribute:"+attrname+" Value: "+attrval);
+#endif
+              bool processed = (n as GomObject).set_attribute (attrname, attrval);
+              if (prefix != null && !processed) {
+                GLib.message ("Prefix found: "+prefix);
+                if (prefix == "xml")
+                  nsuri = "http://www.w3.org/2000/xmlns/";;
+                else
+                  nsuri = tr.lookup_namespace (prefix);
+                (n as DomElement).set_attribute_ns (nsuri, prefix+":"+attrname, attrval);
+              } else if (!processed)
+                (n as DomElement).set_attribute (attrname, attrval);
+            }
           }
         }
       }
diff --git a/test/GomSerializationTest.vala b/test/GomSerializationTest.vala
index f6423a5..51f4bff 100644
--- a/test/GomSerializationTest.vala
+++ b/test/GomSerializationTest.vala
@@ -65,6 +65,18 @@ class GomSerializationTest : GXmlTest  {
       FEBRUARY
     }
   }
+  public class BookRegister : GomElement {
+    [Description (nick="::Year")]
+    public int year { get; set; }
+    public Book book { get; set; }
+    construct {
+      _local_name = "BookRegister";
+    }
+    public string to_string () {
+      var parser = new XParser (this);
+      return parser.write_string ();
+    }
+  }
   public static void add_tests () {
     Test.add_func ("/gxml/gom-serialization/write/properties", () => {
       var b = new Book ();
@@ -116,6 +128,11 @@ class GomSerializationTest : GXmlTest  {
       assert ("TaxFree=\"true\"" in s);
       GLib.message ("DOC:"+s);
     });
+    Test.add_func ("/gxml/gom-serialization/write/object-property", () => {
+      /*var b = new BookRegister ();
+      string s = b.to_string ();
+      assert ("<BookRegister><Book/></BookRegister>" in s);*/
+    });
     Test.add_func ("/gxml/gom-serialization/read/properties", () => {
       var b = new Book ();
       var parser = new XParser (b);


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