From e077204a16c76df4af90ba067e94c31af3d9e372 Mon Sep 17 00:00:00 2001
From: Lance Stout <lancestout@gmail.com>
Date: Thu, 5 Aug 2010 20:26:41 -0400
Subject: Replaced the ToString class with a tostring function.

The sleekxmpp.xmlstream.tostring and sleekxmpp.xmlstream.tostring26 packages
have been merged to sleekxmpp.xmlstream.tostring. The __init__.py file will
import the appropriate tostring function depending on the Python version.

The setup.py file has been updated with the package changes.

ElementBase is now a direct descendent of object and does not subclass ToString.

Stanza objects now return their XML contents for __repr__.
---
 sleekxmpp/xmlstream/stanzabase.py          |  91 +++++++++--------
 sleekxmpp/xmlstream/tostring/__init__.py   |  13 ++-
 sleekxmpp/xmlstream/tostring/tostring.py   | 149 ++++++++++++++++-----------
 sleekxmpp/xmlstream/tostring/tostring26.py | 157 ++++++++++++++++++-----------
 sleekxmpp/xmlstream/tostring26/__init__.py |  65 ------------
 sleekxmpp/xmlstream/xmlstream.py           | 101 +++++--------------
 6 files changed, 267 insertions(+), 309 deletions(-)
 delete mode 100644 sleekxmpp/xmlstream/tostring26/__init__.py

(limited to 'sleekxmpp/xmlstream')

diff --git a/sleekxmpp/xmlstream/stanzabase.py b/sleekxmpp/xmlstream/stanzabase.py
index 94ff958c..3b5f0bf4 100644
--- a/sleekxmpp/xmlstream/stanzabase.py
+++ b/sleekxmpp/xmlstream/stanzabase.py
@@ -12,10 +12,7 @@ import weakref
 import copy
 from . jid import JID
 
-if sys.version_info < (3,0):
-        from . import tostring26 as tostring
-else:
-        from . import tostring
+from sleekxmpp.xmlstream.tostring import tostring
 
 xmltester = type(ET.Element('xml'))
 
@@ -29,7 +26,7 @@ def registerStanzaPlugin(stanza, plugin):
         stanza.plugin_tag_map[tag] = plugin
 
 
-class ElementBase(tostring.ToString):
+class ElementBase(object):
         name = 'stanza'
         plugin_attrib = 'plugin'
         namespace = 'jabber:client'
@@ -70,20 +67,20 @@ class ElementBase(tostring.ToString):
 
         def __bool__(self):
                 return True
-        
+
         def __next__(self):
                 self.idx += 1
                 if self.idx > len(self.iterables):
                         self.idx = 0
                         raise StopIteration
                 return self.iterables[self.idx - 1]
-        
+
         def next(self):
                 return self.__next__()
 
         def __len__(self):
                 return len(self.iterables)
-        
+
         def append(self, item):
                 if not isinstance(item, ElementBase):
                         if type(item) == xmltester:
@@ -93,18 +90,18 @@ class ElementBase(tostring.ToString):
                 self.xml.append(item.xml)
                 self.iterables.append(item)
                 return self
-        
+
         def pop(self, idx=0):
                 aff = self.iterables.pop(idx)
                 self.xml.remove(aff.xml)
                 return aff
-        
+
         def get(self, key, defaultvalue=None):
                 value = self[key]
                 if value is None or value == '':
                         return defaultvalue
                 return value
-        
+
         def keys(self):
                 out = []
                 out += [x for x in self.interfaces]
@@ -112,7 +109,7 @@ class ElementBase(tostring.ToString):
                 if self.iterables:
                         out.append('substanzas')
                 return tuple(out)
-        
+
         def match(self, matchstring):
                 if isinstance(matchstring, str):
                         nodes = matchstring.split('/')
@@ -136,13 +133,13 @@ class ElementBase(tostring.ToString):
                         else:
                                 return False
                 return True
-        
+
         def find(self, xpath): # for backwards compatiblity, expose elementtree interface
                 return self.xml.find(xpath)
 
         def findall(self, xpath):
                 return self.xml.findall(xpath)
-        
+
         def setup(self, xml=None):
                 if self.xml is None:
                         self.xml = xml
@@ -162,11 +159,11 @@ class ElementBase(tostring.ToString):
         def enable(self, attrib):
                 self.initPlugin(attrib)
                 return self
