Commits

Alain Poirier committed 0359536

Pure etree elements, comments and PIs can be serialized

  • Participants
  • Parent commits e5a57a7

Comments (0)

Files changed (2)

File nagare/serializer.py

       - ``output`` -- the rendered content
       - ``content_type`` -- the rendered content type
       - ``doctype`` -- the (optional) doctype
-      - ``declaration`` -- is the XML declaration to be outputed ?
+      - ``declaration`` -- is the XML declaration to be outputed?
 
     Return:
       - a tuple (content_type, content)
       - ``output`` -- the rendered content
       - ``content_type`` -- the rendered content type
       - ``doctype`` -- the (optional) doctype
-      - ``declaration`` -- is the XML declaration to be outputed ?
+      - ``declaration`` -- is the XML declaration to be outputed?
 
     Return:
       - a tuple (content_type, content)
         # The browser only accepts HTML
         lxml.html.xhtml_to_html(output)
 
-        output = (doctype + '\n' if declaration else '') + output.write_htmlstring(pretty_print=True)
+        output = output.write_htmlstring(pretty_print=True, doctype=doctype if declaration else None)
 
     return (content_type, output)
 
 
 @peak.rules.when(serialize, (xml._Tag,))
+def serialize(next_method, output, content_type, doctype, declaration):
+    """Generic method to generate a XML text from a tree
+
+    In:
+      - ``output`` -- the rendered content
+      - ``content_type`` -- the rendered content type
+      - ``doctype`` -- the (optional) doctype
+      - ``declaration`` -- is the XML declaration to be outputed?
+
+    Return:
+      - a tuple (content_type, content)
+    """
+    if content_type == 'text/html':
+        output = next_method(output, content_type, doctype, declaration)[1]
+    else:
+        output = output.write_xmlstring(xml_declaration=declaration, doctype=doctype if declaration else None)
+
+    return (content_type, output)
+
+
+@peak.rules.when(serialize, (etree._Element,))
 def serialize(output, content_type, doctype, declaration):
     """Generic method to generate a XML text from a tree
 
       - ``output`` -- the rendered content
       - ``content_type`` -- the rendered content type
       - ``doctype`` -- the (optional) doctype
-      - ``declaration`` -- is the XML declaration to be outputed ?
+      - ``declaration`` -- is the XML declaration to be outputed?
 
     Return:
       - a tuple (content_type, content)
     """
-    r = ('<?xml version="1.0" encoding="UTF-8"?>\n' + doctype + '\n') if declaration else ''
-    return (content_type, r + output.write_xmlstring())
+    if content_type == 'text/html':
+        lxml.html.xhtml_to_html(output)
+        method = 'html'
+        pretty_print = True
+    else:
+        method = 'xml'
+        pretty_print = False
 
-
-@peak.rules.when(serialize, (etree._Comment,))
-def serialize(output, content_type, doctype, declaration):
-    """Generic method to generate a XML text from a comment element
-
-    In:
-      - ``output`` -- the comment element
-      - ``content_type`` -- the rendered content type
-      - ``doctype`` -- the (optional) doctype
-      - ``declaration`` -- is the XML declaration to be outputed ?
-
-    Return:
-      - a tuple (content_type, content)
-    """
-    return (content_type, etree.tostring(output))
-
-
-@peak.rules.when(serialize, (etree._ProcessingInstruction,))
-def serialize(output, content_type, doctype, declaration):
-    """Generic method to generate a XML test from a processing instruction
-
-    In:
-      - ``output`` -- the processing instruction
-      - ``content_type`` -- the rendered content type
-      - ``doctype`` -- the (optional) doctype
-      - ``declaration`` -- is the XML declaration to be outputed ?
-
-    Return:
-      - a tuple (content_type, content)
-    """
-    return (content_type, etree.tostring(output))
+    return (
+            content_type,
+            etree.tostring(
+                output, encoding='utf-8', method=method, pretty_print=pretty_print,
+                xml_declaration=declaration, doctype=doctype if declaration else None
+                )
+            )
 
 
 @peak.rules.when(serialize, (str,))
       - ``output`` -- the rendered content
       - ``content_type`` -- the rendered content type
       - ``doctype`` -- the (optional) doctype
