[gxml] * fixed NodeList for addition of DocumentFragment * successfully test get_elements_by_tag_name's liv



commit e9a5532a544c592831c4f7e83ae54f9e60de9098
Author: Richard Schwarting <aquarichy gmail com>
Date:   Thu Jul 28 22:11:54 2011 -0400

    * fixed NodeList for addition of DocumentFragment
    * successfully test get_elements_by_tag_name's live nature

 gxml/Element.vala     |   16 ++++++-
 gxml/NodeList.vala    |   43 +++++++++++++------
 test/ElementTest.vala |  109 +++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 152 insertions(+), 16 deletions(-)
---
diff --git a/gxml/Element.vala b/gxml/Element.vala
index 3157124..38fd7c8 100644
--- a/gxml/Element.vala
+++ b/gxml/Element.vala
@@ -207,6 +207,11 @@ namespace GXml.Dom {
 				}
 			}
 		}
+		/**
+		 * Checks whether a descendant of a node is an Element, or whether its descendants
+		 * are elements.  If they are, we check the basenode and its ancestors to see
+		 * whether they're keeping that node in a TagNameNodeList, so we can remove it.
+		 */
 		private void check_remove_tag_name (Element basenode, XNode child) {
 			// TODO: make sure there aren't any other NodeTypes that could have elements as children 
 			if (child.node_type == NodeType.ELEMENT) {
@@ -220,21 +225,21 @@ namespace GXml.Dom {
 			}
 		}
 
-		/*** XNode methods ***/
+		/* ** XNode methods ** */
 		public override XNode? insert_before (XNode new_child, XNode? ref_child) throws DomError {
 			XNode ret = base.insert_before (new_child, ref_child);
 			check_add_tag_name (this, new_child);
 			return ret;
 		}
 		public override XNode? replace_child (XNode new_child, XNode old_child) throws DomError {
+			check_remove_tag_name (this, old_child);
 			XNode ret = base.replace_child (new_child, old_child);
-			check_remove_tag_name (this, old_child); // removal should probably precede addition, in case we're moving something around
 			check_add_tag_name (this, new_child);
 			return ret;
 		}
 		public override XNode? remove_child (XNode old_child) throws DomError {
-			XNode ret = base.remove_child (old_child);
 			check_remove_tag_name (this, old_child);
+			XNode ret = base.remove_child (old_child);
 			return ret;
 		}
 		public override XNode? append_child (XNode new_child) throws DomError {
@@ -284,6 +289,11 @@ namespace GXml.Dom {
 			if (this.parent_node != null && this.parent_node.node_type == NodeType.ELEMENT)
 				((Element)this.parent_node).on_new_descendant_with_tag_name (elem);
 		}
+		/**
+		 * Checks whether this element has a TagNameNodeList containing this element,
+		 * and if so, removes it.  It also asks the parents above if they have such
+		 * a list.
+		 */
 		private void on_remove_descendant_with_tag_name (Element elem) {
 			foreach (TagNameNodeList list in tag_name_lists) {
 				if (elem.tag_name == list.tag_name) {
diff --git a/gxml/NodeList.vala b/gxml/NodeList.vala
index 84bd2bf..85dd3e4 100644
--- a/gxml/NodeList.vala
+++ b/gxml/NodeList.vala
@@ -508,7 +508,6 @@ namespace GXml.Dom {
 				this.append_child (ref_child);
 			}
 
-
 			while (child != ((BackedNode)ref_child).node && child != null) {
 				child = child->next;
 			}
@@ -516,7 +515,13 @@ namespace GXml.Dom {
 				throw new DomError.NOT_FOUND ("ref_child not found.");
 				// TODO: provide a more useful description of ref_child, but there are so many different types
 			} else {
-				child->add_prev_sibling (((BackedNode)new_child).node);
+				if (new_child.node_type == NodeType.DOCUMENT_FRAGMENT) {
+					foreach (XNode new_grand_child in new_child.child_nodes) {
+						child->add_prev_sibling (((BackedNode)new_grand_child).node);
+					}
+				} else {
+					child->add_prev_sibling (((BackedNode)new_child).node);
+				}
 			}
 			return new_child;
 		}
@@ -530,19 +535,25 @@ namespace GXml.Dom {
 			// TODO: need to handle errors?
 
 			// TODO: want to do a 'find_child' function
-			Xml.Node *child = head;
+			if (new_child.node_type == NodeType.DOCUMENT_FRAGMENT) {
+				this.insert_before (new_child, old_child);
+				this.remove_child (old_child);
+			} else {
+				Xml.Node *child = head;
 
-			while (child != null && child != ((BackedNode)old_child).node) {
-				child = child->next;
-			}
+				while (child != null && child != ((BackedNode)old_child).node) {
+					child = child->next;
+				}
 
-			if (child != null) {
-				// it is a valid child
-				child->replace (((BackedNode)new_child).node);
-			} else {
-				throw new DomError.NOT_FOUND ("old_child not found");
-				// TODO: provide more useful descr. of old_child
+				if (child != null) {
+					// it is a valid child
+					child->replace (((BackedNode)new_child).node);
+				} else {
+					throw new DomError.NOT_FOUND ("old_child not found");
+					// TODO: provide more useful descr. of old_child
+				}
 			}
+
 			return old_child;
 		}
 		internal new XNode? remove_child (XNode old_child) /* throws DomError */ {
@@ -557,7 +568,13 @@ namespace GXml.Dom {
 			// new_child if it already exists elsewhere in
 			// the tree.
 
-			parent_as_xmlnode->add_child (((BackedNode)new_child).node);
+			if (new_child.node_type == NodeType.DOCUMENT_FRAGMENT) {
+				foreach (XNode grand_child in new_child.child_nodes) {
+					parent_as_xmlnode->add_child (((BackedNode)grand_child).node);
+				}
+			} else {
+				parent_as_xmlnode->add_child (((BackedNode)new_child).node);
+			}
 
 			return new_child;
 		}
diff --git a/test/ElementTest.vala b/test/ElementTest.vala
index 33cccdb..66361fc 100644
--- a/test/ElementTest.vala
+++ b/test/ElementTest.vala
@@ -171,6 +171,115 @@ class ElementTest : GXmlTest  {
 					assert (false);
 				}
 			});
+		Test.add_func ("/gxml/element/get_elements_by_tag_name.live", () => {
+				/* Need to test the following cases:
+
+				   you have an element, it has 3 title descendants.
+				   get the node list, has 3 nodes
+				   add a title to the element, node list has 4 nodes
+				   add a title to a grand child, node list has 5 nodes
+				   add another element tree with 2 titles at various depths, list has 7
+				   add a document fragment with 2 titles at various depths, list has 9
+
+				   remove a single child element, list has 8
+				   remove a deeper descendent, list has 7
+				   remove a tree with 2, list has 5
+				   readd the tree, list has 7
+				*/
+				try {
+					Document doc;
+					string xml;
+
+					xml =
+"<A>
+  <t />
+  <Bs>
+    <t />
+    <B>
+      <t />
+      <D><t /></D>
+      <D><t /></D>
+    </B>
+    <B><t /></B>
+    <B></B>
+  </Bs>
+  <Cs><C><t /></C></Cs>
+</A>";
+					doc = new Document.from_string (xml);
+
+					XNode a = doc.document_element;
+					XNode bs = a.child_nodes.item (3);
+					XNode b3 = bs.child_nodes.item (7);
+					XNode t1, t2;
+
+					NodeList ts = ((Element)bs).get_elements_by_tag_name ("t");
+					assert (ts.length == 5);
+
+					// Test adding direct child
+					bs.append_child (t1 = doc.create_element ("t"));
+					assert (ts.length == 6);
+
+					// Test adding descendant
+					b3.append_child (doc.create_element ("t"));
+					assert (ts.length == 7);
+
+					// Test situation where we add a node tree
+					XNode b4;
+					XNode d, d2;
+
+					b4 = doc.create_element ("B");
+					b4.append_child (doc.create_element ("t"));
+					d = doc.create_element ("D");
+					d.append_child (t2 = doc.create_element ("t"));
+					b4.append_child (d);
+
+					bs.append_child (b4);
+
+					assert (ts.length == 9);
+
+					// Test situation where we use insert_before
+					d2 = doc.create_element ("D");
+					d2.append_child (doc.create_element ("t"));
+					b4.insert_before (d2, d);
+
+					assert (ts.length == 10);
+
+					// Test situation where we add a document fragment
+					DocumentFragment frag;
+
+					frag = doc.create_document_fragment ();
+					frag.append_child (doc.create_element ("t"));
+					d = doc.create_element ("D");
+					d.append_child (doc.create_element ("t"));
+					frag.append_child (d);
+					d2 = doc.create_element ("D");
+					d2.append_child (doc.create_element ("t"));
+					frag.insert_before (d2, d);
+
+					b4.append_child (frag);
+					assert (ts.length == 13);
+
+					// Test removing single child
+					t1.parent_node.remove_child (t1);
+					assert (ts.length == 12);
+
+					// Test removing deeper descendant
+					t2.parent_node.remove_child (t2);
+					assert (ts.length == 11);
+
+					// Test removing subtree
+					b4 = b4.parent_node.remove_child (b4);
+
+					assert (ts.length == 6);
+
+					// Test restoring subtree
+					bs.append_child (b4);
+					assert (ts.length == 11);
+				} catch (GXml.Dom.DomError e) {
+					GLib.warning ("%s", e.message);
+					assert (false);
+				}
+			});
 		Test.add_func ("/gxml/element/normalize", () => {
 				try {
 					Element elem = get_elem_new_doc ("tagname");



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