-        
+
         def initPlugin(self, attrib):
                 if attrib not in self.plugins:
                         self.plugins[attrib] = self.plugin_attrib_map[attrib](parent=self)
-        
+
         def __getitem__(self, attrib):
                 if attrib == 'substanzas':
                         return self.iterables
@@ -183,7 +180,7 @@ class ElementBase(tostring.ToString):
                         return self.plugins[attrib]
                 else:
                         return ''
-        
+
         def __setitem__(self, attrib, value):
                 if attrib in self.interfaces:
                         if value is not None:
@@ -201,7 +198,7 @@ class ElementBase(tostring.ToString):
                         self.initPlugin(attrib)
                         self.plugins[attrib][attrib] = value
                 return self
-        
+
         def __delitem__(self, attrib):
                 if attrib.lower() in self.interfaces:
                         if hasattr(self, "del%s" % attrib.title()):
@@ -215,7 +212,7 @@ class ElementBase(tostring.ToString):
                         if attrib in self.plugins:
                                 del self.plugins[attrib]
                 return self
-        
+
         def __eq__(self, other):
                 if not isinstance(other, ElementBase):
                         return False
@@ -224,20 +221,20 @@ class ElementBase(tostring.ToString):
                         if key not in values or values[key] != other[key]:
                                 return False
                 return True
-        
+
         def _setAttr(self, name, value):
                 if value is None or value == '':
                         self.__delitem__(name)
                 else:
                         self.xml.attrib[name] = value
-        
+
         def _delAttr(self, name):
                 if name in self.xml.attrib:
                         del self.xml.attrib[name]
-        
+
         def _getAttr(self, name, default=''):
                 return self.xml.attrib.get(name, default)
-        
+
         def _getSubText(self, name):
                 if '}' not in name:
                         name = "{%s}%s" % (self.namespace, name)
@@ -246,7 +243,7 @@ class ElementBase(tostring.ToString):
                         return ''
                 else:
                         return stanza.text
-        
+
         def _setSubText(self, name, attrib={}, text=None):
                 if '}' not in name:
                         name = "{%s}%s" % (self.namespace, name)
@@ -258,14 +255,14 @@ class ElementBase(tostring.ToString):
                         self.xml.append(stanza)
                 stanza.text = text
                 return stanza
-                
+
         def _delSub(self, name):
                 if '}' not in name:
                         name = "{%s}%s" % (self.namespace, name)
                 for child in self.xml.getchildren():
                         if child.tag == name:
                                 self.xml.remove(child)
-        
+
         def getStanzaValues(self):
                 out = {}
                 for interface in self.interfaces:
@@ -279,7 +276,7 @@ class ElementBase(tostring.ToString):
                                 iterables[-1].update({'__childtag__': "{%s}%s" % (stanza.namespace, stanza.name)})
                         out['substanzas'] = iterables
                 return out
-        
+
         def setStanzaValues(self, attrib):
                 for interface in attrib:
                         if interface == 'substanzas':
@@ -298,14 +295,20 @@ class ElementBase(tostring.ToString):
                         if interface in self.plugins:
                                 self.plugins[interface].setStanzaValues(attrib[interface])
                 return self
-        
+
         def appendxml(self, xml):
                 self.xml.append(xml)
                 return self
 
         def __copy__(self):
                 return self.__class__(xml=copy.deepcopy(self.xml), parent=self.parent)
-        
+
+        def __str__(self):
+                return tostring(self.xml, xmlns='', stanza_ns=self.namespace)
+
+        def __repr__(self):
+                return self.__str__()
+
         #def __del__(self): #prevents garbage collection of reference cycle
         #       if self.parent is not None:
         #               self.parent.xml.remove(self.xml)
@@ -329,7 +332,7 @@ class StanzaBase(ElementBase):
                 if sfrom is not None:
                         self['from'] = sfrom
                 self.tag = "{%s}%s" % (self.namespace, self.name)
-        
+
         def setType(self, value):
                 if value in self.types:
                         self.xml.attrib['type'] = value
@@ -337,22 +340,22 @@ class StanzaBase(ElementBase):
 
         def getPayload(self):
                 return self.xml.getchildren()
-        
+
         def setPayload(self, value):
                 self.xml.append(value)
                 return self
-        
+
         def delPayload(self):
                 self.clear()
                 return self
-        
+
         def clear(self):
                 for child in self.xml.getchildren():
                         self.xml.remove(child)
                 for plugin in list(self.plugins.keys()):
                         del self.plugins[plugin]
                 return self