-      - ``declaration`` -- is the XML declaration to be outputed ?
+      - ``declaration`` -- is the XML declaration to be outputed?
 
     Return:
       - a tuple (content_type, content)
       - ``output`` -- the rendered content
       - ``content_type`` -- the rendered content type
       - ``doctype`` -- the (optional) doctype
-      - ``declaration`` -- is the XML declaration to be outputed ?
+      - ``declaration`` -- is the XML declaration to be outputed?
 
     Return:
       - a tuple (content_type, content)
 
 @peak.rules.when(serialize, ((list, tuple),))
 def serialize(output, content_type, doctype, declaration):
-    """Generic method to generate from a list or a tuple
+    """Generic method to generate a text from a list or a tuple
 
     In:
       - ``output`` -- the rendered content
       - ``content_type`` -- the rendered content type
       - ``doctype`` -- the (optional) doctype
-      - ``declaration`` -- is the XML declaration to be outputed ?
+      - ``declaration`` -- is the XML declaration to be outputed?
 
     Return:
       - a tuple (content_type, content)
     if not output:
         return (content_type, '')
 
-    (content_type, first) = serialize(output[0], content_type, doctype, declaration)
+    first = serialize(output[0], content_type, doctype, declaration)[1]
     second = ''.join(serialize(e, content_type, doctype, False)[1] for e in output[1:])
 
     return (content_type, first + second)

File nagare/test/test_serializer.py

