From 15ef6f334d1cd4003c3c7143858c45a2dff2fcdf Mon Sep 17 00:00:00 2001 From: Gaetan Delannay Date: Tue, 23 Feb 2010 14:55:51 +0100 Subject: [PATCH] Improvements in XmlMarshaller: any Python variable may be the root of a structure to marshall. --- shared/xml_parser.py | 149 ++++++++++++++++++++++++++----------------- 1 file changed, 89 insertions(+), 60 deletions(-) diff --git a/shared/xml_parser.py b/shared/xml_parser.py index 33e33a4..8000265 100644 --- a/shared/xml_parser.py +++ b/shared/xml_parser.py @@ -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) @@ -411,12 +420,12 @@ class XmlMarshaller: fType = None # No type will mean "unicode". if fieldType == 'file': fType ='file' elif fieldType == 'ref': fType = 'list' - elif isinstance(fieldValue, bool): fType = 'bool' - elif isinstance(fieldValue, int): fType = 'int' + elif isinstance(fieldValue, bool): fType = 'bool' + elif isinstance(fieldValue, int): fType = 'int' elif isinstance(fieldValue, float): fType = 'float' - elif isinstance(fieldValue, long): fType = 'long' + elif isinstance(fieldValue, long): fType = 'long' elif isinstance(fieldValue, tuple): fType = 'tuple' - elif isinstance(fieldValue, list): fType = 'list' + elif isinstance(fieldValue, list): fType = 'list' elif fieldValue.__class__.__name__ == 'DateTime': fType = 'DateTime' if fType: res.write(' type="%s"' % fType) # Dump other attributes if needed @@ -434,75 +443,95 @@ class XmlMarshaller: self.dumpValue(res, fieldValue, fieldType) 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 - if objectType in ('archetype', 'appy'): - objectId = instance.UID() # ID in DB - else: objectId = str(id(instance)) # ID in RAM + # Dump the XML prologue res.write(self.xmlPrologue) - res.write('<'); res.write(self.rootElementName) - 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(): - mustDump = False - if fieldName in self.fieldsToExclude: + 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('<'); res.write(self.rootElementName) + 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(): mustDump = False - elif self.fieldsToMarshall == 'all': - mustDump = True - else: - if (type(self.fieldsToMarshall) in self.sequenceTypes) and \ - (fieldName in self.fieldsToMarshall): + if fieldName in self.fieldsToExclude: + mustDump = False + elif self.fieldsToMarshall == 'all': mustDump = True - if mustDump: - self.dumpField(res, fieldName, fieldValue) - elif objectType in ('archetype', 'appy'): - fields = instance.schema.fields() - for field in instance.schema.fields(): - # Dump only needed fields - mustDump = False - if field.getName() in self.fieldsToExclude: + else: + if (type(self.fieldsToMarshall) in self.sequenceTypes) \ + and (fieldName in self.fieldsToMarshall): + mustDump = True + if mustDump: + self.dumpField(res, fieldName, fieldValue) + elif objectType in ('archetype', 'appy'): + fields = instance.schema.fields() + for field in instance.schema.fields(): + # Dump only needed fields mustDump = False - elif (self.fieldsToMarshall == 'all') and \ - (field.schemata != 'metadata'): - mustDump = True - elif self.fieldsToMarshall == 'all_with_metadata': - mustDump = True - else: - if (type(self.fieldsToMarshall) in self.sequenceTypes) and \ - (field.getName() in self.fieldsToMarshall): + if field.getName() in self.fieldsToExclude: + mustDump = False + elif (self.fieldsToMarshall == 'all') and \ + (field.schemata != 'metadata'): mustDump = True - if mustDump: - fieldType = 'basic' - if field.type in self.atFiles: - fieldType = 'file' - elif field.type == 'reference': - fieldType = 'ref' - self.dumpField(res, field.getName(), field.get(instance), - fieldType=fieldType) - if objectType == 'appy': - # Dump the object history. - res.write('') - wfInfo = instance.portal_workflow.getWorkflowsFor(instance) - if wfInfo: - history = instance.workflow_history[wfInfo[0].id] - for event in history: - res.write('') - for k, v in event.iteritems(): self.dumpField(res, k, v) - res.write('') - res.write('') - self.marshallSpecificElements(instance, res) + elif self.fieldsToMarshall == 'all_with_metadata': + mustDump = True + else: + if (type(self.fieldsToMarshall) in self.sequenceTypes) \ + and (field.getName() in self.fieldsToMarshall): + mustDump = True + if mustDump: + fieldType = 'basic' + if field.type in self.atFiles: + fieldType = 'file' + elif field.type == 'reference': + fieldType = 'ref' + self.dumpField(res, field.getName(),field.get(instance), + fieldType=fieldType) + if objectType == 'appy': + # Dump the object history. + res.write('') + wfInfo = instance.portal_workflow.getWorkflowsFor(instance) + if wfInfo: + history = instance.workflow_history[wfInfo[0].id] + for event in history: + res.write('') + for k, v in event.iteritems(): + self.dumpField(res, k, v) + res.write('') + res.write('') + self.marshallSpecificElements(instance, res) + res.write('') + else: + self.dumpField(res, self.rootElementName, instance) # Return the result - res.write('') res = res.getValue() if not self.dumpUnicode: res = res.encode('utf-8')