-        
+
         def reply(self):
                 # if it's a component, use from
                 if self.stream and hasattr(self.stream, "is_component") and self.stream.is_component:
@@ -362,32 +365,34 @@ class StanzaBase(ElementBase):
                         del self['from']
                 self.clear()
                 return self
-        
+
         def error(self):
                 self['type'] = 'error'
                 return self
-        
+
         def getTo(self):
                 return JID(self._getAttr('to'))
-        
+
         def setTo(self, value):
                 return self._setAttr('to', str(value))
-        
+
         def getFrom(self):
                 return JID(self._getAttr('from'))
-        
+
         def setFrom(self, value):
                 return self._setAttr('from', str(value))
-        
+
         def unhandled(self):
                 pass
-        
+
         def exception(self, e):
                 logging.exception('Error handling {%s}%s stanza' % (self.namespace, self.name))
-        
+
         def send(self):
                 self.stream.sendRaw(self.__str__())
 
         def __copy__(self):
                 return self.__class__(xml=copy.deepcopy(self.xml), stream=self.stream)
-                
+
+        def __str__(self):
+                return tostring(self.xml, xmlns='', stanza_ns=self.namespace, stream=self.stream)
diff --git a/sleekxmpp/xmlstream/tostring/__init__.py b/sleekxmpp/xmlstream/tostring/__init__.py
index d93fe4ea..5852cba2 100644
--- a/sleekxmpp/xmlstream/tostring/__init__.py
+++ b/sleekxmpp/xmlstream/tostring/__init__.py
@@ -1,14 +1,19 @@
 """
+    SleekXMPP: The Sleek XMPP Library
+    Copyright (C) 2010  Nathanael C. Fritz
+    This file is part of SleekXMPP.
 
+    See the file LICENSE for copying permission.
 """
 
 import sys
 
+# Import the correct tostring and xml_escape functions based on the Python
+# version in order to properly handle Unicode.
 
-# Import the correct ToString class based on the Python version.
 if sys.version_info < (3, 0):
-    from sleekxmpp.xmlstream.tostring.tostring26 import ToString
+    from sleekxmpp.xmlstream.tostring.tostring26 import tostring, xml_escape
 else:
-    from sleekxmpp.xmlstream.tostring.tostring import ToString
+    from sleekxmpp.xmlstream.tostring.tostring import tostring, xml_escape
 
