Use of a replacement to StringIO for managing encoding problems while marchalling Python objects.

This commit is contained in:
Gaetan Delannay 2010-02-02 16:25:10 +01:00
parent 36a740ed7e
commit 160c4960da
2 changed files with 30 additions and 20 deletions

View file

@ -37,6 +37,20 @@ class UnmarshalledFile:
self.content = '' # The binary content of the file of a file object self.content = '' # The binary content of the file of a file object
self.size = 0 # The length of the file in bytes. self.size = 0 # The length of the file in bytes.
class UnicodeBuffer:
'''With StringIO class, I have tons of encoding problems. So I define a
similar class here, that uses an internal unicode buffer.'''
def __init__(self):
self.buffer = u''
def write(self, s):
if s == None: return
if isinstance(s, unicode):
self.buffer += s
elif isinstance(s, str):
self.buffer += s.decode('utf-8')
else:
self.buffer += unicode(s)
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
class Dummy: pass class Dummy: pass
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------

View file

@ -20,7 +20,7 @@
import xml.sax, difflib import xml.sax, difflib
from xml.sax.handler import ContentHandler, ErrorHandler from xml.sax.handler import ContentHandler, ErrorHandler
from xml.sax.xmlreader import InputSource from xml.sax.xmlreader import InputSource
from StringIO import StringIO from appy.shared import UnicodeBuffer
from appy.shared.errors import AppyError from appy.shared.errors import AppyError
# Error-related constants ------------------------------------------------------ # Error-related constants ------------------------------------------------------
@ -343,24 +343,16 @@ class XmlMarshaller:
def dumpString(self, res, s): def dumpString(self, res, s):
'''Dumps a string into the result.''' '''Dumps a string into the result.'''
if hasattr(self, 'cdata') and self.cdata: res.write('<![CDATA[') if self.cdata: res.write('<![CDATA[')
# Try to solve encoding problems if isinstance(s, str):
try: s = s.decode('utf-8')
if hasattr(self, 'dumpUnicode') and self.dumpUnicode:
# Produce a unicode
s = s.decode('utf-8')
else:
# Produce a str
s = s.decode('utf-8').encode('utf-8')
except UnicodeEncodeError:
pass
# Replace special chars by XML entities # Replace special chars by XML entities
for c in s: for c in s:
if self.xmlEntities.has_key(c): if self.xmlEntities.has_key(c):
res.write(self.xmlEntities[c]) res.write(self.xmlEntities[c])
else: else:
res.write(c) res.write(c)
if hasattr(self, 'cdata') and self.cdata: res.write(']]>') if self.cdata: res.write(']]>')
def dumpFile(self, res, v): def dumpFile(self, res, v):
'''Dumps a file into the result.''' '''Dumps a file into the result.'''
@ -443,12 +435,15 @@ class XmlMarshaller:
res.write('</'); res.write(fieldName); res.write('>') res.write('</'); res.write(fieldName); res.write('>')
def marshall(self, instance, objectType='popo'): def marshall(self, instance, objectType='popo'):
'''Returns in a StringIO the XML version of p_instance. If p_instance '''Returns in a UnicodeBuffer the XML version of p_instance. If
corresponds to a Plain Old Python Object, specify 'popo' for p_instance corresponds to a Plain Old Python Object, specify 'popo'
p_objectType. If p_instance corresponds to an Archetypes object for p_objectType. If p_instance corresponds to an Archetypes object
(Zope/Plone), specify 'archetype' for p_objectType. if p_instance is (Zope/Plone), specify 'archetype' for p_objectType. if p_instance is
a Appy object, specify "appy" as p_objectType.''' a Appy object, specify "appy" as p_objectType.'''
res = StringIO() if not hasattr(self, 'cdata'):
# The constructor has not been called. Do it now.
XmlMarshaller.__init__(self)
res = UnicodeBuffer()
# Dump the XML prologue and root element # Dump the XML prologue and root element
if objectType in ('archetype', 'appy'): if objectType in ('archetype', 'appy'):
objectId = instance.UID() # ID in DB objectId = instance.UID() # ID in DB
@ -508,9 +503,10 @@ class XmlMarshaller:
self.marshallSpecificElements(instance, res) self.marshallSpecificElements(instance, res)
# Return the result # Return the result
res.write('</'); res.write(self.rootElementName); res.write('>') res.write('</'); res.write(self.rootElementName); res.write('>')
data = res.getvalue() res = res.buffer
res.close() if not self.dumpUnicode:
return data res = res.encode('utf-8')
return res
def marshallSpecificElements(self, instance, res): def marshallSpecificElements(self, instance, res):
'''You can use this marshaller as a base class for creating your own. '''You can use this marshaller as a base class for creating your own.