+# Encoding: utf-8
+
+#--
+# Copyright (c) 2008-2012 Net-ng.
+# All rights reserved.
+#
+# This software is licensed under the BSD License, as described in
+# the file LICENSE.txt, which you should have received as part of
+# this distribution.
+#--
+
+import unittest
+
+from lxml import etree
+
+from nagare.namespaces import xml, xhtml
+from nagare.serializer import serialize
+
+
+class TestSerializer(unittest.TestCase):
+    def test_html(self):
+        h = xhtml.Renderer()
+
+        r = serialize(h.p('hello'), 'text/html', '<!DOCTYPE html>', False)
+        self.assertEqual(r, ('text/html', '<p>hello</p>\n'))
+        r = serialize(h.p(u'été'), 'text/html', '<!DOCTYPE html>', False)
+        self.assertEqual(r, ('text/html', '<p>\xc3\xa9t\xc3\xa9</p>\n'))
+        r = serialize(h.p('hello'), 'text/html', '<!DOCTYPE html>', True)
+        self.assertEqual(r, ('text/html', '<!DOCTYPE html>\n<p>hello</p>\n'))
+
+    def test_xhtml(self):
+        h = xhtml.Renderer()
+
+        r = serialize(h.p('hello'), 'application/xhtml+xml', '<!DOCTYPE html>', False)
+        self.assertEqual(r, ('application/xhtml+xml', '<p>hello</p>'))
+        r = serialize(h.p(u'été'), 'application/xhtml+xml', '<!DOCTYPE html>', False)
+        self.assertEqual(r, ('application/xhtml+xml', '<p>\xc3\xa9t\xc3\xa9</p>'))
+        r = serialize(h.p('hello'), 'application/xhtml+xml', '<!DOCTYPE html>', True)
+        self.assertEqual(r, ('application/xhtml+xml', "<?xml version='1.0' encoding='utf-8'?>\n<!DOCTYPE html>\n<p>hello</p>"))
+
+    def test_xml(self):
+        x = xml.Renderer()
+
+        r = serialize(x.person('hello'), 'text/xml', '<!DOCTYPE html>', False)
+        self.assertEqual(r, ('text/xml', '<person>hello</person>'))
+        r = serialize(x.person(u'été'), 'text/xml', '<!DOCTYPE html>', False)
+        self.assertEqual(r, ('text/xml', '<person>\xc3\xa9t\xc3\xa9</person>'))
+        r = serialize(x.person('hello'), 'text/xml', '<!DOCTYPE html>', True)
+        self.assertEqual(r, ('text/xml', "<?xml version='1.0' encoding='utf-8'?>\n<!DOCTYPE html>\n<person>hello</person>"))
+
+    def test_comment(self):
+        x = xml.Renderer()
+
+        r = serialize(x.comment('hello'), 'text/xml', '<!DOCTYPE html>', False)
+        self.assertEqual(r, ('text/xml', '<!--hello-->'))
+        r = serialize(x.comment(u'été'), 'text/xml', '<!DOCTYPE html>', False)
+        self.assertEqual(r, ('text/xml', '<!--\xc3\xa9t\xc3\xa9-->'))
+        r = serialize(x.comment('hello'), 'text/xml', '<!DOCTYPE html>', True)
+        self.assertEqual(r, ('text/xml', "<?xml version='1.0' encoding='utf-8'?>\n<!DOCTYPE html>\n<!--hello-->"))
+
+    def test_pi(self):
+        x = xml.Renderer()
+
+        r = serialize(x.processing_instruction('hello'), 'text/xml', '<!DOCTYPE html>', False)
+        self.assertEqual(r, ('text/xml', '<?hello ?>'))
+        r = serialize(x.processing_instruction(u'été'), 'text/xml', '<!DOCTYPE html>', False)
+        self.assertEqual(r, ('text/xml', '<?\xc3\xa9t\xc3\xa9 ?>'))
+        r = serialize(x.processing_instruction('hello'), 'text/xml', '<!DOCTYPE html>', True)
+        self.assertEqual(r, ('text/xml', "<?xml version='1.0' encoding='utf-8'?>\n<!DOCTYPE html>\n<?hello ?>"))
+
+    def test_etree(self):
+        e = etree.Element('person')
+        e.text = 'hello'
+        r = serialize(e, 'text/xml', '<!DOCTYPE html>', False)
+        self.assertEqual(r, ('text/xml', '<person>hello</person>'))
+        e = etree.Element('person')
+        e.text = u'été'
+        r = serialize(e, 'text/xml', '<!DOCTYPE html>', False)
+        self.assertEqual(r, ('text/xml', '<person>\xc3\xa9t\xc3\xa9</person>'))
+        e = etree.Element('person')
+        e.text = 'hello'
+        r = serialize(e, 'text/xml', '<!DOCTYPE html>', True)
+        self.assertEqual(r, ('text/xml', "<?xml version='1.0' encoding='utf-8'?>\n<!DOCTYPE html>\n<person>hello</person>"))
+
+    def test_str(self):
+        r = serialize('hello world', 'text/msg', '<!DOCTYPE html>', False)
+        self.assertEqual(r, ('text/msg', 'hello world'))
+        r = serialize(u'été'.encode('utf-8'), 'text/msg', '<!DOCTYPE html>', False)
+        self.assertEqual(r, ('text/msg', '\xc3\xa9t\xc3\xa9'))
+        r = serialize('hello world', 'text/msg', '<!DOCTYPE html>', True)
+        self.assertEqual(r, ('text/msg', 'hello world'))
+        r = serialize('hello world', '', '<!DOCTYPE html>', False)
+        self.assertEqual(r, ('text/plain', 'hello world'))
+        r = serialize(u'été'.encode('utf-8'), '', '<!DOCTYPE html>', False)
+        self.assertEqual(r, ('text/plain', '\xc3\xa9t\xc3\xa9'))
+        r = serialize('hello world', '', '<!DOCTYPE html>', True)
+        self.assertEqual(r, ('text/plain', 'hello world'))
+
+    def test_unicode(self):
+        r = serialize(u'hello world', 'text/msg', '<!DOCTYPE html>', False)
+        self.assertEqual(r, ('text/msg', 'hello world'))
+        r = serialize(u'été', 'text/msg', '<!DOCTYPE html>', False)
+        self.assertEqual(r, ('text/msg', '\xc3\xa9t\xc3\xa9'))
+        r = serialize(u'hello world', 'text/msg', '<!DOCTYPE html>', True)
+        self.assertEqual(r, ('text/msg', 'hello world'))
+        r = serialize(u'hello world', '', '<!DOCTYPE html>', False)
+        self.assertEqual(r, ('text/plain', 'hello world'))
+        r = serialize(u'été', '', '<!DOCTYPE html>', False)
+        self.assertEqual(r, ('text/plain', '\xc3\xa9t\xc3\xa9'))
+        r = serialize(u'hello world', '', '<!DOCTYPE html>', True)
+        self.assertEqual(r, ('text/plain', 'hello world'))
+
+    def test_list(self):
+        h = xhtml.Renderer()
+        x = xml.Renderer()
+
+        e = etree.Element('person')
+        e.text = 'hello'
+
+        l = [h.p('hello'), x.person('hello'), x.comment('hello'), x.processing_instruction('hello'), e, 'hello', u'hello']
+
+        r = serialize(l, 'text/html', '<!DOCTYPE html>', False)
+        self.assertEqual(r, ('text/html', '<p>hello</p>\n<person>hello</person>\n<!--hello-->\n<?hello >\n<person>hello</person>\nhellohello'))
+        r = serialize(l, 'text/html', '<!DOCTYPE html>', True)
+        self.assertEqual(r, ('text/html', '<!DOCTYPE html>\n<p>hello</p>\n<person>hello</person>\n<!--hello-->\n<?hello >\n<person>hello</person>\nhellohello'))
+
+        r = serialize(l, 'application/xhtml+xml', '<!DOCTYPE html>', False)
+        self.assertEqual(r, ('application/xhtml+xml', '<p>hello</p><person>hello</person><!--hello--><?hello ?><person>hello</person>hellohello'))
+        r = serialize(l, 'application/xhtml+xml', '<!DOCTYPE html>', True)
+        self.assertEqual(r, ('application/xhtml+xml', "<?xml version='1.0' encoding='utf-8'?>\n<!DOCTYPE html>\n<p>hello</p><person>hello</person><!--hello--><?hello ?><person>hello</person>hellohello"))
+
+        r = serialize(l, 'text/msg', '<!DOCTYPE html>', False)
+        self.assertEqual(r, ('text/msg', '<p>hello</p>\n<person>hello</person><!--hello--><?hello ?><person>hello</person>hellohello'))
+        r = serialize(l, 'text/msg', '<!DOCTYPE html>', True)
+        self.assertEqual(r, ('text/msg', '<!DOCTYPE html>\n<p>hello</p>\n<person>hello</person><!--hello--><?hello ?><person>hello</person>hellohello'))
+
+        r = serialize(l, '', '<!DOCTYPE html>', False)
+        self.assertEqual(r, ('', '<p>hello</p>\n<person>hello</person><!--hello--><?hello ?><person>hello</person>hellohello'))
+        r = serialize(l, '', '<!DOCTYPE html>', True)
+        self.assertEqual(r, ('', '<!DOCTYPE html>\n<p>hello</p>\n<person>hello</person><!--hello--><?hello ?><person>hello</person>hellohello'))
+
+        l = l[1:] + [l[0]]
+        r = serialize(l, 'text/html', '<!DOCTYPE html>', False)
+        self.assertEqual(r, ('text/html', '<person>hello</person>\n<!--hello-->\n<?hello >\n<person>hello</person>\nhellohello<p>hello</p>\n'))
+        r = serialize(l, 'text/html', '<!DOCTYPE html>', True)
+        self.assertEqual(r, ('text/html', '<!DOCTYPE html>\n<person>hello</person>\n<!--hello-->\n<?hello >\n<person>hello</person>\nhellohello<p>hello</p>\n'))
+
+        r = serialize(l, 'application/xhtml+xml', '<!DOCTYPE html>', False)
+        self.assertEqual(r, ('application/xhtml+xml', '<person>hello</person><!--hello--><?hello ?><person>hello</person>hellohello<p>hello</p>'))
+        r = serialize(l, 'application/xhtml+xml', '<!DOCTYPE html>', True)
+        self.assertEqual(r, ('application/xhtml+xml', "<?xml version='1.0' encoding='utf-8'?>\n<!DOCTYPE html>\n<person>hello</person><!--hello--><?hello ?><person>hello</person>hellohello<p>hello</p>"))
+
+        r = serialize(l, 'text/msg', '<!DOCTYPE html>', False)
+        self.assertEqual(r, ('text/msg', "<person>hello</person><!--hello--><?hello ?><person>hello</person>hellohello<p>hello</p>\n"))
+        r = serialize(l, 'text/msg', '<!DOCTYPE html>', True)
+        self.assertEqual(r, ('text/msg', "<?xml version='1.0' encoding='utf-8'?>\n<!DOCTYPE html>\n<person>hello</person><!--hello--><?hello ?><person>hello</person>hellohello<p>hello</p>\n"))
+
+        r = serialize(l, '', '<!DOCTYPE html>', False)
+        self.assertEqual(r, ('', '<person>hello</person><!--hello--><?hello ?><person>hello</person>hellohello<p>hello</p>\n'))
+        r = serialize(l, '', '<!DOCTYPE html>', True)
+        self.assertEqual(r, ('', "<?xml version='1.0' encoding='utf-8'?>\n<!DOCTYPE html>\n<person>hello</person><!--hello--><?hello ?><person>hello</person>hellohello<p>hello</p>\n"))
+
+        l = l[1:] + [l[0]]
+        r = serialize(l, 'text/html', '<!DOCTYPE html>', False)
+        self.assertEqual(r, ('text/html', '<!--hello-->\n<?hello >\n<person>hello</person>\nhellohello<p>hello</p>\n<person>hello</person>\n'))
+        r = serialize(l, 'text/html', '<!DOCTYPE html>', True)
+        self.assertEqual(r, ('text/html', '<!DOCTYPE html>\n<!--hello-->\n<?hello >\n<person>hello</person>\nhellohello<p>hello</p>\n<person>hello</person>\n'))
+
+        r = serialize(l, 'application/xhtml+xml', '<!DOCTYPE html>', False)
+        self.assertEqual(r, ('application/xhtml+xml', '<!--hello--><?hello ?><person>hello</person>hellohello<p>hello</p><person>hello</person>'))
+        r = serialize(l, 'application/xhtml+xml', '<!DOCTYPE html>', True)
+        self.assertEqual(r, ('application/xhtml+xml', "<?xml version='1.0' encoding='utf-8'?>\n<!DOCTYPE html>\n<!--hello--><?hello ?><person>hello</person>hellohello<p>hello</p><person>hello</person>"))
+
+        r = serialize(l, 'text/msg', '<!DOCTYPE html>', False)
+        self.assertEqual(r, ('text/msg', '<!--hello--><?hello ?><person>hello</person>hellohello<p>hello</p>\n<person>hello</person>'))
+        r = serialize(l, 'text/msg', '<!DOCTYPE html>', True)
+        self.assertEqual(r, ('text/msg', "<?xml version='1.0' encoding='utf-8'?>\n<!DOCTYPE html>\n<!--hello--><?hello ?><person>hello</person>hellohello<p>hello</p>\n<person>hello</person>"))
+
+        r = serialize(l, '', '<!DOCTYPE html>', False)
+        self.assertEqual(r, ('', '<!--hello--><?hello ?><person>hello</person>hellohello<p>hello</p>\n<person>hello</person>'))
+        r = serialize(l, '', '<!DOCTYPE html>', True)
+        self.assertEqual(r, ('', "<?xml version='1.0' encoding='utf-8'?>\n<!DOCTYPE html>\n<!--hello--><?hello ?><person>hello</person>hellohello<p>hello</p>\n<person>hello</person>"))
+
+        l = l[1:] + [l[0]]
+        r = serialize(l, 'text/html', '<!DOCTYPE html>', False)
+        self.assertEqual(r, ('text/html', '<?hello >\n<person>hello</person>\nhellohello<p>hello</p>\n<person>hello</person>\n<!--hello-->\n'))
+        r = serialize(l, 'text/html', '<!DOCTYPE html>', True)
+        self.assertEqual(r, ('text/html', '<!DOCTYPE html>\n<?hello >\n<person>hello</person>\nhellohello<p>hello</p>\n<person>hello</person>\n<!--hello-->\n'))
+
+        r = serialize(l, 'application/xhtml+xml', '<!DOCTYPE html>', False)
+        self.assertEqual(r, ('application/xhtml+xml', '<?hello ?><person>hello</person>hellohello<p>hello</p><person>hello</person><!--hello-->'))
+        r = serialize(l, 'application/xhtml+xml', '<!DOCTYPE html>', True)
+        self.assertEqual(r, ('application/xhtml+xml', "<?xml version='1.0' encoding='utf-8'?>\n<!DOCTYPE html>\n<?hello ?><person>hello</person>hellohello<p>hello</p><person>hello</person><!--hello-->"))
+
+        r = serialize(l, 'text/msg', '<!DOCTYPE html>', False)
+        self.assertEqual(r, ('text/msg', '<?hello ?><person>hello</person>hellohello<p>hello</p>\n<person>hello</person><!--hello-->'))
+        r = serialize(l, 'text/msg', '<!DOCTYPE html>', True)
+        self.assertEqual(r, ('text/msg', "<?xml version='1.0' encoding='utf-8'?>\n<!DOCTYPE html>\n<?hello ?><person>hello</person>hellohello<p>hello</p>\n<person>hello</person><!--hello-->"))
+
+        r = serialize(l, '', '<!DOCTYPE html>', False)
+        self.assertEqual(r, ('', '<?hello ?><person>hello</person>hellohello<p>hello</p>\n<person>hello</person><!--hello-->'))
+        r = serialize(l, '', '<!DOCTYPE html>', True)
+        self.assertEqual(r, ('', "<?xml version='1.0' encoding='utf-8'?>\n<!DOCTYPE html>\n<?hello ?><person>hello</person>hellohello<p>hello</p>\n<person>hello</person><!--hello-->"))
+
+        l = l[1:] + [l[0]]
+        r = serialize(l, 'text/html', '<!DOCTYPE html>', False)
+        self.assertEqual(r, ('text/html', '<person>hello</person>\nhellohello<p>hello</p>\n<person>hello</person>\n<!--hello-->\n<?hello >\n'))
+        r = serialize(l, 'text/html', '<!DOCTYPE html>', True)
+        self.assertEqual(r, ('text/html', '<!DOCTYPE html>\n<person>hello</person>\nhellohello<p>hello</p>\n<person>hello</person>\n<!--hello-->\n<?hello >\n'))
+
+        r = serialize(l, 'application/xhtml+xml', '<!DOCTYPE html>', False)
+        self.assertEqual(r, ('application/xhtml+xml', '<person>hello</person>hellohello<p>hello</p><person>hello</person><!--hello--><?hello ?>'))
+        r = serialize(l, 'application/xhtml+xml', '<!DOCTYPE html>', True)
+        self.assertEqual(r, ('application/xhtml+xml', "<?xml version='1.0' encoding='utf-8'?>\n<!DOCTYPE html>\n<person>hello</person>hellohello<p>hello</p><person>hello</person><!--hello--><?hello ?>"))
+
+        r = serialize(l, 'text/msg', '<!DOCTYPE html>', False)
+        self.assertEqual(r, ('text/msg', '<person>hello</person>hellohello<p>hello</p>\n<person>hello</person><!--hello--><?hello ?>'))
+        r = serialize(l, 'text/msg', '<!DOCTYPE html>', True)
+        self.assertEqual(r, ('text/msg', "<?xml version='1.0' encoding='utf-8'?>\n<!DOCTYPE html>\n<person>hello</person>hellohello<p>hello</p>\n<person>hello</person><!--hello--><?hello ?>"))
+
+        r = serialize(l, '', '<!DOCTYPE html>', False)
+        self.assertEqual(r, ('', '<person>hello</person>hellohello<p>hello</p>\n<person>hello</person><!--hello--><?hello ?>'))
+        r = serialize(l, '', '<!DOCTYPE html>', True)
+        self.assertEqual(r, ('', "<?xml version='1.0' encoding='utf-8'?>\n<!DOCTYPE html>\n<person>hello</person>hellohello<p>hello</p>\n<person>hello</person><!--hello--><?hello ?>"))
+
+        l = l[1:] + [l[0]]
+        r = serialize(l, 'text/html', '<!DOCTYPE html>', False)
+        self.assertEqual(r, ('text/html', 'hellohello<p>hello</p>\n<person>hello</person>\n<!--hello-->\n<?hello >\n<person>hello</person>\n'))
+        r = serialize(l, 'text/html', '<!DOCTYPE html>', True)
+        self.assertEqual(r, ('text/html', 'hellohello<p>hello</p>\n<person>hello</person>\n<!--hello-->\n<?hello >\n<person>hello</person>\n'))
+
+        r = serialize(l, 'application/xhtml+xml', '<!DOCTYPE html>', False)
+        self.assertEqual(r, ('application/xhtml+xml', 'hellohello<p>hello</p><person>hello</person><!--hello--><?hello ?><person>hello</person>'))
+        r = serialize(l, 'application/xhtml+xml', '<!DOCTYPE html>', True)
+        self.assertEqual(r, ('application/xhtml+xml', 'hellohello<p>hello</p><person>hello</person><!--hello--><?hello ?><person>hello</person>'))
+
+        r = serialize(l, 'text/msg', '<!DOCTYPE html>', False)
+        self.assertEqual(r, ('text/msg', 'hellohello<p>hello</p>\n<person>hello</person><!--hello--><?hello ?><person>hello</person>'))
+        r = serialize(l, 'text/msg', '<!DOCTYPE html>', True)
+        self.assertEqual(r, ('text/msg', 'hellohello<p>hello</p>\n<person>hello</person><!--hello--><?hello ?><person>hello</person>'))
+
+        r = serialize(l, '', '<!DOCTYPE html>', False)
+        self.assertEqual(r, ('', 'hellohello<p>hello</p>\n<person>hello</person><!--hello--><?hello ?><person>hello</person>'))
+        r = serialize(l, '', '<!DOCTYPE html>', True)
+        self.assertEqual(r, ('', 'hellohello<p>hello</p>\n<person>hello</person><!--hello--><?hello ?><person>hello</person>'))
+
+        l = l[1:] + [l[0]]
+        r = serialize(l, 'text/html', '<!DOCTYPE html>', False)
+        self.assertEqual(r, ('text/html', 'hello<p>hello</p>\n<person>hello</person>\n<!--hello-->\n<?hello >\n<person>hello</person>\nhello'))
+        r = serialize(l, 'text/html', '<!DOCTYPE html>', True)
+        self.assertEqual(r, ('text/html', 'hello<p>hello</p>\n<person>hello</person>\n<!--hello-->\n<?hello >\n<person>hello</person>\nhello'))
+
+        r = serialize(l, 'application/xhtml+xml', '<!DOCTYPE html>', False)
+        self.assertEqual(r, ('application/xhtml+xml', 'hello<p>hello</p><person>hello</person><!--hello--><?hello ?><person>hello</person>hello'))
+        r = serialize(l, 'application/xhtml+xml', '<!DOCTYPE html>', True)
+        self.assertEqual(r, ('application/xhtml+xml', 'hello<p>hello</p><person>hello</person><!--hello--><?hello ?><person>hello</person>hello'))
+
+        r = serialize(l, 'text/msg', '<!DOCTYPE html>', False)
+        self.assertEqual(r, ('text/msg', 'hello<p>hello</p>\n<person>hello</person><!--hello--><?hello ?><person>hello</person>hello'))
+        r = serialize(l, 'text/msg', '<!DOCTYPE html>', True)
+        self.assertEqual(r, ('text/msg', 'hello<p>hello</p>\n<person>hello</person><!--hello--><?hello ?><person>hello</person>hello'))
+
+        r = serialize(l, '', '<!DOCTYPE html>', False)
+        self.assertEqual(r, ('', 'hello<p>hello</p>\n<person>hello</person><!--hello--><?hello ?><person>hello</person>hello'))
+        r = serialize(l, '', '<!DOCTYPE html>', True)
+        self.assertEqual(r, ('', 'hello<p>hello</p>\n<person>hello</person><!--hello--><?hello ?><person>hello</person>hello'))