-__all__ = ['ToString']
+__all__ = ['tostring', 'xml_escape']
diff --git a/sleekxmpp/xmlstream/tostring/tostring.py b/sleekxmpp/xmlstream/tostring/tostring.py
index 6603cbb8..62ff1181 100644
--- a/sleekxmpp/xmlstream/tostring/tostring.py
+++ b/sleekxmpp/xmlstream/tostring/tostring.py
@@ -1,60 +1,91 @@
+"""
+    SleekXMPP: The Sleek XMPP Library
+    Copyright (C) 2010  Nathanael C. Fritz
+    This file is part of SleekXMPP.
 
-class ToString(object):
-	def __str__(self, xml=None, xmlns='', stringbuffer=''):
-		if xml is None:
-			xml = self.xml
-		newoutput = [stringbuffer]
-		#TODO respect ET mapped namespaces
-		itag = xml.tag.split('}', 1)[-1]
-		if '}' in xml.tag:
-			ixmlns = xml.tag.split('}', 1)[0][1:]
-		else:
-			ixmlns = ''
-		nsbuffer = ''
-		if xmlns != ixmlns and ixmlns != '' and ixmlns != self.namespace:
-			if self.stream is not None and ixmlns in self.stream.namespace_map:
-				if self.stream.namespace_map[ixmlns] != '':
-					itag = "%s:%s" % (self.stream.namespace_map[ixmlns], itag)
-			else:
-				nsbuffer = """ xmlns="%s\"""" % ixmlns
-		if ixmlns not in ('', xmlns, self.namespace):
-			nsbuffer = """ xmlns="%s\"""" % ixmlns
-		newoutput.append("<%s" % itag)
-		newoutput.append(nsbuffer)
-		for attrib in xml.attrib:
-			if '{' not in attrib:
-				newoutput.append(""" %s="%s\"""" % (attrib, self.xmlesc(xml.attrib[attrib])))
-		if len(xml) or xml.text or xml.tail:
-			newoutput.append(">")
-			if xml.text:
-				newoutput.append(self.xmlesc(xml.text))
-			if len(xml):
-				for child in xml.getchildren():
-					newoutput.append(self.__str__(child, ixmlns))
-			newoutput.append("</%s>" % (itag, ))
-			if xml.tail:
-				newoutput.append(self.xmlesc(xml.tail))
-		elif xml.text:
-			newoutput.append(">%s</%s>" % (self.xmlesc(xml.text), itag))
-		else:
-			newoutput.append(" />")
-		return ''.join(newoutput)
-
-	def xmlesc(self, text):
-		text = list(text)
-		cc = 0
-		matches = ('&', '<', '"', '>', "'")
-		for c in text:
-			if c in matches:
-				if c == '&':
-					text[cc] = '&amp;'
-				elif c == '<':
-					text[cc] = '&lt;'
-				elif c == '>':
-					text[cc] = '&gt;'
-				elif c == "'":
-					text[cc] = '&apos;'
-				else:
-					text[cc] = '&quot;'
-			cc += 1
-		return ''.join(text)
+    See the file LICENSE for copying permission.
+"""
+
+
+def tostring(xml=None, xmlns='', stanza_ns='', stream=None, outbuffer=''):
+    """
+    Serialize an XML object to a Unicode string.
+
+    Arguments:
+        xml       -- The XML object to serialize. If the value is None,
+                     then the XML object contained in this stanza
+                     object will be used.
+        xmlns     -- Optional namespace of an element wrapping the XML
+                     object.
+        stanza_ns -- The namespace of the stanza object that contains
+                     the XML object.
+        stream    -- The XML stream that generated the XML object.
+        outbuffer -- Optional buffer for storing serializations during
+                     recursive calls.
+    """
+    # Add previous results to the start of the output.
+    output = [outbuffer]
+
+    # Extract the element's tag name.
+    tag_name = xml.tag.split('}', 1)[-1]
+
+    # Extract the element's namespace if it is defined.
+    if '}' in xml.tag:
+        tag_xmlns = xml.tag.split('}', 1)[0][1:]
+    else:
+        tag_xmlns = ''
+
+    # Output the tag name and derived namespace of the element.
+    namespace = ''
+    if tag_xmlns not in ['', xmlns, stanza_ns]:
+        namespace = ' xmlns="%s"' % tag_xmlns
+        if stream and tag_xmlns in stream.namespace_map:
+            mapped_namespace = stream.namespace_map[tag_xmlns]
+            if mapped_namespace:
+                tag = "%s:%s" % (mapped_namespace, tag_name)
+    output.append("<%s" % tag_name)
+    output.append(namespace)
+
+    # Output escaped attribute values.
+    for attrib, value in xml.attrib.items():
+        if '{' not in attrib:
+            value = xml_escape(value)
+            output.append(' %s="%s"' % (attrib, value))
+
+    if len(xml) or xml.text:
+        # If there are additional child elements to serialize.
+        output.append(">")
+        if xml.text:
+            output.append(xml_escape(xml.text))
+        if len(xml):
+            for child in xml.getchildren():
+                output.append(tostring(child, tag_xmlns, stanza_ns, stream))
+        output.append("</%s>" % tag_name)
+    elif xml.text:
+        # If we only have text content.
+        output.append(">%s</%s>" % (xml_escape(xml.text), tag_name))
+    else:
+        # Empty element.
+        output.append(" />")
+    if xml.tail:
+        # If there is additional text after the element.
+        output.append(xml_escape(xml.tail))
+    return ''.join(output)
+
+
+def xml_escape(text):
+    """
+    Convert special characters in XML to escape sequences.
+
+    Arguments:
+        text -- The XML text to convert.
+    """
+    text = list(text)
+    escapes = {'&': '&amp;',
+               '<': '&lt;',
+               '>': '&gt;',
+               "'": '&apos;',
+               '"': '&quot;'}
+    for i, c in enumerate(text):
+        text[i] = escapes.get(c, c)
+    return ''.join(text)
diff --git a/sleekxmpp/xmlstream/tostring/tostring26.py b/sleekxmpp/xmlstream/tostring/tostring26.py
index 9711c300..9dba2717 100644
--- a/sleekxmpp/xmlstream/tostring/tostring26.py
+++ b/sleekxmpp/xmlstream/tostring/tostring26.py
@@ -1,65 +1,100 @@
+"""
+    SleekXMPP: The Sleek XMPP Library
+    Copyright (C) 2010  Nathanael C. Fritz
+    This file is part of SleekXMPP.
+
+    See the file LICENSE for copying permission.
+"""
+
+from __future__ import unicode_literals
 import types
 
-class ToString(object):
-	def __str__(self, xml=None, xmlns='', stringbuffer=''):
-		if xml is None:
-			xml = self.xml
-		newoutput = [stringbuffer]
-		#TODO respect ET mapped namespaces
-		itag = xml.tag.split('}', 1)[-1]
-		if '}' in xml.tag:
-			ixmlns = xml.tag.split('}', 1)[0][1:]
-		else:
-			ixmlns = ''
-		nsbuffer = ''
-		if xmlns != ixmlns and ixmlns != u'' and ixmlns != self.namespace:
-			if self.stream is not None and ixmlns in self.stream.namespace_map:
-				if self.stream.namespace_map[ixmlns] != u'':
-					itag = "%s:%s" % (self.stream.namespace_map[ixmlns], itag)
-			else:
-				nsbuffer = """ xmlns="%s\"""" % ixmlns
-		if ixmlns not in ('', xmlns, self.namespace):
-			nsbuffer = """ xmlns="%s\"""" % ixmlns
-		newoutput.append("<%s" % itag)
-		newoutput.append(nsbuffer)
-		for attrib in xml.attrib:
-			if '{' not in attrib:
-				newoutput.append(""" %s="%s\"""" % (attrib, self.xmlesc(xml.attrib[attrib])))
-		if len(xml) or xml.text or xml.tail:
-			newoutput.append(u">")
-			if xml.text:
-				newoutput.append(self.xmlesc(xml.text))
-			if len(xml):
-				for child in xml.getchildren():
-					newoutput.append(self.__str__(child, ixmlns))
-			newoutput.append(u"</%s>" % (itag, ))
-			if xml.tail:
-				newoutput.append(self.xmlesc(xml.tail))
-		elif xml.text:
-			newoutput.append(">%s</%s>" % (self.xmlesc(xml.text), itag))
-		else:
-			newoutput.append(" />")
-		return u''.join(newoutput)
 
