diff -ur bs4.1307471_fixed/element.py bs4/element.py --- bs4.1307471_fixed/element.py 2014-04-14 13:41:45.000000000 +0100 +++ bs4/element.py 2014-04-14 13:22:49.000000000 +0100 @@ -674,6 +674,9 @@ "'%s' object has no attribute '%s'" % ( self.__class__.__name__, attr)) + def clone(self): + return type(self)(self) + def output_ready(self, formatter="minimal"): output = self.format_string(self, formatter) return self.PREFIX + output + self.SUFFIX @@ -878,6 +881,18 @@ for element in self.contents[:]: element.extract() + def clone(self): + """ + Create a clone; a copy of the element and all contents. + """ + copy = type(self)(None, self.builder, self.name, self.namespace, + self.nsprefix, self.attrs) + for attr in ('can_be_empty_element', 'hidden'): + setattr(copy, attr, getattr(self, attr)) + for child in self.contents: + copy.append(child.clone()) + return copy + def index(self, element): """ Find the index of a child by identity, not value. Avoids issues with Only in bs4: element.py.1307471_fixed.py Only in bs4: element.py.orig diff -ur bs4.1307471_fixed/tests/test_tree.py bs4/tests/test_tree.py --- bs4.1307471_fixed/tests/test_tree.py 2014-04-14 13:41:45.000000000 +0100 +++ bs4/tests/test_tree.py 2014-04-14 13:40:34.000000000 +0100 @@ -1100,6 +1100,13 @@ soup.a.string = cdata self.assertTrue(isinstance(soup.a.string, CData)) + def test_clone(self): + soup = self.soup('foo') + clone = soup.a.clone() + self.assertFalse(clone is soup.a) + self.assertTrue(clone.parent is None) + self.assertEqual(str(clone), str(soup.a)) + class TestElementObjects(SoupTest): """Test various features of element objects.""" Only in bs4/tests: test_tree.py.orig