diff --git a/gxml/StreamReader.vala b/gxml/StreamReader.vala index 9d0ff67bc43a0162a5c4bc8487147e55b18f8dfa..b9a443924396208e9164105d34cd316ad63e58fb 100644 --- a/gxml/StreamReader.vala +++ b/gxml/StreamReader.vala @@ -28,6 +28,7 @@ public errordomain GXml.StreamReaderError { public class GXml.StreamReader : GLib.Object { uint8[] buf = new uint8[2]; + Gee.HashMap root_collections = new Gee.HashMap (); public DataInputStream stream { get; } public Cancellable? cancellable { get; set; } public DomDocument document { get; } @@ -84,7 +85,13 @@ public class GXml.StreamReader : GLib.Object { public GXml.Element read_root_element () throws GLib.Error { return read_element (true); } - public GXml.Element read_element (bool children) throws GLib.Error { + public GXml.Element read_element (bool children, GXml.Element? parent = null) throws GLib.Error { + if (parent != null) { + if (!(parent is GXml.Object)) { + throw new DomError.INVALID_NODE_TYPE_ERROR + (_("Parent '%s' is not implemeting GXml.Object interface"), parent.get_type ().name ()); + } + } GXml.Element e = null; var buf = new MemoryOutputStream.resizable (); var dbuf = new DataOutputStream (buf); @@ -122,6 +129,40 @@ public class GXml.StreamReader : GLib.Object { document.append_child (e); } } + if (document.document_element == e && parent == null) { + foreach (ParamSpec pspec in + (e as GXml.Object).get_property_element_list ()) { + if (!(pspec.value_type.is_a (typeof (Collection)))) continue; + Collection col; + Value vc = Value (pspec.value_type); + e.get_property (pspec.name, ref vc); + col = vc.get_object () as Collection; + if (col == null) { + col = GLib.Object.new (pspec.value_type, + "element", e) as Collection; + vc.set_object (col); + e.set_property (pspec.name, vc); + } + if (col.items_type == GLib.Type.INVALID + || !(col.items_type.is_a (typeof (GXml.Object)))) { + throw new DomError.INVALID_NODE_TYPE_ERROR + (_("Collection '%s' hasn't been constructed properly: items' type property was not set at construction time or set to invalid type"), col.get_type ().name ()); + } + if (col.items_name == "" || col.items_name == null) { + throw new DomError.INVALID_NODE_TYPE_ERROR + (_("Collection '%s' hasn't been constructed properly: items' name property was not set at construction time"), col.get_type ().name ()); + } + if (col.element == null || !(col.element is GXml.Object)) { + throw new DomError.INVALID_NODE_TYPE_ERROR + (_("Collection '%s' hasn't been constructed properly: element property was not set at construction time"), col.get_type ().name ()); + } + if (!(col.element is GXml.Object)) { + throw new DomError.INVALID_NODE_TYPE_ERROR + (_("Invalid object of type '%s' doesn't implement GXml.Object interface: can't be handled by the collection"), col.element.get_type ().name ()); + } + root_collections.set (col.items_name.down (), col); + } + } e.read_buffer = buf; if (is_empty) { return e; @@ -139,9 +180,36 @@ public class GXml.StreamReader : GLib.Object { if (closetag == (string) oname_buf.get_data ()) { return e; } - } else if (children) { - var ce = read_element (false); - e.append_child (ce); + } else if (children && parent == null) { + GXml.Element ce = read_element (false, e);; + message ("Parsing node: %s", ce.local_name); + var col = root_collections.get (ce.local_name.down ()); + if (col != null) { + var cobj = GLib.Object.new (col.items_type, + "owner-document", document) as Element; + cobj.read_buffer = ce.read_buffer; + e.append_child (cobj); + col.append (cobj); + message ("Added node: %s to %s", cobj.local_name, col.get_type ().name ()); + } else { + message ("Searching node property"); + foreach (ParamSpec pspec in + (e as GXml.Object).get_property_element_list ()) { + if (pspec.value_type.is_a (typeof (Collection))) continue; + var obj = GLib.Object.new (pspec.value_type, + "owner-document", document) as Element; + message ("%s == %s", obj.local_name, ce.local_name.down ()); + if (obj.local_name.down () + == ce.local_name.down ()) { + Value v = Value (pspec.value_type); + v.set_object (obj); + e.set_property (pspec.name, v); + obj.read_buffer = ce.read_buffer; + ce = obj; + } + } + e.append_child (ce); + } } else { dbuf.put_byte ('<', cancellable); dbuf.put_byte (cur_byte (), cancellable); diff --git a/test/StreamReaderTest.vala b/test/StreamReaderTest.vala index 8b55e3be894f4c488600f72784c68ec73d7c2d51..01cf557325cd9167ae1c5e121c19502e82558620 100644 --- a/test/StreamReaderTest.vala +++ b/test/StreamReaderTest.vala @@ -91,6 +91,7 @@ class Book : GXml.Element { public int year { get; set; } [Description(nick="::ISBN")] public string ISBN { get; set; } + public Authors authors { get; set; } construct { try { initialize ("Book"); @@ -110,6 +111,7 @@ class Book : GXml.Element { } class BookStore : GXml.Element { + public Name name { get; set; } public Book.Collection books { get; set; } construct { try { @@ -141,6 +143,7 @@ class GXmlTest { var doc = sr.read (); message (doc.write_string ()); var rootbuf = (string) (doc.document_element as GXml.Element).read_buffer.data; + assert (doc.document_element.child_nodes.length > 0); var childbuf = (string) (doc.document_element.child_nodes.item (0) as GXml.Element).read_buffer.data; message (rootbuf); message (childbuf); @@ -232,6 +235,7 @@ class GXmlTest { Idle.add (()=>{ string str = """ + Magic Book @@ -265,7 +269,13 @@ class GXmlTest { assert (doc.document_element != null); assert (doc.document_element is BookStore); var bs = doc.document_element as BookStore; - assert (bs.child_nodes.length == 2); + assert (bs != null); + assert (bs.name != null); + assert (bs.name is Name); + assert (bs.books != null); + assert (bs.books.length == 2); + assert (bs.books.get_item (0) is Book); + assert (bs.books.get_item (1) is Book); foreach (DomNode n in bs.child_nodes) { if (n is DomElement) { assert ((n as GXml.Element).read_buffer != null); @@ -277,6 +287,15 @@ class GXmlTest { message (doc.write_string ()); assert (bs.read_buffer == null); assert (bs.books != null); + assert (bs.books.length == 2); + var b1 = bs.books.get_item (0) as Book; + assert (b1 != null); + assert (b1 is Book); + assert (b1.authors != null); + var b2 = bs.books.get_item (0) as Book; + assert (b2 != null); + assert (b2 is Book); + assert (b2.authors != null); loop.quit (); } catch (GLib.Error e) { warning ("Error: %s", e.message);