-	def xmlesc(self, text):
-		if type(text) != types.UnicodeType:
-			text = list(unicode(text, 'utf-8', 'ignore'))
-		else:
-			text = list(text)
+def tostring(xml=None, xmlns='', stanza_ns='', stream=None, outbuffer=''):
+    """
+    Serialize an XML object to a Unicode string.
+
+    Arguments:
+        xml       -- The XML object to serialize. If the value is None,
+                     then the XML object contained in this stanza
+                     object will be used.
+        xmlns     -- Optional namespace of an element wrapping the XML
+                     object.
+        stanza_ns -- The namespace of the stanza object that contains
+                     the XML object.
+        stream    -- The XML stream that generated the XML object.
+        outbuffer -- Optional buffer for storing serializations during
+                     recursive calls.
+    """
+    # Add previous results to the start of the output.
+    output = [outbuffer]
+
+    # Extract the element's tag name.
+    tag_name = xml.tag.split('}', 1)[-1]
+
+    # Extract the element's namespace if it is defined.
+    if '}' in xml.tag:
+        tag_xmlns = xml.tag.split('}', 1)[0][1:]
+    else:
+        tag_xmlns = u''
+
+    # Output the tag name and derived namespace of the element.
+    namespace = u''
+    if tag_xmlns not in ['', xmlns, stanza_ns]:
+        namespace = u' xmlns="%s"' % tag_xmlns
+        if stream and tag_xmlns in stream.namespace_map:
+            mapped_namespace = stream.namespace_map[tag_xmlns]
+            if mapped_namespace:
+                tag = u"%s:%s" % (mapped_namespace, tag_name)
+    output.append(u"<%s" % tag_name)
+    output.append(namespace)
+
+    # Output escaped attribute values.
+    for attrib, value in xml.attrib.items():
+        if '{' not in attrib:
+            value = xml_escape(value)
+            output.append(u' %s="%s"' % (attrib, value))
+
+    if len(xml) or xml.text:
+        # If there are additional child elements to serialize.
+        output.append(u">")
+        if xml.text:
+            output.append(xml_escape(xml.text))
+        if len(xml):
+            for child in xml.getchildren():
+                output.append(tostring(child, tag_xmlns, stanza_ns, stream))
+        output.append(u"</%s>" % tag_name)
+        if xml.tail:
+            # If there is additional text after the element.
+            output.append(xml_escape(xml.tail))
+    elif xml.text:
+        # If we only have text content.
+        output.append(u">%s</%s>" % (xml_escape(xml.text), tag_name))
+    else:
+        # Empty element.
+        output.append(u" />")
+    if xml.tail:
+        # If there is additional text after the element.
+        output.append(xml_escape(xml.tail))
+    return u''.join(output)
+
+
+def xml_escape(text):
+    """
+    Convert special characters in XML to escape sequences.
 
-		cc = 0
-		matches = (u'&', u'<', u'"', u'>', u"'")
-		for c in text:
-			if c in matches:
-				if c == u'&':
-					text[cc] = u'&amp;'
-				elif c == u'<':
-					text[cc] = u'&lt;'
-				elif c == u'>':
-					text[cc] = u'&gt;'
-				elif c == u"'":
-					text[cc] = u'&apos;'
-				else:
-					text[cc] = u'&quot;'
-			cc += 1
-		return ''.join(text)
+    Arguments:
+        text -- The XML text to convert.
+    """
+    if type(text) != types.UnicodeType:
+        text = list(unicode(text, 'utf-8', 'ignore'))
+    else:
+        text = list(text)
+    escapes = {u'&': u'&amp;',
+               u'<': u'&lt;',
+               u'>': u'&gt;',
+               u"'": u'&apos;',
+               u'"': u'&quot;'}
+    for i, c in enumerate(text):
+        text[i] = escapes.get(c, c)
+    return u''.join(text)
diff --git a/sleekxmpp/xmlstream/tostring26/__init__.py b/sleekxmpp/xmlstream/tostring26/__init__.py
deleted file mode 100644
index 9711c300..00000000
--- a/sleekxmpp/xmlstream/tostring26/__init__.py
+++ /dev/null
@@ -1,65 +0,0 @@
-import types
-
-class ToString(object):
-	def __str__(self, xml=None, xmlns='', stringbuffer=''):
-		if xml is None:
-			xml = self.xml
-		newoutput = [stringbuffer]
-		#TODO respect ET mapped namespaces
-		itag = xml.tag.split('}', 1)[-1]
-		if '}' in xml.tag:
-			ixmlns = xml.tag.split('}', 1)[0][1:]
-		else:
-			ixmlns = ''
-		nsbuffer = ''
-		if xmlns != ixmlns and ixmlns != u'' and ixmlns != self.namespace:
-			if self.stream is not None and ixmlns in self.stream.namespace_map:
-				if self.stream.namespace_map[ixmlns] != u'':
-					itag = "%s:%s" % (self.stream.namespace_map[ixmlns], itag)
-			else:
-				nsbuffer = """ xmlns="%s\"""" % ixmlns
-		if ixmlns not in ('', xmlns, self.namespace):
-			nsbuffer = """ xmlns="%s\"""" % ixmlns
-		newoutput.append("<%s" % itag)
-		newoutput.append(nsbuffer)
-		for attrib in xml.attrib:
-			if '{' not in attrib:
-				newoutput.append(""" %s="%s\"""" % (attrib, self.xmlesc(xml.attrib[attrib])))
-		if len(xml) or xml.text or xml.tail:
-			newoutput.append(u">")
-			if xml.text:
-				newoutput.append(self.xmlesc(xml.text))
-			if len(xml):
-				for child in xml.getchildren():
-					newoutput.append(self.__str__(child, ixmlns))
-			newoutput.append(u"</%s>" % (itag, ))
-			if xml.tail:
-				newoutput.append(self.xmlesc(xml.tail))
-		elif xml.text:
-			newoutput.append(">%s</%s>" % (self.xmlesc(xml.text), itag))
-		else:
-			newoutput.append(" />")
-		return u''.join(newoutput)
-
-	def xmlesc(self, text):
-		if type(text) != types.UnicodeType:
-			text = list(unicode(text, 'utf-8', 'ignore'))
-		else:
-			text = list(text)
-
-		cc = 0
-		matches = (u'&', u'<', u'"', u'>', u"'")
-		for c in text:
-			if c in matches:
-				if c == u'&':
-					text[cc] = u'&amp;'
-				elif c == u'<':
-					text[cc] = u'&lt;'
-				elif c == u'>':
-					text[cc] = u'&gt;'
-				elif c == u"'":
-					text[cc] = u'&apos;'
-				else:
-					text[cc] = u'&quot;'
-			cc += 1
-		return ''.join(text)
diff --git a/sleekxmpp/xmlstream/xmlstream.py b/sleekxmpp/xmlstream/xmlstream.py
index 94fed64a..ffaa6514 100644
--- a/sleekxmpp/xmlstream/xmlstream.py
+++ b/sleekxmpp/xmlstream/xmlstream.py
@@ -23,6 +23,7 @@ import types
 import copy
 import xml.sax.saxutils
 from . import scheduler
