Improvements in XmlMarshaller: any Python variable may be the root of a structure to marshall.

This commit is contained in:
Gaetan Delannay 2010-02-23 14:55:51 +01:00
parent 37c252c3fd
commit 15ef6f334d

View file

@ -17,7 +17,7 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,USA.
# ------------------------------------------------------------------------------
import xml.sax, difflib
import xml.sax, difflib, types
from xml.sax.handler import ContentHandler, ErrorHandler
from xml.sax.xmlreader import InputSource
from appy.shared import UnicodeBuffer
@ -401,6 +401,15 @@ class XmlMarshaller:
self.dumpString(res, value)
elif isinstance(value, bool):
res.write(self.trueFalse[value])
elif self.isAnObject(value):
if hasattr(value, 'absolute_url'):
res.write(value.absolute_url())
else:
res.write(value)
# We could dump the entire object content, too. Maybe we could add a
# parameter to the marshaller to know how to marshall objects
# (produce an ID, an URL, include the entire tag but we need to take
# care of circular references,...)
else:
res.write(value)
@ -434,23 +443,40 @@ class XmlMarshaller:
self.dumpValue(res, fieldValue, fieldType)
res.write('</'); res.write(fieldName); res.write('>')
def isAnObject(self, instance):
'''Returns True if p_instance is a class instance, False if it is a
basic type, or tuple, sequence, etc.'''
iType = type(instance)
if iType == types.InstanceType:
return True
elif iType.__name__ == 'ImplicitAcquirerWrapper':
# This is the case with Archetype instances
return True
return False
def marshall(self, instance, objectType='popo'):
'''Returns in a UnicodeBuffer the XML version of p_instance. If
p_instance corresponds to a Plain Old Python Object, specify 'popo'
for p_objectType. If p_instance corresponds to an Archetypes object
(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. If p_instance is not
an instance at all, but another Python data structure or basic type,
p_objectType is ignored.'''
# Call the XmlMarshaller constructor if it hasn't been called yet.
if not hasattr(self, 'cdata'):
# The constructor has not been called. Do it now.
XmlMarshaller.__init__(self)
# Create the buffer where the XML result will be dumped.
res = UnicodeBuffer()
# Dump the XML prologue and root element
# Dump the XML prologue
res.write(self.xmlPrologue)
if self.isAnObject(instance):
# Determine object ID
if objectType in ('archetype', 'appy'):
objectId = instance.UID() # ID in DB
else: objectId = str(id(instance)) # ID in RAM
res.write(self.xmlPrologue)
else:
objectId = str(id(instance)) # ID in RAM
res.write('<'); res.write(self.rootElementName)
res.write(' type="object" id="'); res.write(objectId); res.write('">')
res.write(' type="object" id="');res.write(objectId);res.write('">')
# Dump the object ID and the value of the fields that must be dumped
if objectType == 'popo':
for fieldName, fieldValue in instance.__dict__.iteritems():
@ -460,8 +486,8 @@ class XmlMarshaller:
elif self.fieldsToMarshall == 'all':
mustDump = True
else:
if (type(self.fieldsToMarshall) in self.sequenceTypes) and \
(fieldName in self.fieldsToMarshall):
if (type(self.fieldsToMarshall) in self.sequenceTypes) \
and (fieldName in self.fieldsToMarshall):
mustDump = True
if mustDump:
self.dumpField(res, fieldName, fieldValue)
@ -478,8 +504,8 @@ class XmlMarshaller:
elif self.fieldsToMarshall == 'all_with_metadata':
mustDump = True
else:
if (type(self.fieldsToMarshall) in self.sequenceTypes) and \
(field.getName() in self.fieldsToMarshall):
if (type(self.fieldsToMarshall) in self.sequenceTypes) \
and (field.getName() in self.fieldsToMarshall):
mustDump = True
if mustDump:
fieldType = 'basic'
@ -487,7 +513,7 @@ class XmlMarshaller:
fieldType = 'file'
elif field.type == 'reference':
fieldType = 'ref'
self.dumpField(res, field.getName(), field.get(instance),
self.dumpField(res, field.getName(),field.get(instance),
fieldType=fieldType)
if objectType == 'appy':
# Dump the object history.
@ -497,12 +523,15 @@ class XmlMarshaller:
history = instance.workflow_history[wfInfo[0].id]
for event in history:
res.write('<event type="object">')
for k, v in event.iteritems(): self.dumpField(res, k, v)
for k, v in event.iteritems():
self.dumpField(res, k, v)
res.write('</event>')
res.write('</history>')
self.marshallSpecificElements(instance, res)
# Return the result
res.write('</'); res.write(self.rootElementName); res.write('>')
else:
self.dumpField(res, self.rootElementName, instance)
# Return the result
res = res.getValue()
if not self.dumpUnicode:
res = res.encode('utf-8')