diff --git a/gxml/Attr.vala b/gxml/Attr.vala index e0f270d9aa2b9cc8422e83e2ee1de85f8dd12cdb..2770d7bc18926165d22d7c968af56d7cc3d29520 100644 --- a/gxml/Attr.vala +++ b/gxml/Attr.vala @@ -68,7 +68,7 @@ namespace GXml { } /** Private properties */ - private Xml.Attr *node; + internal Xml.Attr *node; /** Constructors */ internal Attr (Xml.Attr *node, Document doc) { diff --git a/gxml/Document.vala b/gxml/Document.vala index af08c2e13f8459d43b7470cfcfecf09c6ec813df..840b18d266e2535d7712e8cf0a84d8ff5e940c70 100644 --- a/gxml/Document.vala +++ b/gxml/Document.vala @@ -186,6 +186,8 @@ namespace GXml { ~Document () { List to_free = new List (); + sync_dirty_elements (); + /* we use two separate loops, because freeing a node frees its descendants, and we might have a branch with children that might be @@ -328,10 +330,11 @@ namespace GXml { try { instream = fin.read (null); + this.from_stream (instream, can); + instream.close (); } catch (GLib.Error e) { throw new DomError.INVALID_DOC (e.message); } - this.from_stream (instream, can); } /** * Creates a Document from data provided through the InputStream instream. @@ -342,13 +345,13 @@ namespace GXml { // TODO: accept Cancellable // Cancellable can = new Cancellable (); InputStreamBox box = { instream, can }; - + Xml.Doc *doc; Xml.TextReader reader = new Xml.TextReader.for_io ((Xml.InputReadCallback)_ioread, (Xml.InputCloseCallback)_ioinclose, &box, "", null, 0); reader.read (); reader.expand (); - Xml.Doc *doc = reader.current_doc (); + doc = reader.current_doc (); reader.close (); this.from_libxml2 (doc); @@ -393,6 +396,8 @@ namespace GXml { elem.save_attributes (tmp_node); } this.dirty_elements = new List (); // clear the old list + + tmp_node->free (); } } diff --git a/gxml/Element.vala b/gxml/Element.vala index 1c3ed8ec32de93d6f3ec77dd9a60f6b0caf4483c..0ee8b891d9bb8535b19a37fcde5c89cda6193842 100644 --- a/gxml/Element.vala +++ b/gxml/Element.vala @@ -95,7 +95,7 @@ namespace GXml { if (this._attributes == null) { this.owner_document.dirty_elements.append (this); this._attributes = new HashTable (GLib.str_hash, GLib.str_equal); - // TODO: make sure other HashTables have appropriate hash, equal functions + // TODO: make sure other HashTables have appropriate hash, equal functions for (Xml.Attr *prop = base.node->properties; prop != null; prop = prop->next) { attr = new Attr (prop, this.owner_document); @@ -144,16 +144,21 @@ namespace GXml { } // Go through the GXml table of attributes for this element and add corresponding libxml2 ones - foreach (string propname in this.attributes.get_keys ()) { - attr = this.attributes.lookup (propname); + foreach (string propname in this._attributes.get_keys ()) { + attr = this._attributes.lookup (propname); + Xml.Attr* saved_attr; if (attr.namespace_uri != null || attr.prefix != null) { // I hate namespace handling between libxml2 and DOM Level 2/3 Core! ns = tmp_node->new_ns (attr.namespace_uri, attr.prefix); - this.node->set_ns_prop (ns, propname, attr.node_value); + saved_attr = this.node->set_ns_prop (ns, propname, attr.node_value); } else { - this.node->set_prop (propname, attr.node_value); + saved_attr = this.node->set_prop (propname, attr.node_value); } + + // Replace the old out-of-tree attr with the newly allocated one in the tree, that way xmlFreeDoc can clean up correctly + attr.node->free (); + attr.node = saved_attr; } } } @@ -214,7 +219,6 @@ namespace GXml { this.attributes.replace (name, attr); // TODO: replace wanted 'owned', look up what to do - } /** * Remove the attribute named name from this element. diff --git a/vapi/libxml-2.0.vapi b/vapi/libxml-2.0.vapi index 6743b1c0dfc0ac7a02b4f82643b285a4dc78de89..b434a7e3fa3b6f0983f1e2b8f6214061c3ec070b 100644 --- a/vapi/libxml-2.0.vapi +++ b/vapi/libxml-2.0.vapi @@ -277,6 +277,9 @@ namespace Xml { public Ns* ns; public AttributeType atype; + [CCode (cname = "xmlFreeProp")] + public int free(); + [CCode (cname = "xmlRemoveProp")] public int remove(); }