From c54466596f3dcc7a35a41c49fff0d057d4a8ed8f Mon Sep 17 00:00:00 2001 From: Lance Stout Date: Wed, 4 Aug 2010 14:41:37 -0400 Subject: Modified sleekxmpp.xmlstream.tostring to import ToString class based on Python version. The package sleekxmpp.xmlstream.tostring26 remains for now until stanzabase is updated, but is no longer needed. --- sleekxmpp/xmlstream/tostring/__init__.py | 70 +++++------------------------- sleekxmpp/xmlstream/tostring/tostring.py | 60 +++++++++++++++++++++++++ sleekxmpp/xmlstream/tostring/tostring26.py | 65 +++++++++++++++++++++++++++ 3 files changed, 137 insertions(+), 58 deletions(-) create mode 100644 sleekxmpp/xmlstream/tostring/tostring.py create mode 100644 sleekxmpp/xmlstream/tostring/tostring26.py (limited to 'sleekxmpp/xmlstream/tostring') diff --git a/sleekxmpp/xmlstream/tostring/__init__.py b/sleekxmpp/xmlstream/tostring/__init__.py index 6603cbb8..d93fe4ea 100644 --- a/sleekxmpp/xmlstream/tostring/__init__.py +++ b/sleekxmpp/xmlstream/tostring/__init__.py @@ -1,60 +1,14 @@ +""" -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("" % (itag, )) - if xml.tail: - newoutput.append(self.xmlesc(xml.tail)) - elif xml.text: - newoutput.append(">%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] = '&' - elif c == '<': - text[cc] = '<' - elif c == '>': - text[cc] = '>' - elif c == "'": - text[cc] = ''' - else: - text[cc] = '"' - cc += 1 - return ''.join(text) +import sys + + +# Import the correct ToString class based on the Python version. +if sys.version_info < (3, 0): + from sleekxmpp.xmlstream.tostring.tostring26 import ToString +else: + from sleekxmpp.xmlstream.tostring.tostring import ToString + +__all__ = ['ToString'] diff --git a/sleekxmpp/xmlstream/tostring/tostring.py b/sleekxmpp/xmlstream/tostring/tostring.py new file mode 100644 index 00000000..6603cbb8 --- /dev/null +++ b/sleekxmpp/xmlstream/tostring/tostring.py @@ -0,0 +1,60 @@ + +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("" % (itag, )) + if xml.tail: + newoutput.append(self.xmlesc(xml.tail)) + elif xml.text: + newoutput.append(">%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] = '&' + elif c == '<': + text[cc] = '<' + elif c == '>': + text[cc] = '>' + elif c == "'": + text[cc] = ''' + else: + text[cc] = '"' + cc += 1 + return ''.join(text) diff --git a/sleekxmpp/xmlstream/tostring/tostring26.py b/sleekxmpp/xmlstream/tostring/tostring26.py new file mode 100644 index 00000000..9711c300 --- /dev/null +++ b/sleekxmpp/xmlstream/tostring/tostring26.py @@ -0,0 +1,65 @@ +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"" % (itag, )) + if xml.tail: + newoutput.append(self.xmlesc(xml.tail)) + elif xml.text: + newoutput.append(">%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'&' + elif c == u'<': + text[cc] = u'<' + elif c == u'>': + text[cc] = u'>' + elif c == u"'": + text[cc] = u''' + else: + text[cc] = u'"' + cc += 1 + return ''.join(text) -- cgit v1.2.3 From e077204a16c76df4af90ba067e94c31af3d9e372 Mon Sep 17 00:00:00 2001 From: Lance Stout 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/tostring/__init__.py | 13 ++- sleekxmpp/xmlstream/tostring/tostring.py | 149 ++++++++++++++++----------- sleekxmpp/xmlstream/tostring/tostring26.py | 157 ++++++++++++++++++----------- 3 files changed, 195 insertions(+), 124 deletions(-) (limited to 'sleekxmpp/xmlstream/tostring') 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("" % (itag, )) - if xml.tail: - newoutput.append(self.xmlesc(xml.tail)) - elif xml.text: - newoutput.append(">%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] = '&' - elif c == '<': - text[cc] = '<' - elif c == '>': - text[cc] = '>' - elif c == "'": - text[cc] = ''' - else: - text[cc] = '"' - 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("" % tag_name) + elif xml.text: + # If we only have text content. + output.append(">%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 = {'&': '&', + '<': '<', + '>': '>', + "'": ''', + '"': '"'} + 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"" % (itag, )) - if xml.tail: - newoutput.append(self.xmlesc(xml.tail)) - elif xml.text: - newoutput.append(">%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"" % 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" % (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'&' - elif c == u'<': - text[cc] = u'<' - elif c == u'>': - text[cc] = u'>' - elif c == u"'": - text[cc] = u''' - else: - text[cc] = u'"' - 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'&', + u'<': u'<', + u'>': u'>', + u"'": u''', + u'"': u'"'} + for i, c in enumerate(text): + text[i] = escapes.get(c, c) + return u''.join(text) -- cgit v1.2.3 From 3c0dfb56e6dcd864a29523950fcc23e6c3761ff7 Mon Sep 17 00:00:00 2001 From: Lance Stout Date: Thu, 5 Aug 2010 20:43:38 -0400 Subject: Update tostring docs to clarify what the xmlns and stanza_ns parameters do. --- sleekxmpp/xmlstream/tostring/tostring.py | 4 ++++ sleekxmpp/xmlstream/tostring/tostring26.py | 4 ++++ 2 files changed, 8 insertions(+) (limited to 'sleekxmpp/xmlstream/tostring') diff --git a/sleekxmpp/xmlstream/tostring/tostring.py b/sleekxmpp/xmlstream/tostring/tostring.py index 62ff1181..c2696321 100644 --- a/sleekxmpp/xmlstream/tostring/tostring.py +++ b/sleekxmpp/xmlstream/tostring/tostring.py @@ -11,6 +11,10 @@ def tostring(xml=None, xmlns='', stanza_ns='', stream=None, outbuffer=''): """ Serialize an XML object to a Unicode string. + If namespaces are provided using xmlns or stanza_ns, then elements + that use those namespaces will not include the xmlns attribute in + the output. + Arguments: xml -- The XML object to serialize. If the value is None, then the XML object contained in this stanza diff --git a/sleekxmpp/xmlstream/tostring/tostring26.py b/sleekxmpp/xmlstream/tostring/tostring26.py index 9dba2717..7a376374 100644 --- a/sleekxmpp/xmlstream/tostring/tostring26.py +++ b/sleekxmpp/xmlstream/tostring/tostring26.py @@ -14,6 +14,10 @@ def tostring(xml=None, xmlns='', stanza_ns='', stream=None, outbuffer=''): """ Serialize an XML object to a Unicode string. + If namespaces are provided using xmlns or stanza_ns, then elements + that use those namespaces will not include the xmlns attribute in + the output. + Arguments: xml -- The XML object to serialize. If the value is None, then the XML object contained in this stanza -- cgit v1.2.3