diff --git Lib/test/test_sax.py Lib/test/test_sax.py
index 222c653..ffcfd97 100644
--- Lib/test/test_sax.py
+++ Lib/test/test_sax.py
@@ -165,6 +165,16 @@ class XmlgenTest(unittest.TestCase):
self.assertEquals(result.getvalue(), start + "")
+ def test_xmlgen_basic_empty(self):
+ result = StringIO()
+ gen = XMLGenerator(result, short_empty_elements=True)
+ gen.startDocument()
+ gen.startElement("doc", {})
+ gen.endElement("doc")
+ gen.endDocument()
+
+ self.assertEquals(result.getvalue(), start + "")
+
def test_xmlgen_content(self):
result = StringIO()
gen = XMLGenerator(result)
@@ -177,6 +187,18 @@ class XmlgenTest(unittest.TestCase):
self.assertEquals(result.getvalue(), start + "huhei")
+ def test_xmlgen_content_empty(self):
+ result = StringIO()
+ gen = XMLGenerator(result, short_empty_elements=True)
+
+ gen.startDocument()
+ gen.startElement("doc", {})
+ gen.characters("huhei")
+ gen.endElement("doc")
+ gen.endDocument()
+
+ self.assertEquals(result.getvalue(), start + "huhei")
+
def test_xmlgen_pi(self):
result = StringIO()
gen = XMLGenerator(result)
@@ -234,6 +256,18 @@ class XmlgenTest(unittest.TestCase):
self.assertEquals(result.getvalue(), start + " ")
+ def test_xmlgen_ignorable_empty(self):
+ result = StringIO()
+ gen = XMLGenerator(result, short_empty_elements=True)
+
+ gen.startDocument()
+ gen.startElement("doc", {})
+ gen.ignorableWhitespace(" ")
+ gen.endElement("doc")
+ gen.endDocument()
+
+ self.assertEquals(result.getvalue(), start + " ")
+
def test_xmlgen_ns(self):
result = StringIO()
gen = XMLGenerator(result)
@@ -252,6 +286,24 @@ class XmlgenTest(unittest.TestCase):
('' %
ns_uri))
+ def test_xmlgen_ns_empty(self):
+ result = StringIO()
+ gen = XMLGenerator(result, short_empty_elements=True)
+
+ gen.startDocument()
+ gen.startPrefixMapping("ns1", ns_uri)
+ gen.startElementNS((ns_uri, "doc"), "ns1:doc", {})
+ # add an unqualified name
+ gen.startElementNS((None, "udoc"), None, {})
+ gen.endElementNS((None, "udoc"), None)
+ gen.endElementNS((ns_uri, "doc"), "ns1:doc")
+ gen.endPrefixMapping("ns1")
+ gen.endDocument()
+
+ self.assertEquals(result.getvalue(), start + \
+ ('' %
+ ns_uri))
+
def test_1463026_1(self):
result = StringIO()
gen = XMLGenerator(result)
@@ -263,6 +315,17 @@ class XmlgenTest(unittest.TestCase):
self.assertEquals(result.getvalue(), start+'')
+ def test_1463026_1_empty(self):
+ result = StringIO()
+ gen = XMLGenerator(result, short_empty_elements=True)
+
+ gen.startDocument()
+ gen.startElementNS((None, 'a'), 'a', {(None, 'b'):'c'})
+ gen.endElementNS((None, 'a'), 'a')
+ gen.endDocument()
+
+ self.assertEquals(result.getvalue(), start+'')
+
def test_1463026_2(self):
result = StringIO()
gen = XMLGenerator(result)
@@ -276,6 +339,19 @@ class XmlgenTest(unittest.TestCase):
self.assertEquals(result.getvalue(), start+'')
+ def test_1463026_2_empty(self):
+ result = StringIO()
+ gen = XMLGenerator(result, short_empty_elements=True)
+
+ gen.startDocument()
+ gen.startPrefixMapping(None, 'qux')
+ gen.startElementNS(('qux', 'a'), 'a', {})
+ gen.endElementNS(('qux', 'a'), 'a')
+ gen.endPrefixMapping(None)
+ gen.endDocument()
+
+ self.assertEquals(result.getvalue(), start+'')
+
def test_1463026_3(self):
result = StringIO()
gen = XMLGenerator(result)
@@ -290,6 +366,20 @@ class XmlgenTest(unittest.TestCase):
self.assertEquals(result.getvalue(),
start+'')
+ def test_1463026_3_empty(self):
+ result = StringIO()
+ gen = XMLGenerator(result, short_empty_elements=True)
+
+ gen.startDocument()
+ gen.startPrefixMapping('my', 'qux')
+ gen.startElementNS(('qux', 'a'), 'a', {(None, 'b'):'c'})
+ gen.endElementNS(('qux', 'a'), 'a')
+ gen.endPrefixMapping('my')
+ gen.endDocument()
+
+ self.assertEquals(result.getvalue(),
+ start+'')
+
class XMLFilterBaseTest(unittest.TestCase):
def test_filter_basic(self):
diff --git Lib/xml/sax/saxutils.py Lib/xml/sax/saxutils.py
index e845015..46946fc 100644
--- Lib/xml/sax/saxutils.py
+++ Lib/xml/sax/saxutils.py
@@ -78,7 +78,7 @@ def quoteattr(data, entities={}):
class XMLGenerator(handler.ContentHandler):
- def __init__(self, out=None, encoding="iso-8859-1"):
+ def __init__(self, out=None, encoding="iso-8859-1", short_empty_elements=False):
if out is None:
import sys
out = sys.stdout
@@ -88,6 +88,8 @@ class XMLGenerator(handler.ContentHandler):
self._current_context = self._ns_contexts[-1]
self._undeclared_ns_maps = []
self._encoding = encoding
+ self._short_empty_elements = short_empty_elements
+ self._pending_start_element = False
def _write(self, text):
if isinstance(text, str):
@@ -106,6 +108,11 @@ class XMLGenerator(handler.ContentHandler):
# Return the unqualified name
return name[1]
+ def _finish_pending_start_element(self,endElement=False):
+ if self._pending_start_element:
+ self._write('>')
+ self._pending_start_element = False
+
# ContentHandler methods
def startDocument(self):
@@ -122,15 +129,24 @@ class XMLGenerator(handler.ContentHandler):
del self._ns_contexts[-1]
def startElement(self, name, attrs):
+ self._finish_pending_start_element()
self._write('<' + name)
for (name, value) in attrs.items():
self._write(' %s=%s' % (name, quoteattr(value)))
- self._write('>')
+ if self._short_empty_elements:
+ self._pending_start_element = True
+ else:
+ self._write(">")
def endElement(self, name):
- self._write('%s>' % name)
+ if self._pending_start_element:
+ self._write('/>')
+ self._pending_start_element = False
+ else:
+ self._write('%s>' % name)
def startElementNS(self, name, qname, attrs):
+ self._finish_pending_start_element()
self._write('<' + self._qname(name))
for prefix, uri in self._undeclared_ns_maps:
@@ -142,18 +158,30 @@ class XMLGenerator(handler.ContentHandler):
for (name, value) in attrs.items():
self._write(' %s=%s' % (self._qname(name), quoteattr(value)))
- self._write('>')
+ if self._short_empty_elements:
+ self._pending_start_element = True
+ else:
+ self._write(">")
def endElementNS(self, name, qname):
- self._write('%s>' % self._qname(name))
+ if self._pending_start_element:
+ self._write('/>')
+ self._pending_start_element = False
+ else:
+ self._write('%s>' % self._qname(name))
def characters(self, content):
- self._write(escape(content))
+ if content:
+ self._finish_pending_start_element()
+ self._write(escape(content))
def ignorableWhitespace(self, content):
- self._write(content)
+ if content:
+ self._finish_pending_start_element()
+ self._write(content)
def processingInstruction(self, target, data):
+ self._finish_pending_start_element()
self._write('%s %s?>' % (target, data))