+class TreeBuilder:
+ @property
+ def cursor(self):
+ return self.current_cursors[-1]
+
+ def enter_fragment(self, fragment):
+ cursor = self.cursors.get(fragment, self.cursor)
+ self.current_cursors.append(cursor)
+
+ def exit_fragment(self):
+ self.current_cursors.pop()
+
+ def create_fragment(self, name, element):
+ assert name not in self.cursors
+ self.cursors[name] = element
+
+ def forget_fragment(self, name):
+ del self.cursors[name]
+
+ def start_element(self, tag, attrib=None):
+ self.current_cursors.append(etree.SubElement(
+ self.cursor,
+ tag,
+ **(attrib or {})
+ ))
+
+ def end_element(self):
+ self.current_cursors.pop()
+
+ def push_text(self, text):
+ cursor = self.cursor
+ if len(cursor):
+ cursor[-1].tail = (cursor[-1].tail or '') + text
+ else:
+ cursor.text = (cursor.text or '') + text
+
+
+class HtmlBuilder(TreeBuilder):
+ build_method_fn = 'html_build'