+from sleekxmpp.xmlstream.tostring import tostring
 
 RESPONSE_TIMEOUT = 10
 HANDLER_THREADS = 1
@@ -37,7 +38,7 @@ if sys.version_info < (3, 0):
 	#monkey patch broken filesocket object
 	from . import filesocket
 	#socket._fileobject = filesocket.filesocket
-	
+
 
 class RestartStream(Exception):
 	pass
@@ -82,7 +83,7 @@ class XMLStream(object):
 		self.namespace_map = {}
 
 		self.run = True
-	
+
 	def setSocket(self, socket):
 		"Set the socket"
 		self.socket = socket
@@ -90,10 +91,10 @@ class XMLStream(object):
 			self.filesocket = socket.makefile('rb', 0) # ElementTree.iterparse requires a file.  0 buffer files have to be binary
 			self.state.set('connected', True)
 
-	
+
 	def setFileSocket(self, filesocket):
 		self.filesocket = filesocket
-	
+
 	def connect(self, host='', port=0, use_ssl=False, use_tls=True):
 		"Link to connectTCP"
 		return self.connectTCP(host, port, use_ssl, use_tls)
@@ -125,7 +126,7 @@ class XMLStream(object):
 			except socket.error as serr:
 				logging.error("Could not connect. Socket Error #%s: %s" % (serr.errno, serr.strerror))
 				time.sleep(1)
