Source code for ecoxipy.etree_output
# -*- coding: utf-8 -*-
u'''\
:mod:`ecoxipy.etree_output` - Building ElementTree Data
=======================================================
:class:`ETreeOutput` creates :mod:`xml.etree.ElementTree` structures.
.. _ecoxipy.etree_output.examples:
Usage Example:
>>> from xml.dom.minidom import getDOMImplementation
>>> etree_output = ETreeOutput()
>>> from ecoxipy import MarkupBuilder
>>> b = MarkupBuilder(etree_output)
>>> xml_doc = b[:'section':True] (
... b.section(
... b.p(b & 'Hello World!'),
... None,
... b(u'<p>äöüß</p>'),
... b.p('<&>'),
... b(
... '<raw/>text', b.br,
... (i for i in range(3)), (i for i in range(3, 6))
... ),
... b | '<This is a comment!>',
... b['pi-target':'<PI content>'],
... b['pi-without-content':],
... attr='\\'"<&>'
... )
... )
>>> from io import BytesIO
>>> bytes_io = BytesIO()
>>> xml_doc.write(bytes_io, 'utf-8', True)
>>> document_string = u"""<?xml version='1.0' encoding='utf-8'?>\\n<section attr="'"<&>"><p>Hello World!</p><p>äöüß</p><p><&></p><raw />text<br />012345<!--<This is a comment!>--><?pi-target <PI content>?><?pi-without-content?></section>"""
>>> bytes_io.getvalue() == document_string.encode('UTF-8')
True
'''
from ecoxipy import Output, _unicode
[docs]class ETreeOutput(Output):
'''\
An :class:`Output` implementation which creates
:mod:`xml.etree.ElementTree` structures.
:param element_factory: A :mod:`xml.etree.ElementTree`-compatible
factory. If this is :const:`None` :mod:`xml.etree.ElementTree` is
used.
'''
def __init__(self, element_factory=None):
if element_factory is None:
from xml.etree import ElementTree
element_factory = ElementTree
self._element_factory = element_factory
from collections import deque as _deque
[docs] def is_native_type(self, content):
'''\
Tests if an object is a ``etree`` object by calling :meth:`iselement`
of the element factory.
:returns: :const:`True` for compatible :mod:`xml.etree.ElementTree`
objects, :const:`False` otherwise.
'''
return self._element_factory.iselement(content)
[docs] def element(self, name, children, attributes):
'''\
Creates an element.
'''
element = self._element_factory.Element(name, attributes)
if len(children) < 2:
try:
child = children.popleft()
if child.__class__ is _unicode:
element.text = child
else:
element.append(child)
except IndexError:
pass
return element
texts = None
previous = None
def handle_texts():
if texts is None or len(texts) == 0:
return
joined_texts = u''.join(texts)
texts.clear()
if previous is None:
element.text = joined_texts
else:
previous.tail = joined_texts
for child in children:
if child.__class__ is _unicode:
if texts is None:
texts = self._deque()
texts.append(child)
else:
handle_texts()
element.append(child)
previous = child
handle_texts()
return element
[docs] def text(self, content):
'''\
Creates an Unicode string.
'''
return content
[docs] def processing_instruction(self, target, content):
'''\
Creates a processing instruction element.
'''
return self._element_factory.ProcessingInstruction(
target, content)
[docs] def document(self, doctype_name, doctype_publicid, doctype_systemid,
children, omit_xml_declaration, encoding):
'''\
Creates an :mod:`xml.etree.ElementTree.ElementTree`-compatible object
using the factory.
As :mod:`xml.etree.ElementTree` lacks support for document type
declarations, the ``doctype_*`` parameters are ignored. Element tree
wrappers do not allow specification of the output encoding and of the
XML declaration, so ``encoding`` and ``omit_xml_declaration`` are also
ignored. As element trees only allow one root element, the length of
``children`` must be zero or one, otherwise a :class:`ValueError` is
raised.
'''
if len(children) == 0:
root_element = None
elif len(children) > 1:
raise ValueError('Only one root element is allowed.')
else:
root_element = children.popleft()
return self._element_factory.ElementTree(root_element)
del Output