diff --git a/README.md b/README.md
index ef5c148..73bb320 100644
--- a/README.md
+++ b/README.md
@@ -18,22 +18,22 @@ from display_xml import XML
XML('
+
{content}
+
"""
-
+
NAMED_STYLE_TEMPLATE = (
- """
{extras[style_name]}
""" +
- HTML_TEMPLATE +
+ """
{extras[style_name]}
""" +
+ HTML_TEMPLATE +
"
"
)
- def __init__(self, in_obj, style='default', template=None,
- extras={}):
- '''
+ _other_params_docstring = """expand: bool
+ Whether or not to expand the XML elements by default.
+ pretty_print: int
+ By how much to increase the indentation level between parent element
+ and child element.
+ """
+
+ def __init__(self, in_obj, style='default', template=None,
+ extras=None, expand=False, pretty_print=1):
+ f"""
Parameters
----------
in_obj : str, lxml.etree._Element, lxml.etree._ElementTree, or bytes
Object to be displayed as html
style : str, optional
Pygment style names (the default is 'default')
- '''
+ expand: bool
+ Whether or not to expand the XML elements by default.
+ pretty_print: int
+ By how much to increase the indentation level between parent element
+ and child element.
+ """
+ if extras is None:
+ extras = {}
+
if template is None:
template = self.HTML_TEMPLATE
-
+
if isinstance(in_obj, (str, bytes)):
- self.xml = et.fromstring(in_obj, parser=no_blank_parser)
+ self._xml = et.fromstring(in_obj, parser=no_blank_parser)
elif isinstance(in_obj, et._ElementTree):
- self.xml = in_obj.getroot()
+ self._xml = in_obj.getroot()
elif isinstance(in_obj, et._Element):
- self.xml = in_obj
+ self._xml = in_obj
else:
raise TypeError(f"{in_obj} is of type {type(in_obj)}."
"This object only can displays objects of type "
"str, bytes, lxml.etree._ElementTree, or "
"lxml.etree._Element.")
-
- self.text = et.tostring(self.xml, pretty_print=True)
+
self.style = style
self.formatter = HtmlFormatter(style=self.style)
self.uuid_class = "a"+str(self.uuid)
self.template = template
self.extras = extras
-
+ self.expand = expand
+ self.pretty_print = pretty_print
+
+
+ def _make_foldable(self, xml):
+ """Make the document foldable.
+
+ Add
elements above all parent nodes.
+ """
+ details = et.Element("details")
+ summary = et.Element("summary")
+ summary.text = xml.tag # TODO: include attributes
+ details.append(summary)
+ root = et.Element(xml.tag)
+ root.text = xml.text
+ root.tail = xml.tail
+ for node in xml:
+ foldable_node = self._make_foldable(node)
+ root.append(foldable_node)
+ details.append(root)
+ return details
+
@classmethod
- def display_all_styles(cls, in_obj):
+ def display_all_styles(cls, in_obj, **kwargs):
"""
Displays all available pygments styles using XML.style_gen()
-
+
Parameters
----------
-
+
in_obj: str lxml.etree._Element, lxml.ettree._ElementTree, or bytes
Object to be displayed as html
- """
- for disp in cls.style_gen(in_obj):
+ kwargs: passed to cls.style_gen method.
+ """.format(cls._other_params_docstring)
+ for disp in cls.style_gen(in_obj, **kwargs):
display(disp)
-
+
@classmethod
- def style_gen(cls, in_obj):
+ def style_gen(cls, in_obj, **kwargs):
"""
Generator for iterating over all of the styles available from pygments.
-
+
If you declare this xml = XML.style_gen(text), use next(xml).
+
+ in_obj: str lxml.etree._Element, lxml.ettree._ElementTree, or bytes
+ Object to be displayed as html
+ kwargs: passed to cls.__init__.
"""
for style in get_all_styles():
- yield(cls(in_obj,
- style=style,
- template=cls.NAMED_STYLE_TEMPLATE,
- extras={"style_name": style}
+ yield(cls(in_obj,
+ style=style,
+ template=cls.NAMED_STYLE_TEMPLATE,
+ extras={"style_name": style},
+ **kwargs
))
-
+
@property
def style_css(self):
"""
- Generates the css classes needed to apply this uniquely.
-
- TODO: it might be nice to move toward a vdom based displayer for more versatile control
-
- TODO: figure out a way to add a toggleable arrow for collapsing this
+ Generates the css classes needed to apply this uniquely.
+
+ TODO: it might be nice to move toward a vdom based displayer
+ for more versatile control
"""
+ details_css = """
+{div} pre {{ margin: 0 0; font-family: inherit;}} /* consistent font for opening and closing tags */
+{div} .highlight {{ display: inline}}
+{div} summary::marker {{ font-size: 0.66em; margin-inline-end: 0.4em; }} /* marker for firefox */
+{div} summary::-webkit-details-marker {{width: 0.66em; margin-inline-end: 0.4em;}} /* marker for chrome */
+{div} .indented-xml-content {{padding-left:1.06em;}}
+""".format(div=f"div.{self.uuid_class}") # noqa
temp_css = self.formatter.get_style_defs()
- css_list = [f"div.{self.uuid_class} {x}" for x in temp_css.split("\n")]
+ css_list = [
+ f"div.{self.uuid_class} {x}" for x in temp_css.split("\n")
+ ] + details_css.split('\n')
return "\n".join(css_list)
@property
@@ -105,9 +210,60 @@ def uuid(self):
return uuid4()
def _repr_html_(self):
- content = highlight(self.text, XmlLexer(), self.formatter)
- return self.template.format(uuid_class=self.uuid_class,
- style_css=self.style_css,
- content=content,
- extras=self.extras
- )
+ content = tostring(
+ self._xml,
+ hook=self._foldable_to_string_hook,
+ indent_increment_size=int(self.pretty_print)
+ )
+ return self.template.format(
+ uuid_class=self.uuid_class,
+ style_css=self.style_css,
+ content=content,
+ extras=self.extras,
+ )
+
+ def _foldable_to_string_hook(self, tag, attributes, text, children,
+ tail, indent):
+ """Return foldable content string.
+
+ Use element to make the string foldable.
+ https://developer.mozilla.org/en-US/docs/Web/HTML/Element/details
+
+ This is a hook function to use in combination with the ``tostring``
+ function defined in this module. It receives HTML string representation
+ of all the components in the XML's element.
+
+ Parameters
+ ----------
+ tag: str
+ The element's tag name.
+ attributes: str
+ The element's tag's attributes, of teh form "attr1='val1'
+ attr2='val2'".
+ text: str
+ The element's text.
+ children: str
+ The HTML text representing the element's children.
+ tail: str
+ Text representing the element's tail.
+ indent: integer
+ Indentation level for this element (in ems).
+ """
+ def highlight_string(string):
+ return highlight(string, XmlLexer(), self.formatter)
+
+ opening_tag = highlight_string(f"<{tag}{attributes}>").replace(
+ '', '').replace('', '')
+ closing_tag = highlight_string(f"{tag}>")
+ foldable_content = f"""
+
+
+ {opening_tag}
+
+ {text}{children}
+ {closing_tag}{tail}
+
+
+
+"""
+ return foldable_content
diff --git a/example_notebook.ipynb b/example_notebook.ipynb
new file mode 100644
index 0000000..5fc3569
--- /dev/null
+++ b/example_notebook.ipynb
@@ -0,0 +1,4893 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Example Notebook for display_xml"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "By default the output is folded. "
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ " \n",
+ " \n",
+ " \n",
+ "
\n",
+ "
\n",
+ " <body>\n",
+ "
\n",
+ "
\n",
+ " \n",
+ " \n",
+ "
\n",
+ "
\n",
+ " <tag>\n",
+ "
\n",
+ "
\n",
+ " \n",
+ " content\n",
+ "
\n",
+ "\n",
+ "
\n",
+ " \n",
+ "
\n",
+ "\n",
+ "
\n",
+ "\n",
+ "
\n",
+ " \n",
+ "
\n",
+ "\n",
+ "
\n",
+ "\n",
+ " "
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "execution_count": 1,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "from display_xml import XML\n",
+ "XML('content')"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "To expand all elements by default, use `expand=True`."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ " \n",
+ " \n",
+ " \n",
+ "
\n",
+ "
\n",
+ " <body>\n",
+ "
\n",
+ "
\n",
+ " \n",
+ " \n",
+ "
\n",
+ "
\n",
+ " <tag>\n",
+ "
\n",
+ "
\n",
+ " \n",
+ " content\n",
+ "
\n",
+ "\n",
+ "
\n",
+ " \n",
+ "
\n",
+ "\n",
+ "
\n",
+ "\n",
+ "
\n",
+ " \n",
+ "
\n",
+ "\n",
+ "
\n",
+ "\n",
+ " "
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "execution_count": 2,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "XML('content', expand=True) "
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Set `pretty_print` to control the width of the indentation level. The default is 1\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ " \n",
+ " \n",
+ " \n",
+ "
\n",
+ "
\n",
+ " <body>\n",
+ "
\n",
+ "
\n",
+ " \n",
+ " \n",
+ "
\n",
+ "
\n",
+ " <tag>\n",
+ "
\n",
+ "
\n",
+ " \n",
+ " content\n",
+ "
\n",
+ "\n",
+ "
\n",
+ " \n",
+ "
\n",
+ "\n",
+ "
\n",
+ "\n",
+ "
\n",
+ " \n",
+ "
\n",
+ "\n",
+ "
\n",
+ "\n",
+ " "
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "execution_count": 3,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "XML('content', expand=True, pretty_print=0) "
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ " \n",
+ " \n",
+ " \n",
+ "
\n",
+ "
\n",
+ " <body>\n",
+ "
\n",
+ "
\n",
+ " \n",
+ " \n",
+ "
\n",
+ "
\n",
+ " <tag>\n",
+ "
\n",
+ "
\n",
+ " \n",
+ " content\n",
+ "
\n",
+ "\n",
+ "
\n",
+ " \n",
+ "
\n",
+ "\n",
+ "
\n",
+ "\n",
+ "
\n",
+ " \n",
+ "
\n",
+ "\n",
+ "
\n",
+ "\n",
+ " "
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "execution_count": 4,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "XML('content', expand=True, pretty_print=3) "
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Styles"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 6,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ " default
\n",
+ " \n",
+ " \n",
+ " \n",
+ "
\n",
+ "
\n",
+ " <body>\n",
+ "
\n",
+ "
\n",
+ " \n",
+ " \n",
+ "
\n",
+ "
\n",
+ " <tag>\n",
+ "
\n",
+ "
\n",
+ " \n",
+ " content\n",
+ "
\n",
+ "\n",
+ "
\n",
+ " \n",
+ "
\n",
+ "\n",
+ "
\n",
+ "\n",
+ "
\n",
+ " \n",
+ "
\n",
+ "\n",
+ "
\n",
+ "\n",
+ "
"
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/html": [
+ " emacs
\n",
+ " \n",
+ " \n",
+ " \n",
+ "
\n",
+ "
\n",
+ " <body>\n",
+ "
\n",
+ "
\n",
+ " \n",
+ " \n",
+ "
\n",
+ "
\n",
+ " <tag>\n",
+ "
\n",
+ "
\n",
+ " \n",
+ " content\n",
+ "
\n",
+ "\n",
+ "
\n",
+ " \n",
+ "
\n",
+ "\n",
+ "
\n",
+ "\n",
+ "
\n",
+ " \n",
+ "
\n",
+ "\n",
+ "
\n",
+ "\n",
+ "
"
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/html": [
+ " friendly
\n",
+ " \n",
+ " \n",
+ " \n",
+ "
\n",
+ "
\n",
+ " <body>\n",
+ "
\n",
+ "
\n",
+ " \n",
+ " \n",
+ "
\n",
+ "
\n",
+ " <tag>\n",
+ "
\n",
+ "
\n",
+ " \n",
+ " content\n",
+ "
\n",
+ "\n",
+ "
\n",
+ " \n",
+ "
\n",
+ "\n",
+ "
\n",
+ "\n",
+ "
\n",
+ " \n",
+ "
\n",
+ "\n",
+ "
\n",
+ "\n",
+ "
"
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/html": [
+ " colorful
\n",
+ " \n",
+ " \n",
+ " \n",
+ "
\n",
+ "
\n",
+ " <body>\n",
+ "
\n",
+ "
\n",
+ " \n",
+ " \n",
+ "
\n",
+ "
\n",
+ " <tag>\n",
+ "
\n",
+ "
\n",
+ " \n",
+ " content\n",
+ "
\n",
+ "\n",
+ "
\n",
+ " \n",
+ "
\n",
+ "\n",
+ "
\n",
+ "\n",
+ "
\n",
+ " \n",
+ "
\n",
+ "\n",
+ "
\n",
+ "\n",
+ "
"
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/html": [
+ " autumn
\n",
+ " \n",
+ " \n",
+ " \n",
+ "
\n",
+ "
\n",
+ " <body>\n",
+ "
\n",
+ "
\n",
+ " \n",
+ " \n",
+ "
\n",
+ "
\n",
+ " <tag>\n",
+ "
\n",
+ "
\n",
+ " \n",
+ " content\n",
+ "
\n",
+ "\n",
+ "
\n",
+ " \n",
+ "
\n",
+ "\n",
+ "
\n",
+ "\n",
+ "
\n",
+ " \n",
+ "
\n",
+ "\n",
+ "
\n",
+ "\n",
+ "
"
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/html": [
+ " murphy
\n",
+ " \n",
+ " \n",
+ " \n",
+ "
\n",
+ "
\n",
+ " <body>\n",
+ "
\n",
+ "
\n",
+ " \n",
+ " \n",
+ "
\n",
+ "
\n",
+ " <tag>\n",
+ "
\n",
+ "
\n",
+ " \n",
+ " content\n",
+ "
\n",
+ "\n",
+ "
\n",
+ " \n",
+ "
\n",
+ "\n",
+ "
\n",
+ "\n",
+ "
\n",
+ " \n",
+ "
\n",
+ "\n",
+ "
\n",
+ "\n",
+ "
"
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/html": [
+ " manni
\n",
+ " \n",
+ " \n",
+ " \n",
+ "
\n",
+ "
\n",
+ " <body>\n",
+ "
\n",
+ "
\n",
+ " \n",
+ " \n",
+ "
\n",
+ "
\n",
+ " <tag>\n",
+ "
\n",
+ "
\n",
+ " \n",
+ " content\n",
+ "
\n",
+ "\n",
+ "
\n",
+ " \n",
+ "
\n",
+ "\n",
+ "
\n",
+ "\n",
+ "
\n",
+ " \n",
+ "
\n",
+ "\n",
+ "
\n",
+ "\n",
+ "
"
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/html": [
+ " monokai
\n",
+ " \n",
+ " \n",
+ " \n",
+ "
\n",
+ "
\n",
+ " <body>\n",
+ "
\n",
+ "
\n",
+ " \n",
+ " \n",
+ "
\n",
+ "
\n",
+ " <tag>\n",
+ "
\n",
+ "
\n",
+ " \n",
+ " content\n",
+ "
\n",
+ "\n",
+ "
\n",
+ " \n",
+ "
\n",
+ "\n",
+ "
\n",
+ "\n",
+ "
\n",
+ " \n",
+ "
\n",
+ "\n",
+ "
\n",
+ "\n",
+ "
"
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/html": [
+ " perldoc
\n",
+ " \n",
+ " \n",
+ " \n",
+ "
\n",
+ "
\n",
+ " <body>\n",
+ "
\n",
+ "
\n",
+ " \n",
+ " \n",
+ "
\n",
+ "
\n",
+ " <tag>\n",
+ "
\n",
+ "
\n",
+ " \n",
+ " content\n",
+ "
\n",
+ "\n",
+ "
\n",
+ " \n",
+ "
\n",
+ "\n",
+ "
\n",
+ "\n",
+ "
\n",
+ " \n",
+ "
\n",
+ "\n",
+ "
\n",
+ "\n",
+ "
"
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/html": [
+ " pastie
\n",
+ " \n",
+ " \n",
+ " \n",
+ "
\n",
+ "
\n",
+ " <body>\n",
+ "
\n",
+ "
\n",
+ " \n",
+ " \n",
+ "
\n",
+ "
\n",
+ " <tag>\n",
+ "
\n",
+ "
\n",
+ " \n",
+ " content\n",
+ "
\n",
+ "\n",
+ "
\n",
+ " \n",
+ "
\n",
+ "\n",
+ "
\n",
+ "\n",
+ "
\n",
+ " \n",
+ "
\n",
+ "\n",
+ "
\n",
+ "\n",
+ "
"
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/html": [
+ " borland
\n",
+ " \n",
+ " \n",
+ " \n",
+ "
\n",
+ "
\n",
+ " <body>\n",
+ "
\n",
+ "
\n",
+ " \n",
+ " \n",
+ "
\n",
+ "
\n",
+ " <tag>\n",
+ "
\n",
+ "
\n",
+ " \n",
+ " content\n",
+ "
\n",
+ "\n",
+ "
\n",
+ " \n",
+ "
\n",
+ "\n",
+ "
\n",
+ "\n",
+ "
\n",
+ " \n",
+ "
\n",
+ "\n",
+ "
\n",
+ "\n",
+ "
"
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/html": [
+ " trac
\n",
+ " \n",
+ " \n",
+ " \n",
+ "
\n",
+ "
\n",
+ " <body>\n",
+ "
\n",
+ "
\n",
+ " \n",
+ " \n",
+ "
\n",
+ "
\n",
+ " <tag>\n",
+ "
\n",
+ "
\n",
+ " \n",
+ " content\n",
+ "
\n",
+ "\n",
+ "
\n",
+ " \n",
+ "
\n",
+ "\n",
+ "
\n",
+ "\n",
+ "
\n",
+ " \n",
+ "
\n",
+ "\n",
+ "
\n",
+ "\n",
+ "
"
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/html": [
+ " native
\n",
+ " \n",
+ " \n",
+ " \n",
+ "
\n",
+ "
\n",
+ " <body>\n",
+ "
\n",
+ "
\n",
+ " \n",
+ " \n",
+ "
\n",
+ "
\n",
+ " <tag>\n",
+ "
\n",
+ "
\n",
+ " \n",
+ " content\n",
+ "
\n",
+ "\n",
+ "
\n",
+ " \n",
+ "
\n",
+ "\n",
+ "
\n",
+ "\n",
+ "
\n",
+ " \n",
+ "
\n",
+ "\n",
+ "
\n",
+ "\n",
+ "
"
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/html": [
+ " fruity
\n",
+ " \n",
+ " \n",
+ " \n",
+ "
\n",
+ "
\n",
+ " <body>\n",
+ "
\n",
+ "
\n",
+ " \n",
+ " \n",
+ "
\n",
+ "
\n",
+ " <tag>\n",
+ "
\n",
+ "
\n",
+ " \n",
+ " content\n",
+ "
\n",
+ "\n",
+ "
\n",
+ " \n",
+ "
\n",
+ "\n",
+ "
\n",
+ "\n",
+ "
\n",
+ " \n",
+ "
\n",
+ "\n",
+ "
\n",
+ "\n",
+ "
"
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/html": [
+ " bw
\n",
+ " \n",
+ " \n",
+ " \n",
+ "
\n",
+ "
\n",
+ " <body>\n",
+ "
\n",
+ "
\n",
+ " \n",
+ " \n",
+ "
\n",
+ "
\n",
+ " <tag>\n",
+ "
\n",
+ "
\n",
+ " \n",
+ " content\n",
+ "
\n",
+ "\n",
+ "
\n",
+ " \n",
+ "
\n",
+ "\n",
+ "
\n",
+ "\n",
+ "
\n",
+ " \n",
+ "
\n",
+ "\n",
+ "
\n",
+ "\n",
+ "
"
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/html": [
+ " vim
\n",
+ " \n",
+ " \n",
+ " \n",
+ "
\n",
+ "
\n",
+ " <body>\n",
+ "
\n",
+ "
\n",
+ " \n",
+ " \n",
+ "
\n",
+ "
\n",
+ " <tag>\n",
+ "
\n",
+ "
\n",
+ " \n",
+ " content\n",
+ "
\n",
+ "\n",
+ "
\n",
+ " \n",
+ "
\n",
+ "\n",
+ "
\n",
+ "\n",
+ "
\n",
+ " \n",
+ "
\n",
+ "\n",
+ "
\n",
+ "\n",
+ "
"
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/html": [
+ " vs
\n",
+ " \n",
+ " \n",
+ " \n",
+ "
\n",
+ "
\n",
+ " <body>\n",
+ "
\n",
+ "
\n",
+ " \n",
+ " \n",
+ "
\n",
+ "
\n",
+ " <tag>\n",
+ "
\n",
+ "
\n",
+ " \n",
+ " content\n",
+ "
\n",
+ "\n",
+ "
\n",
+ " \n",
+ "
\n",
+ "\n",
+ "
\n",
+ "\n",
+ "
\n",
+ " \n",
+ "
\n",
+ "\n",
+ "
\n",
+ "\n",
+ "
"
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/html": [
+ " tango
\n",
+ " \n",
+ " \n",
+ " \n",
+ "
\n",
+ "
\n",
+ " <body>\n",
+ "
\n",
+ "
\n",
+ " \n",
+ " \n",
+ "
\n",
+ "
\n",
+ " <tag>\n",
+ "
\n",
+ "
\n",
+ " \n",
+ " content\n",
+ "
\n",
+ "\n",
+ "
\n",
+ " \n",
+ "
\n",
+ "\n",
+ "
\n",
+ "\n",
+ "
\n",
+ " \n",
+ "
\n",
+ "\n",
+ "
\n",
+ "\n",
+ "
"
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/html": [
+ " rrt
\n",
+ " \n",
+ " \n",
+ " \n",
+ "
\n",
+ "
\n",
+ " <body>\n",
+ "
\n",
+ "
\n",
+ " \n",
+ " \n",
+ "
\n",
+ "
\n",
+ " <tag>\n",
+ "
\n",
+ "
\n",
+ " \n",
+ " content\n",
+ "
\n",
+ "\n",
+ "
\n",
+ " \n",
+ "
\n",
+ "\n",
+ "
\n",
+ "\n",
+ "
\n",
+ " \n",
+ "
\n",
+ "\n",
+ "
\n",
+ "\n",
+ "
"
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/html": [
+ " xcode
\n",
+ " \n",
+ " \n",
+ " \n",
+ "
\n",
+ "
\n",
+ " <body>\n",
+ "
\n",
+ "
\n",
+ " \n",
+ " \n",
+ "
\n",
+ "
\n",
+ " <tag>\n",
+ "
\n",
+ "
\n",
+ " \n",
+ " content\n",
+ "
\n",
+ "\n",
+ "
\n",
+ " \n",
+ "
\n",
+ "\n",
+ "
\n",
+ "\n",
+ "
\n",
+ " \n",
+ "
\n",
+ "\n",
+ "
\n",
+ "\n",
+ "
"
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/html": [
+ " igor
\n",
+ " \n",
+ " \n",
+ " \n",
+ "
\n",
+ "
\n",
+ " <body>\n",
+ "
\n",
+ "
\n",
+ " \n",
+ " \n",
+ "
\n",
+ "
\n",
+ " <tag>\n",
+ "
\n",
+ "
\n",
+ " \n",
+ " content\n",
+ "
\n",
+ "\n",
+ "
\n",
+ " \n",
+ "
\n",
+ "\n",
+ "
\n",
+ "\n",
+ "
\n",
+ " \n",
+ "
\n",
+ "\n",
+ "
\n",
+ "\n",
+ "
"
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/html": [
+ " paraiso-light
\n",
+ " \n",
+ " \n",
+ " \n",
+ "
\n",
+ "
\n",
+ " <body>\n",
+ "
\n",
+ "
\n",
+ " \n",
+ " \n",
+ "
\n",
+ "
\n",
+ " <tag>\n",
+ "
\n",
+ "
\n",
+ " \n",
+ " content\n",
+ "
\n",
+ "\n",
+ "
\n",
+ " \n",
+ "
\n",
+ "\n",
+ "
\n",
+ "\n",
+ "
\n",
+ " \n",
+ "
\n",
+ "\n",
+ "
\n",
+ "\n",
+ "
"
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/html": [
+ " paraiso-dark
\n",
+ " \n",
+ " \n",
+ " \n",
+ "
\n",
+ "
\n",
+ " <body>\n",
+ "
\n",
+ "
\n",
+ " \n",
+ " \n",
+ "
\n",
+ "
\n",
+ " <tag>\n",
+ "
\n",
+ "
\n",
+ " \n",
+ " content\n",
+ "
\n",
+ "\n",
+ "
\n",
+ " \n",
+ "
\n",
+ "\n",
+ "
\n",
+ "\n",
+ "
\n",
+ " \n",
+ "
\n",
+ "\n",
+ "
\n",
+ "\n",
+ "
"
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/html": [
+ " lovelace
\n",
+ " \n",
+ " \n",
+ " \n",
+ "
\n",
+ "
\n",
+ " <body>\n",
+ "
\n",
+ "
\n",
+ " \n",
+ " \n",
+ "
\n",
+ "
\n",
+ " <tag>\n",
+ "
\n",
+ "
\n",
+ " \n",
+ " content\n",
+ "
\n",
+ "\n",
+ "
\n",
+ " \n",
+ "
\n",
+ "\n",
+ "
\n",
+ "\n",
+ "
\n",
+ " \n",
+ "
\n",
+ "\n",
+ "
\n",
+ "\n",
+ "
"
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/html": [
+ " algol
\n",
+ " \n",
+ " \n",
+ " \n",
+ "
\n",
+ "
\n",
+ " <body>\n",
+ "
\n",
+ "
\n",
+ " \n",
+ " \n",
+ "
\n",
+ "
\n",
+ " <tag>\n",
+ "
\n",
+ "
\n",
+ " \n",
+ " content\n",
+ "
\n",
+ "\n",
+ "
\n",
+ " \n",
+ "
\n",
+ "\n",
+ "
\n",
+ "\n",
+ "
\n",
+ " \n",
+ "
\n",
+ "\n",
+ "
\n",
+ "\n",
+ "
"
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/html": [
+ " algol_nu
\n",
+ " \n",
+ " \n",
+ " \n",
+ "
\n",
+ "
\n",
+ " <body>\n",
+ "
\n",
+ "
\n",
+ " \n",
+ " \n",
+ "
\n",
+ "
\n",
+ " <tag>\n",
+ "
\n",
+ "
\n",
+ " \n",
+ " content\n",
+ "
\n",
+ "\n",
+ "
\n",
+ " \n",
+ "
\n",
+ "\n",
+ "
\n",
+ "\n",
+ "
\n",
+ " \n",
+ "
\n",
+ "\n",
+ "
\n",
+ "\n",
+ "
"
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/html": [
+ " arduino
\n",
+ " \n",
+ " \n",
+ " \n",
+ "
\n",
+ "
\n",
+ " <body>\n",
+ "
\n",
+ "
\n",
+ " \n",
+ " \n",
+ "
\n",
+ "
\n",
+ " <tag>\n",
+ "
\n",
+ "
\n",
+ " \n",
+ " content\n",
+ "
\n",
+ "\n",
+ "
\n",
+ " \n",
+ "
\n",
+ "\n",
+ "
\n",
+ "\n",
+ "
\n",
+ " \n",
+ "
\n",
+ "\n",
+ "
\n",
+ "\n",
+ "
"
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/html": [
+ " rainbow_dash
\n",
+ " \n",
+ " \n",
+ " \n",
+ "
\n",
+ "
\n",
+ " <body>\n",
+ "
\n",
+ "
\n",
+ " \n",
+ " \n",
+ "
\n",
+ "
\n",
+ " <tag>\n",
+ "
\n",
+ "
\n",
+ " \n",
+ " content\n",
+ "
\n",
+ "\n",
+ "
\n",
+ " \n",
+ "
\n",
+ "\n",
+ "
\n",
+ "\n",
+ "
\n",
+ " \n",
+ "
\n",
+ "\n",
+ "
\n",
+ "\n",
+ "
"
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/html": [
+ " abap
\n",
+ " \n",
+ " \n",
+ " \n",
+ "
\n",
+ "
\n",
+ " <body>\n",
+ "
\n",
+ "
\n",
+ " \n",
+ " \n",
+ "
\n",
+ "
\n",
+ " <tag>\n",
+ "
\n",
+ "
\n",
+ " \n",
+ " content\n",
+ "
\n",
+ "\n",
+ "
\n",
+ " \n",
+ "
\n",
+ "\n",
+ "
\n",
+ "\n",
+ "
\n",
+ " \n",
+ "
\n",
+ "\n",
+ "
\n",
+ "\n",
+ "
"
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/html": [
+ " solarized-dark
\n",
+ " \n",
+ " \n",
+ " \n",
+ "
\n",
+ "
\n",
+ " <body>\n",
+ "
\n",
+ "
\n",
+ " \n",
+ " \n",
+ "
\n",
+ "
\n",
+ " <tag>\n",
+ "
\n",
+ "
\n",
+ " \n",
+ " content\n",
+ "
\n",
+ "\n",
+ "
\n",
+ " \n",
+ "
\n",
+ "\n",
+ "
\n",
+ "\n",
+ "
\n",
+ " \n",
+ "
\n",
+ "\n",
+ "
\n",
+ "\n",
+ "
"
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/html": [
+ " solarized-light
\n",
+ " \n",
+ " \n",
+ " \n",
+ "
\n",
+ "
\n",
+ " <body>\n",
+ "
\n",
+ "
\n",
+ " \n",
+ " \n",
+ "
\n",
+ "
\n",
+ " <tag>\n",
+ "
\n",
+ "
\n",
+ " \n",
+ " content\n",
+ "
\n",
+ "\n",
+ "
\n",
+ " \n",
+ "
\n",
+ "\n",
+ "
\n",
+ "\n",
+ "
\n",
+ " \n",
+ "
\n",
+ "\n",
+ "
\n",
+ "\n",
+ "
"
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/html": [
+ " sas
\n",
+ " \n",
+ " \n",
+ " \n",
+ "
\n",
+ "
\n",
+ " <body>\n",
+ "
\n",
+ "
\n",
+ " \n",
+ " \n",
+ "
\n",
+ "
\n",
+ " <tag>\n",
+ "
\n",
+ "
\n",
+ " \n",
+ " content\n",
+ "
\n",
+ "\n",
+ "
\n",
+ " \n",
+ "
\n",
+ "\n",
+ "
\n",
+ "\n",
+ "
\n",
+ " \n",
+ "
\n",
+ "\n",
+ "
\n",
+ "\n",
+ "
"
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/html": [
+ " stata
\n",
+ " \n",
+ " \n",
+ " \n",
+ "
\n",
+ "
\n",
+ " <body>\n",
+ "
\n",
+ "
\n",
+ " \n",
+ " \n",
+ "
\n",
+ "
\n",
+ " <tag>\n",
+ "
\n",
+ "
\n",
+ " \n",
+ " content\n",
+ "
\n",
+ "\n",
+ "
\n",
+ " \n",
+ "
\n",
+ "\n",
+ "
\n",
+ "\n",
+ "
\n",
+ " \n",
+ "
\n",
+ "\n",
+ "
\n",
+ "\n",
+ "
"
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/html": [
+ " stata-light
\n",
+ " \n",
+ " \n",
+ " \n",
+ "
\n",
+ "
\n",
+ " <body>\n",
+ "
\n",
+ "
\n",
+ " \n",
+ " \n",
+ "
\n",
+ "
\n",
+ " <tag>\n",
+ "
\n",
+ "
\n",
+ " \n",
+ " content\n",
+ "
\n",
+ "\n",
+ "
\n",
+ " \n",
+ "
\n",
+ "\n",
+ "
\n",
+ "\n",
+ "
\n",
+ " \n",
+ "
\n",
+ "\n",
+ "
\n",
+ "\n",
+ "
"
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/html": [
+ " stata-dark
\n",
+ " \n",
+ " \n",
+ " \n",
+ "
\n",
+ "
\n",
+ " <body>\n",
+ "
\n",
+ "
\n",
+ " \n",
+ " \n",
+ "
\n",
+ "
\n",
+ " <tag>\n",
+ "
\n",
+ "
\n",
+ " \n",
+ " content\n",
+ "
\n",
+ "\n",
+ "
\n",
+ " \n",
+ "
\n",
+ "\n",
+ "
\n",
+ "\n",
+ "
\n",
+ " \n",
+ "
\n",
+ "\n",
+ "
\n",
+ "\n",
+ "
"
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/html": [
+ " inkpot
\n",
+ " \n",
+ " \n",
+ " \n",
+ "
\n",
+ "
\n",
+ " <body>\n",
+ "
\n",
+ "
\n",
+ " \n",
+ " \n",
+ "
\n",
+ "
\n",
+ " <tag>\n",
+ "
\n",
+ "
\n",
+ " \n",
+ " content\n",
+ "
\n",
+ "\n",
+ "
\n",
+ " \n",
+ "
\n",
+ "\n",
+ "
\n",
+ "\n",
+ "
\n",
+ " \n",
+ "
\n",
+ "\n",
+ "
\n",
+ "\n",
+ "
"
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "XML.display_all_styles('content', expand=True)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 14,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ " \n",
+ " \n",
+ " \n",
+ "
\n",
+ "
\n",
+ " <body>\n",
+ "
\n",
+ "
\n",
+ " \n",
+ " \n",
+ "
\n",
+ "
\n",
+ " <tag>\n",
+ "
\n",
+ "
\n",
+ " \n",
+ " content\n",
+ "
\n",
+ "\n",
+ "
\n",
+ " \n",
+ "
\n",
+ "\n",
+ "
\n",
+ "\n",
+ "
\n",
+ " \n",
+ "
\n",
+ "\n",
+ "
\n",
+ "\n",
+ " "
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "execution_count": 14,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "XML('content', expand=True, style=\"perldoc\")"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "display_xml",
+ "language": "python",
+ "name": "display_xml"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.6.10"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 4
+}
diff --git a/images/multi_display_xml_screenshot.jpg b/images/multi_display_xml_screenshot.jpg
deleted file mode 100644
index 4de7ab1..0000000
Binary files a/images/multi_display_xml_screenshot.jpg and /dev/null differ
diff --git a/images/multi_display_xml_screenshot.png b/images/multi_display_xml_screenshot.png
new file mode 100644
index 0000000..9c5136a
Binary files /dev/null and b/images/multi_display_xml_screenshot.png differ
diff --git a/images/single_display_xml_screenshot.jpg b/images/single_display_xml_screenshot.jpg
deleted file mode 100644
index ece6363..0000000
Binary files a/images/single_display_xml_screenshot.jpg and /dev/null differ
diff --git a/images/single_display_xml_screenshot.png b/images/single_display_xml_screenshot.png
new file mode 100644
index 0000000..3db5e44
Binary files /dev/null and b/images/single_display_xml_screenshot.png differ
diff --git a/images/styled_single_xml_screenshot.png b/images/styled_single_xml_screenshot.png
index 509a7ea..c904805 100644
Binary files a/images/styled_single_xml_screenshot.png and b/images/styled_single_xml_screenshot.png differ
diff --git a/setup.py b/setup.py
index 3b650d1..9090fc7 100644
--- a/setup.py
+++ b/setup.py
@@ -5,7 +5,7 @@
from setupbase import (
ensure_python, find_packages, get_version
)
-
+
setup_dict = dict(
name='display_xml',
version=get_version('display_xml/_version.py'),
@@ -29,6 +29,7 @@
'ipython>=6.2.1',
'pygments>=2.2.0',
'lxml>=4.1.1',
+ 'pytest>=3.0'
]
)
@@ -44,4 +45,4 @@
setuptools.setup(
**setup_dict
-)
\ No newline at end of file
+)
diff --git a/tests/test_display_xml.py b/tests/test_display_xml.py
new file mode 100644
index 0000000..bbc5c67
--- /dev/null
+++ b/tests/test_display_xml.py
@@ -0,0 +1,42 @@
+"""
+"""
+from display_xml import tostring
+import lxml.etree as ET
+import pytest
+
+
+@pytest.fixture
+def element():
+ xml = """
+
+ Princess Diana - Prince Charles
+ Prince William
+ Prince Harry
+
+ the end
+
+ """
+ element = ET.fromstring(xml)
+ return element
+
+
+def test_to_string(element):
+ """Test implementation of tostring against lxml's version."""
+ assert tostring(element) == ET.tostring(element).decode('utf-8')
+
+
+def test_to_string_hook(element):
+ """Show how we can now control formatting of xml recursively by
+ using a hook function that receives each formatted component.
+
+ Here we upcase the tags and put the whole element on one line.
+ """
+ def one_liner_hook(tag, attributes, text, children, tail, indent):
+ print(locals())
+ tag = tag.upper()
+ return f"""<{tag}{attributes}>{text.strip()}{children}{tag}>{tail.strip()}""" # noqa
+
+ assert tostring(element, hook=one_liner_hook, pretty_print=False) == (
+ 'Princess Diana - Prince Charles'
+ 'Prince WilliamPrince Harrythe end' # noqa
+ )