-	
+
 	def connectUnix(self, filepath):
 		"Connect to Unix file and create socket"
 
@@ -146,7 +147,7 @@ class XMLStream(object):
 			logging.warning("Tried to enable TLS, but ssl module not found.")
 			return False
 		raise RestartStream()
-	
+
 	def process(self, threaded=True):
 		self.scheduler.process(threaded=True)
 		for t in range(0, HANDLER_THREADS):
@@ -160,10 +161,10 @@ class XMLStream(object):
 			self.__thread['process'].start()
 		else:
 			self._process()
-	
+
 	def schedule(self, name, seconds, callback, args=None, kwargs=None, repeat=False):
 		self.scheduler.add(name, seconds, callback, args, kwargs, repeat, qpointer=self.eventqueue)
-	
+
 	def _process(self):
 		"Start processing the socket."
 		firstrun = True
@@ -212,7 +213,7 @@ class XMLStream(object):
 		#self.__thread['readXML'].start()
 		#self.__thread['spawnEvents'] = threading.Thread(name='spawnEvents', target=self.__spawnEvents)
 		#self.__thread['spawnEvents'].start()
-	
+
 	def __readXML(self):
 		"Parses the incoming stream, adding to xmlin queue as it goes"
 		#build cElementTree object from expat was we go
@@ -245,7 +246,7 @@ class XMLStream(object):
 			if event == b'start':
 				edepth += 1
 		logging.debug("Ending readXML loop")
-	
+
 	def _sendThread(self):
 		while self.run:
 			data = self.sendqueue.get(True)
@@ -260,11 +261,11 @@ class XMLStream(object):
 				if self.state.reconnect:
 					logging.exception("Disconnected. Socket Error.")
 					self.disconnect(reconnect=True)
-	
+
 	def sendRaw(self, data):
 		self.sendqueue.put(data)
 		return True
-	
+
 	def disconnect(self, reconnect=False):
 		self.state.set('reconnect', reconnect)
 		if self.state['disconnecting']:
@@ -290,20 +291,20 @@ class XMLStream(object):
 		if self.state['processing']:
 			#raise CloseStream
 			pass
-	
+
 	def reconnect(self):
 		self.state.set('tls',False)
 		self.state.set('ssl',False)
 		time.sleep(1)
 		self.connect()
-	
+
 	def incoming_filter(self, xmlobj):
 		return xmlobj
