summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--TODO14
-rw-r--r--bs4/__init__.py6
-rw-r--r--bs4/element.py28
-rw-r--r--bs4/tests/test_tree.py34
4 files changed, 68 insertions, 14 deletions
diff --git a/TODO b/TODO
index e0e4927..1920d01 100644
--- a/TODO
+++ b/TODO
@@ -1,22 +1,8 @@
-Tag.insert_before() and Tag.insert_after()
-
-Also, I think you can avoid the variable altogether by having repr
-return the version without substituting the html entities. This seems
-fine because a truly canonical representation of the object itself
-would not be all that useful compared to the unicode
-representation. Of course, this breaks anything
-
----------------------
-
-
Bugs
----
* I think whitespace may not be processed correctly.
-* Characters like & < > should always be converted to HTML entities on
- output, even if substitute_html_entities is False.
-
* html5lib doesn't support SoupStrainers, which is OK, but there
should be a warning about it.
diff --git a/bs4/__init__.py b/bs4/__init__.py
index 21e5d6c..58f2960 100644
--- a/bs4/__init__.py
+++ b/bs4/__init__.py
@@ -197,6 +197,12 @@ class BeautifulSoup(Tag):
"""Create a new tag associated with this soup."""
return Tag(None, None, name, attrs)
+ def new_string(self, s):
+ """Create a new NavigableString associated with this soup."""
+ navigable = NavigableString(s)
+ navigable.setup()
+ return navigable
+
def popTag(self):
tag = self.tagStack.pop()
#print "Pop", tag.name
diff --git a/bs4/element.py b/bs4/element.py
index b176777..478d285 100644
--- a/bs4/element.py
+++ b/bs4/element.py
@@ -190,6 +190,34 @@ class PageElement(object):
"""Appends the given tag to the contents of this tag."""
self.insert(len(self.contents), tag)
+ def insert_before(self, successor):
+ """Makes this element the immediate predecessor of the given element.
+
+ The two elements will have the same parent, and this element
+ will be immediately before the given one.
+ """
+ parent = successor.parent
+ if parent is None:
+ raise ValueError(
+ "Destination has no parent, so 'before' has no meaning.")
+ self.extract()
+ index = parent.index(successor)
+ parent.insert(index, self)
+
+ def insert_after(self, predecessor):
+ """Makes this element the immediate successor of the given element.
+
+ The two elements will have the same parent, and this element
+ will be immediately after the given one.
+ """
+ parent = predecessor.parent
+ if parent is None:
+ raise ValueError(
+ "Destination has no parent, so 'after' has no meaning.")
+ self.extract()
+ index = parent.index(predecessor)
+ parent.insert(index+1, self)
+
def find_next(self, name=None, attrs={}, text=None, **kwargs):
"""Returns the first item that matches the given criteria and
appears after this Tag in the document."""
diff --git a/bs4/tests/test_tree.py b/bs4/tests/test_tree.py
index 5552347..a457ddc 100644
--- a/bs4/tests/test_tree.py
+++ b/bs4/tests/test_tree.py
@@ -678,6 +678,40 @@ class TestTreeModification(SoupTest):
soup.br.insert(1, "Contents")
self.assertEqual(str(soup.br), "<br>Contents</br>")
+ def test_insert_before(self):
+ soup = self.soup("<a>foo</a><b>bar</b>")
+ soup.new_string("BAZ").insert_before(soup.b)
+ soup.new_string("QUUX").insert_before(soup.a)
+ self.assertEquals(
+ soup.decode(), self.document_for("QUUX<a>foo</a>BAZ<b>bar</b>"))
+
+ soup.b.insert_before(soup.a)
+ self.assertEquals(
+ soup.decode(), self.document_for("QUUX<b>bar</b><a>foo</a>BAZ"))
+
+
+ def test_insert_after(self):
+ soup = self.soup("<a>foo</a><b>bar</b>")
+ soup.new_string("BAZ").insert_after(soup.b)
+ soup.new_string("QUUX").insert_after(soup.a)
+ self.assertEquals(
+ soup.decode(), self.document_for("<a>foo</a>QUUX<b>bar</b>BAZ"))
+ soup.a.insert_after(soup.b)
+ self.assertEquals(
+ soup.decode(), self.document_for("QUUX<b>bar</b><a>foo</a>BAZ"))
+
+ def test_insert_after_raises_valueerror_if_after_has_no_meaning(self):
+ soup = self.soup("")
+ tag = soup.new_tag("a")
+ string = soup.new_string("")
+ self.assertRaises(ValueError, string.insert_after, tag)
+
+ def test_insert_before_raises_valueerror_if_before_has_no_meaning(self):
+ soup = self.soup("")
+ tag = soup.new_tag("a")
+ string = soup.new_string("")
+ self.assertRaises(ValueError, string.insert_before, tag)
+
def test_replace_with(self):
soup = self.soup(
"<p>There's <b>no</b> business like <b>show</b> business</p>")