[gxml.wiki] Update collections with examples for CollectionParent interface



commit adc80365ca9c4916fbfdf8338d8f6cf9d3af6394
Author: Daniel Espinosa Ortiz <esodan gmail com>
Date:   Fri Feb 28 01:08:13 2020 +0000

    Update collections with examples for CollectionParent interface

 collections.md | 174 +++++++++++++++++++++++++++++++++++++++++++++++++++------
 1 file changed, 156 insertions(+), 18 deletions(-)
---
diff --git a/collections.md b/collections.md
index 392ebe3..8fc00ef 100644
--- a/collections.md
+++ b/collections.md
@@ -4,11 +4,11 @@ GXml collections is a set of classes used to get access to `DomElement` nodes us
 
 DOM4 provides bases API for accessing nodes, but is more like a list access, with an index and previous a 
next method access.
 
-There are some classes to provide such collection like access to nodes in TNode derived classes, but they 
are not maintained any more and will be removed.
+# GXml.Collection Interface
 
-# GomCollection Interface
+`BaseCollection`is an abstract class implementing `Collection` interface, and the base for different 
collection implementations.
 
-`BaseCollection`is an abstract class implementing `GomCollection` inteface, and the base for different 
collection implementations.
+> If you want to know all collections available in GXml see [BaseCollection} 
(https://gnome.pages.gitlab.gnome.org/gxml/dev/GXml.BaseCollection.html)
 
 It is designed to add `GObject` properties accessing nodes in the XML tree, arranged by its type.
 
@@ -17,46 +17,46 @@ Lets say you have a top most `DomElement` node called `store`, with children nod
 In order to implement this you should have:
 
 ```vala
-public class Store : GomElement {
+public class Store : GXml.Element {
   construct {
     try { initialize ("store"); }
-    catch (GLib.Error e) { warning ("Initialization error: %s".printf (e.message);  }
+    catch (GLib.Error e) { warning ("Initialization error: %s", e.message);  }
   }
 }
 
-public class Book : GomElement {
+public class Book : GXml.Element {
   construct {
     try { initialize ("book"); }
-    catch (GLib.Error e) { warning ("Initialization error: %s".printf (e.message);  }
+    catch (GLib.Error e) { warning ("Initialization error: %s", e.message);  }
   }
 }
 
-public class News : GomElement {
+public class News : GXml.Element {
   construct {
     try { initialize ("news"); }
-    catch (GLib.Error e) { warning ("Initialization error: %s".printf (e.message);  }
+    catch (GLib.Error e) { warning ("Initialization error: %s", e.message);  }
   }
 }
 
 ```
-Each class will take care to read store, book and news named nodes. But about if you want to access just all 
book nodes or news ones. To do so use a `GomCollection`, it will take a node of a type and add a reference to 
it in the DOM4 `child_nodes` collection.
+Each class will take care to read store, book and news named nodes. But what about if you want to access 
just all `book` nodes or `news` ones. To do so use a `GXml.Collection`, it will take a node of a given type 
and add a reference to it in the DOM4 `child_nodes` collection.
 
-For this example we will declare a new class derived from `GomArrayList`:
+For this example we will declare a new class derived from `GXml.ArrayList`:
 
 ```vala
 
-public class BookArray : GomArrayList {
+public class BookArray : GXml.ArrayList {
   construct {
     try { initialize (typeof (Book)); }
-    catch (GLib.Error e) { warning ("Initialization error: %s".printf (e.message);  }
+    catch (GLib.Error e) { warning ("Initialization error: %s", e.message);  }
   }
 }
 ```
 
-Thats all, now add a property in `Store` to tell it you wan to keep all your book nodes in that collection:
+That is all, now add a property in `Store` to tell it you want to keep all your book nodes in that 
collection:
 
 ```vala
-public class Store : GomElement {
+public class Store : GXml.Element {
   public BookArray books { get; set; }
   construct {
     try {
@@ -66,7 +66,7 @@ public class Store : GomElement {
   }
 }
 ```
-Pay attention on `set_instance_property ("books")` it creates an instance of your collection, using current 
class as its `DomElement` where its references are valid child nodes.
+Pay attention on `set_instance_property ("books")` it creates an instance of your collection, using current 
class as its `DomElement` where its references are valid child nodes. If you don't initialize correctly this 
property, will see errors at parsing time.
 
 **Note** Your perperty name used in `set_instance_property`, should be canonicalized, so if your property 
is called `books_for_sell`, you should use `books-for-sell` in order to initialize the correct property.
 
@@ -93,7 +93,145 @@ s.books.append (b);
 
 In the above example, you create an item in the `books` collection so it is initialized with the same 
`DomDocument` of the target parent.
 
+## Collection of different types
 
-## Array Collection
+`BaseCollection` requires to define just one instantiatable `GLib.Type`, so the parser can know what type to 
use to create the object and set its properties. But what about a collection of objects derived from the same 
type, maybe non-instantiatable like interfaces, for that you have 
[GXml.CollectionParent](https://gnome.pages.gitlab.gnome.org/gxml/dev/GXml.CollectionParent.html) interface.
 
-`GomArrayCollection` is a collection you can use to access a set of nodes of the same time in the order they 
appear in as child in the parent element node. 
\ No newline at end of file
+Lets see this code:
+
+```vala
+// Base type for all items in a Store's shelf
+interface Item : GLib.Object, GXml.Object {}
+
+// A Collection you want to use to hold all this kind of objects
+class Items : GXml.ArrayList, GXml.CollectionParent {
+  construct {
+    // Used a non-instantiatable type interface 'Item'
+    try { initialize (typeof (Item)); } catch (GLib.Error e) { warning  ("Error: %s", e.message); }
+  }
+  // Override supported types, adding all ones you want to add at parsing time
+  public GLib.HashTable<string,GLib.Type> types {
+    owned get {
+      var c = new GLib.HashTable<string,GLib.Type> (str_hash, str_equal);
+      GXml.CollectionParent.add_supported_types (c, items_type,
+                                                {
+                                                typeof (Monitor),
+                                                typeof (Keyword),
+                                                typeof (Cpu)
+                                                });
+      return c;
+    }
+  }
+}
+
+// Items classes definitions
+class Monitor : GXml.Element, Item {
+  [Description (nick="::size")]
+  public int size { get; set; }
+  construct {
+    try { initialize ("Monitor"); } catch (GLib.Error e) { warning  ("Error: %s", e.message); }
+  }
+}
+class Keyword : GXml.Element, Item {
+  [Description (nick="::language")]
+  public string size { get; set; }
+  construct {
+    try { initialize ("Keyword"); } catch (GLib.Error e) { warning  ("Error: %s", e.message); }
+  }
+}
+class Cpu : GXml.Element, Item {
+  [Description (nick="::language")]
+  public string size { get; set; }
+  construct {
+    try { initialize ("Cpu"); } catch (GLib.Error e) { warning  ("Error: %s", e.message); }
+  }
+}
+
+// Base type for all containers, and for Store's Shelf
+abstract interface Container : GLib.Object, GXml.Object {}
+
+// This class is a Container
+class StoreShelf : GXml.Element, Container {
+  [Description (nick="::Id")]
+  public int id { get; set; default = 1; }
+  public Items items { get; set; }
+  construct {
+    try {
+      initialize ("Shelf");
+      set_instance_property ("items");
+    } catch (GLib.Error e) { warning  ("Error: %s", e.message); }
+  }
+}
+
+// A Collection where to add any container found at parsing time
+class Containers : GXml.ArrayList, GXml.CollectionParent {
+  construct {
+    try { initialize (typeof (Container)); } catch (GLib.Error e) { warning  ("Error: %s", e.message); }
+  }
+  // Override supported types, adding all ones you want to add at parsing time
+  public GLib.HashTable<string,GLib.Type> types {
+    owned get {
+      var c = new GLib.HashTable<string,GLib.Type> (str_hash, str_equal);
+      GXml.CollectionParent.add_supported_type (c, items_type, typeof (StoreShelf));
+      return c;
+    }
+  }
+}
+// This is the top level <ComputerStore/> node, parent for <StoreShelf/> nodes
+class ComputerStore : GXml.Element {
+  [Description (nick="::name")]
+  public string name { get; set; }
+  // Any <StoreShelf/> node will be added to this collection
+  // if you want more, just define a new class implementing 'Container' interface
+  // and modify 'Containers.types' property definition to add more types
+  public Containers containers { get; set; default = new Containers (); }
+  construct {
+    try {
+      initialize ("ComputerStore");
+      // This is necesary if you want to use your collection to hold parsed nodes
+      set_instance_property ("containers");
+    } catch (GLib.Error e) { warning  ("Error: %s", e.message); }
+  }
+}
+```
+
+With above code, you can parse XML documents like:
+
+```xml
+<ComputerStore>
+  <Shelf Id="2">
+    <Cpu/>
+    <Monitor size="32"/>
+    <Keyword/>
+  </Shelf>
+</ComputerStore>
+```
+
+Above XML will be mapped to a set of `GLib.Object` classes. The top level node to `ComputerStore` class and 
all its child nodes recognized by `Containers` class, will be instantiated as `GLib.Object` settings its 
attributes. The same case is for the `Items` container, holding a set of objects of the type `Item`.
+
+Accessing the objects in `Containers` or `Items`, you can use the 
[Collection](https://gnome.pages.gitlab.gnome.org/gxml/dev/GXml.Collection.html), then you can cast to the 
required type.
+
+Lets take a close review of a collection definition:
+```vala
+// A Collection you want to use to hold all this kind of objects
+class Items : GXml.ArrayList, GXml.CollectionParent {
+  construct {
+    // Used a non-instantiatable type interface 'Item'
+    try { initialize (typeof (Item)); } catch (GLib.Error e) { warning  ("Error: %s", e.message); }
+  }
+  // Override supported types, adding all ones you want to add at parsing time
+  public GLib.HashTable<string,GLib.Type> types {
+    owned get {
+      var c = new GLib.HashTable<string,GLib.Type> (str_hash, str_equal);
+      GXml.CollectionParent.add_supported_types (c, items_type,
+                                                {
+                                                typeof (Monitor),
+                                                typeof (Keyword),
+                                                typeof (Cpu)
+                                                });
+      return c;
+    }
+  }
+}
+```
+Any [BaseCollection](https://gnome.pages.gitlab.gnome.org/gxml/dev/GXml.BaseCollection.html) derived 
implementations, can be converted to `CollectionParent` by declaring them implementing this interface, so is 
easy to use any other collection type, jut need to override `CollectionParent.types` properties and add the 
types you want your collection should instantiate and hold reference to.
\ No newline at end of file


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