diff options
| author | Michael Williamson <mike@zwobble.org> | 2016-03-14 08:10:01 +0000 |
|---|---|---|
| committer | Michael Williamson <mike@zwobble.org> | 2016-03-14 20:09:13 +0000 |
| commit | 00cfd0d5bae2e7688754dfc458016d42abfcd037 (patch) | |
| tree | 24b49bdad94d9c34c755ec50e0db5fb39a34aee8 | |
| parent | 2329dbcbbc945437256569c789b127e454069c98 (diff) | |
Add HTML AST with strip_empty function
| -rw-r--r-- | mammoth/html/__init__.py | 58 | ||||
| -rw-r--r-- | mammoth/html/nodes.py | 32 | ||||
| -rw-r--r-- | tests/html/__init__.py | 1 | ||||
| -rw-r--r-- | tests/html/strip_empty_tests.py | 65 |
4 files changed, 156 insertions, 0 deletions
diff --git a/mammoth/html/__init__.py b/mammoth/html/__init__.py new file mode 100644 index 0000000..905b423 --- /dev/null +++ b/mammoth/html/__init__.py @@ -0,0 +1,58 @@ +from ..lists import flat_map +from .nodes import TextNode, Element, SelfClosingElement, ForceWrite, NodeVisitor + + +def text(value): + return TextNode(value) + + +def element(tag_name, attributes=None, children=None): + if attributes is None: + attributes = {} + if children is None: + children = [] + + return Element([tag_name], attributes, children, collapsible=False) + + +def self_closing_element(tag_name, attributes=None): + if attributes is None: + attributes = {} + + return SelfClosingElement(tag_name, attributes) + + +force_write = ForceWrite() + + +def strip_empty(nodes): + return flat_map(_strip_empty_node, nodes) + + +def _strip_empty_node(node): + return StripEmpty().visit(node) + + +class StripEmpty(NodeVisitor): + def visit_text_node(self, node): + if node.value: + return [node] + else: + return [] + + def visit_element(self, element): + children = strip_empty(element.children) + if len(children) == 0: + return [] + else: + return [Element( + element.tag_names, + element.attributes, + children, + collapsible=element.collapsible)] + + def visit_self_closing_element(self, element): + return [element] + + def visit_force_write(self, node): + return [node] diff --git a/mammoth/html/nodes.py b/mammoth/html/nodes.py new file mode 100644 index 0000000..aae4888 --- /dev/null +++ b/mammoth/html/nodes.py @@ -0,0 +1,32 @@ +import cobble + + +class Node(object): + pass + + +@cobble.data +class TextNode(Node): + value = cobble.field() + + +@cobble.data +class Element(Node): + tag_names = cobble.field() + attributes = cobble.field() + children = cobble.field() + collapsible = cobble.field() + + +@cobble.data +class SelfClosingElement(Node): + tag_name = cobble.field() + attributes = cobble.field() + + +@cobble.visitable +class ForceWrite(Node): + pass + + +NodeVisitor = cobble.visitor(Node) diff --git a/tests/html/__init__.py b/tests/html/__init__.py new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/tests/html/__init__.py @@ -0,0 +1 @@ + diff --git a/tests/html/strip_empty_tests.py b/tests/html/strip_empty_tests.py new file mode 100644 index 0000000..eb28f30 --- /dev/null +++ b/tests/html/strip_empty_tests.py @@ -0,0 +1,65 @@ +from nose.tools import istest, assert_equal + +from mammoth import html + + +@istest +def text_nodes_with_text_are_not_stripped(): + assert_equal( + [html.text("H")], + html.strip_empty([html.text("H")])) + + +@istest +def empty_text_nodes_are_stripped(): + assert_equal( + [], + html.strip_empty([html.text("")])) + + +@istest +def elements_with_non_empty_children_are_not_stripped(): + assert_equal( + [html.element("p", {}, [html.text("H")])], + html.strip_empty([html.element("p", {}, [html.text("H")])])) + + +@istest +def elements_with_no_children_are_stripped(): + assert_equal( + [], + html.strip_empty([html.element("p")])) + + +@istest +def elements_with_only_empty_children_are_stripped(): + assert_equal( + [], + html.strip_empty([html.element("p", {}, [html.text("")])])) + + +@istest +def empty_children_are_removed(): + assert_equal( + html.strip_empty([html.element("ul", {}, [ + html.element("li", {}, [html.text("")]), + html.element("li", {}, [html.text("H")]), + ])]), + + [html.element("ul", {}, [ + html.element("li", {}, [html.text("H")]) + ])]) + + +@istest +def self_closing_elements_are_never_empty(): + assert_equal( + [html.self_closing_element("br")], + html.strip_empty([html.self_closing_element("br")])) + + +@istest +def force_writes_are_never_empty(): + assert_equal( + [html.force_write], + html.strip_empty([html.force_write])) |