-		
+
 	def __spawnEvent(self, xmlobj):
 		"watching xmlOut and processes handlers"
 		#convert XML into Stanza
-		logging.debug("RECV: %s" % cElementTree.tostring(xmlobj))
+		logging.debug("RECV: %s" % tostring(xmlobj))
 		xmlobj = self.incoming_filter(xmlobj)
 		stanza_type = StanzaBase
 		for stanza_class in self.__root_stanza:
@@ -323,7 +324,7 @@ class XMLStream(object):
 			stanza.unhandled()
 			#loop through handlers and test match
 			#spawn threads as necessary, call handlers, sending Stanza
-	
+
 	def _eventRunner(self):
 		logging.debug("Loading event runner")
 		while self.run:
@@ -354,11 +355,11 @@ class XMLStream(object):
 				elif etype == 'quit':
 					logging.debug("Quitting eventRunner thread")
 					return False
-	
+
 	def registerHandler(self, handler, before=None, after=None):
 		"Add handler with matcher class and parameters."
 		self.__handlers.append(handler)
-	
+
 	def removeHandler(self, name):
 		"Removes the handler."
 		idx = 0
@@ -367,81 +368,27 @@ class XMLStream(object):
 				self.__handlers.pop(idx)
 				return
 			idx += 1
-	
+
 	def registerStanza(self, stanza_class):
 		"Adds stanza.  If root stanzas build stanzas sent in events while non-root stanzas build substanza objects."
 		self.__root_stanza.append(stanza_class)
-	
+
 	def registerStanzaExtension(self, stanza_class, stanza_extension):
 		if stanza_class not in stanza_extensions:
 			stanza_extensions[stanza_class] = [stanza_extension]
 		else:
 			stanza_extensions[stanza_class].append(stanza_extension)
-	
+
 	def removeStanza(self, stanza_class, root=False):
 		"Removes the stanza's registration."
 		if root:
 			del self.__root_stanza[stanza_class]
 		else:
 			del self.__stanza[stanza_class]
-	
+
 	def removeStanzaExtension(self, stanza_class, stanza_extension):
 		stanza_extension[stanza_class].pop(stanza_extension)
 
-	def tostring(self, xml, xmlns='', stringbuffer=''):
-		newoutput = [stringbuffer]
-		#TODO respect ET mapped namespaces
-		itag = xml.tag.split('}', 1)[-1]
-		if '}' in xml.tag:
-			ixmlns = xml.tag.split('}', 1)[0][1:]
-		else:
-			ixmlns = ''
-		nsbuffer = ''
-		if xmlns != ixmlns and ixmlns != '':
-			if ixmlns in self.namespace_map:
-				if self.namespace_map[ixmlns] != '':
-					itag = "%s:%s" % (self.namespace_map[ixmlns], itag)
-			else:
-				nsbuffer = """ xmlns="%s\"""" % ixmlns
-		newoutput.append("<%s" % itag)
-		newoutput.append(nsbuffer)
-		for attrib in xml.attrib:
-			newoutput.append(""" %s="%s\"""" % (attrib, self.xmlesc(xml.attrib[attrib])))
-		if len(xml) or xml.text or xml.tail:
-			newoutput.append(">")
-			if xml.text:
-				newoutput.append(self.xmlesc(xml.text))
-			if len(xml):
-				for child in xml.getchildren():
-					newoutput.append(self.tostring(child, ixmlns))
-			newoutput.append("</%s>" % (itag, ))
-			if xml.tail:
-				newoutput.append(self.xmlesc(xml.tail))
-		elif xml.text:
-			newoutput.append(">%s</%s>" % (self.xmlesc(xml.text), itag))
-		else:
-			newoutput.append(" />")
-		return ''.join(newoutput)
-
-	def xmlesc(self, text):
-		text = list(text)
-		cc = 0
-		matches = ('&', '<', '"', '>', "'")
-		for c in text:
-			if c in matches:
-				if c == '&':
-					text[cc] = '&amp;'
-				elif c == '<':
-					text[cc] = '&lt;'
-				elif c == '>':
-					text[cc] = '&gt;'
-				elif c == "'":
-					text[cc] = '&apos;'
-				elif self.escape_quotes:
-					text[cc] = '&quot;'
-			cc += 1
-		return ''.join(text)
-	
 	def start_stream_handler(self, xml):
 		"""Meant to be overridden"""
 		pass
-- 
cgit v1.2.3