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. # 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.handler import ContentHandler, ErrorHandler
from xml.sax.xmlreader import InputSource from xml.sax.xmlreader import InputSource
from appy.shared import UnicodeBuffer from appy.shared import UnicodeBuffer
@ -401,6 +401,15 @@ class XmlMarshaller:
self.dumpString(res, value) self.dumpString(res, value)
elif isinstance(value, bool): elif isinstance(value, bool):
res.write(self.trueFalse[value]) 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: else:
res.write(value) res.write(value)
@ -434,23 +443,40 @@ class XmlMarshaller:
self.dumpValue(res, fieldValue, fieldType) self.dumpValue(res, fieldValue, fieldType)
res.write('</'); res.write(fieldName); res.write('>') 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'): def marshall(self, instance, objectType='popo'):
'''Returns in a UnicodeBuffer the XML version of p_instance. If '''Returns in a UnicodeBuffer the XML version of p_instance. If
p_instance corresponds to a Plain Old Python Object, specify 'popo' p_instance corresponds to a Plain Old Python Object, specify 'popo'
for 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. 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'): if not hasattr(self, 'cdata'):
# The constructor has not been called. Do it now.
XmlMarshaller.__init__(self) XmlMarshaller.__init__(self)
# Create the buffer where the XML result will be dumped.
res = UnicodeBuffer() 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'): if objectType in ('archetype', 'appy'):
objectId = instance.UID() # ID in DB objectId = instance.UID() # ID in DB
else: objectId = str(id(instance)) # ID in RAM else:
res.write(self.xmlPrologue) objectId = str(id(instance)) # ID in RAM
res.write('<'); res.write(self.rootElementName) 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 # Dump the object ID and the value of the fields that must be dumped
if objectType == 'popo': if objectType == 'popo':
for fieldName, fieldValue in instance.__dict__.iteritems(): for fieldName, fieldValue in instance.__dict__.iteritems():
@ -460,8 +486,8 @@ class XmlMarshaller:
elif self.fieldsToMarshall == 'all': elif self.fieldsToMarshall == 'all':
mustDump = True mustDump = True
else: else:
if (type(self.fieldsToMarshall) in self.sequenceTypes) and \ if (type(self.fieldsToMarshall) in self.sequenceTypes) \
(fieldName in self.fieldsToMarshall): and (fieldName in self.fieldsToMarshall):
mustDump = True mustDump = True
if mustDump: if mustDump:
self.dumpField(res, fieldName, fieldValue) self.dumpField(res, fieldName, fieldValue)
@ -478,8 +504,8 @@ class XmlMarshaller:
elif self.fieldsToMarshall == 'all_with_metadata': elif self.fieldsToMarshall == 'all_with_metadata':
mustDump = True mustDump = True
else: else:
if (type(self.fieldsToMarshall) in self.sequenceTypes) and \ if (type(self.fieldsToMarshall) in self.sequenceTypes) \
(field.getName() in self.fieldsToMarshall): and (field.getName() in self.fieldsToMarshall):
mustDump = True mustDump = True
if mustDump: if mustDump:
fieldType = 'basic' fieldType = 'basic'
@ -487,7 +513,7 @@ class XmlMarshaller:
fieldType = 'file' fieldType = 'file'
elif field.type == 'reference': elif field.type == 'reference':
fieldType = 'ref' fieldType = 'ref'
self.dumpField(res, field.getName(), field.get(instance), self.dumpField(res, field.getName(),field.get(instance),
fieldType=fieldType) fieldType=fieldType)
if objectType == 'appy': if objectType == 'appy':
# Dump the object history. # Dump the object history.
@ -497,12 +523,15 @@ class XmlMarshaller:
history = instance.workflow_history[wfInfo[0].id] history = instance.workflow_history[wfInfo[0].id]
for event in history: for event in history:
res.write('<event type="object">') 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('</event>')
res.write('</history>') res.write('</history>')
self.marshallSpecificElements(instance, res) self.marshallSpecificElements(instance, res)
# Return the result
res.write('</'); res.write(self.rootElementName); res.write('>') res.write('</'); res.write(self.rootElementName); res.write('>')
else:
self.dumpField(res, self.rootElementName, instance)
# Return the result
res = res.getValue() res = res.getValue()
if not self.dumpUnicode: if not self.dumpUnicode:
res = res.encode('utf-8') res = res.encode('utf-8')