diff -r f1b5fc67524a Doc/library/xml.sax.utils.rst --- a/Doc/library/xml.sax.utils.rst Tue May 29 18:44:17 2012 -0500 +++ b/Doc/library/xml.sax.utils.rst Wed May 30 10:56:41 2012 +0300 @@ -50,13 +50,14 @@ using the reference concrete syntax. -.. class:: XMLGenerator(out=None, encoding='iso-8859-1', short_empty_elements=False) +.. class:: XMLGenerator(out=None, encoding=None, short_empty_elements=False) This class implements the :class:`ContentHandler` interface by writing SAX events back into an XML document. In other words, using an :class:`XMLGenerator` as the content handler will reproduce the original document being parsed. *out* - should be a file-like object which will default to *sys.stdout*. *encoding* is - the encoding of the output stream which defaults to ``'iso-8859-1'``. + should be a :term:`file object` which will default to *sys.stdout*. + *encoding* is the encoding of the binary output stream. + Use ``encoding=None`` (which will default) to write to the text output stream. *short_empty_elements* controls the formatting of elements that contain no content: if *False* (the default) they are emitted as a pair of start/end tags, if set to *True* they are emitted as a single self-closed tag. diff -r f1b5fc67524a Lib/test/test_sax.py --- a/Lib/test/test_sax.py Tue May 29 18:44:17 2012 -0500 +++ b/Lib/test/test_sax.py Wed May 30 10:56:41 2012 +0300 @@ -158,7 +158,7 @@ # ===== XMLGenerator -start = '\n' +start = '\n' class XmlgenTest(unittest.TestCase): def test_xmlgen_basic(self): diff -r f1b5fc67524a Lib/test/xmltestdata/test.xml.out --- a/Lib/test/xmltestdata/test.xml.out Tue May 29 18:44:17 2012 -0500 +++ b/Lib/test/xmltestdata/test.xml.out Wed May 30 10:56:41 2012 +0300 @@ -1,4 +1,4 @@ - + Introduction to XSL

Introduction to XSL

diff -r f1b5fc67524a Lib/xml/sax/saxutils.py --- a/Lib/xml/sax/saxutils.py Tue May 29 18:44:17 2012 -0500 +++ b/Lib/xml/sax/saxutils.py Wed May 30 10:56:41 2012 +0300 @@ -4,6 +4,7 @@ """ import os, urllib.parse, urllib.request +import io from . import handler from . import xmlreader @@ -78,11 +79,28 @@ class XMLGenerator(handler.ContentHandler): - def __init__(self, out=None, encoding="iso-8859-1", short_empty_elements=False): + def __init__(self, out=None, encoding=None, short_empty_elements=False): + handler.ContentHandler.__init__(self) if out is None: import sys out = sys.stdout - handler.ContentHandler.__init__(self) + if encoding is not None: + out = out.buffer.raw + if encoding is not None: + if not isinstance(out, io.BufferedIOBase): + writer = out + out = io.BufferedIOBase() + out.writable = lambda: True + out.write = writer.write + try: + # Required to write BOM + out.seekable = writer.seekable + out.tell = writer.tell + except AttributeError: + pass + out = io.TextIOWrapper(out, encoding=encoding, + errors=_error_handling, + newline="\n") self._out = out self._ns_contexts = [{}] # contains uri -> prefix dicts self._current_context = self._ns_contexts[-1] @@ -91,12 +109,6 @@ self._short_empty_elements = short_empty_elements self._pending_start_element = False - def _write(self, text): - if isinstance(text, str): - self._out.write(text) - else: - self._out.write(text.encode(self._encoding, _error_handling)) - def _qname(self, name): """Builds a qualified name from a (ns_url, localname) pair""" if name[0]: @@ -116,14 +128,21 @@ def _finish_pending_start_element(self,endElement=False): if self._pending_start_element: - self._write('>') + self._out.write('>') self._pending_start_element = False # ContentHandler methods def startDocument(self): - self._write('\n' % - self._encoding) + if self._encoding is not None: + self._out.write('\n' % + self._encoding) + else: + self._out.write('\n') + + def endDocument(self): + if self._encoding is not None: + self._out.detach() def startPrefixMapping(self, prefix, uri): self._ns_contexts.append(self._current_context.copy()) @@ -136,24 +155,24 @@ def startElement(self, name, attrs): self._finish_pending_start_element() - self._write('<' + name) + self._out.write('<' + name) for (name, value) in attrs.items(): - self._write(' %s=%s' % (name, quoteattr(value))) + self._out.write(' %s=%s' % (name, quoteattr(value))) if self._short_empty_elements: self._pending_start_element = True else: - self._write(">") + self._out.write(">") def endElement(self, name): if self._pending_start_element: - self._write('/>') + self._out.write('/>') self._pending_start_element = False else: - self._write('' % name) + self._out.write('' % name) def startElementNS(self, name, qname, attrs): self._finish_pending_start_element() - self._write('<' + self._qname(name)) + self._out.write('<' + self._qname(name)) for prefix, uri in self._undeclared_ns_maps: if prefix: @@ -163,32 +182,32 @@ self._undeclared_ns_maps = [] for (name, value) in attrs.items(): - self._write(' %s=%s' % (self._qname(name), quoteattr(value))) + self._out.write(' %s=%s' % (self._qname(name), quoteattr(value))) if self._short_empty_elements: self._pending_start_element = True else: - self._write(">") + self._out.write(">") def endElementNS(self, name, qname): if self._pending_start_element: - self._write('/>') + self._out.write('/>') self._pending_start_element = False else: - self._write('' % self._qname(name)) + self._out.write('' % self._qname(name)) def characters(self, content): if content: self._finish_pending_start_element() - self._write(escape(content)) + self._out.write(escape(content)) def ignorableWhitespace(self, content): if content: self._finish_pending_start_element() - self._write(content) + self._out.write(content) def processingInstruction(self, target, data): self._finish_pending_start_element() - self._write('' % (target, data)) + self._out.write('' % (target, data)) class XMLFilterBase(xmlreader.XMLReader):