Improvements in XmlMarshaller: any Python variable may be the root of a structure to marshall.
This commit is contained in:
parent
37c252c3fd
commit
15ef6f334d
|
@ -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)
|
||||||
|
|
||||||
|
@ -411,12 +420,12 @@ class XmlMarshaller:
|
||||||
fType = None # No type will mean "unicode".
|
fType = None # No type will mean "unicode".
|
||||||
if fieldType == 'file': fType ='file'
|
if fieldType == 'file': fType ='file'
|
||||||
elif fieldType == 'ref': fType = 'list'
|
elif fieldType == 'ref': fType = 'list'
|
||||||
elif isinstance(fieldValue, bool): fType = 'bool'
|
elif isinstance(fieldValue, bool): fType = 'bool'
|
||||||
elif isinstance(fieldValue, int): fType = 'int'
|
elif isinstance(fieldValue, int): fType = 'int'
|
||||||
elif isinstance(fieldValue, float): fType = 'float'
|
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, tuple): fType = 'tuple'
|
||||||
elif isinstance(fieldValue, list): fType = 'list'
|
elif isinstance(fieldValue, list): fType = 'list'
|
||||||
elif fieldValue.__class__.__name__ == 'DateTime': fType = 'DateTime'
|
elif fieldValue.__class__.__name__ == 'DateTime': fType = 'DateTime'
|
||||||
if fType: res.write(' type="%s"' % fType)
|
if fType: res.write(' type="%s"' % fType)
|
||||||
# Dump other attributes if needed
|
# Dump other attributes if needed
|
||||||
|
@ -434,75 +443,95 @@ 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
|
||||||
if objectType in ('archetype', 'appy'):
|
|
||||||
objectId = instance.UID() # ID in DB
|
|
||||||
else: objectId = str(id(instance)) # ID in RAM
|
|
||||||
res.write(self.xmlPrologue)
|
res.write(self.xmlPrologue)
|
||||||
res.write('<'); res.write(self.rootElementName)
|
if self.isAnObject(instance):
|
||||||
res.write(' type="object" id="'); res.write(objectId); res.write('">')
|
# Determine object ID
|
||||||
# Dump the object ID and the value of the fields that must be dumped
|
if objectType in ('archetype', 'appy'):
|
||||||
if objectType == 'popo':
|
objectId = instance.UID() # ID in DB
|
||||||
for fieldName, fieldValue in instance.__dict__.iteritems():
|
else:
|
||||||
mustDump = False
|
objectId = str(id(instance)) # ID in RAM
|
||||||
if fieldName in self.fieldsToExclude:
|
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
|
mustDump = False
|
||||||
elif self.fieldsToMarshall == 'all':
|
if fieldName in self.fieldsToExclude:
|
||||||
mustDump = True
|
mustDump = False
|
||||||
else:
|
elif self.fieldsToMarshall == 'all':
|
||||||
if (type(self.fieldsToMarshall) in self.sequenceTypes) and \
|
|
||||||
(fieldName in self.fieldsToMarshall):
|
|
||||||
mustDump = True
|
mustDump = True
|
||||||
if mustDump:
|
else:
|
||||||
self.dumpField(res, fieldName, fieldValue)
|
if (type(self.fieldsToMarshall) in self.sequenceTypes) \
|
||||||
elif objectType in ('archetype', 'appy'):
|
and (fieldName in self.fieldsToMarshall):
|
||||||
fields = instance.schema.fields()
|
mustDump = True
|
||||||
for field in instance.schema.fields():
|
if mustDump:
|
||||||
# Dump only needed fields
|
self.dumpField(res, fieldName, fieldValue)
|
||||||
mustDump = False
|
elif objectType in ('archetype', 'appy'):
|
||||||
if field.getName() in self.fieldsToExclude:
|
fields = instance.schema.fields()
|
||||||
|
for field in instance.schema.fields():
|
||||||
|
# Dump only needed fields
|
||||||
mustDump = False
|
mustDump = False
|
||||||
elif (self.fieldsToMarshall == 'all') and \
|
if field.getName() in self.fieldsToExclude:
|
||||||
(field.schemata != 'metadata'):
|
mustDump = False
|
||||||
mustDump = True
|
elif (self.fieldsToMarshall == 'all') and \
|
||||||
elif self.fieldsToMarshall == 'all_with_metadata':
|
(field.schemata != 'metadata'):
|
||||||
mustDump = True
|
|
||||||
else:
|
|
||||||
if (type(self.fieldsToMarshall) in self.sequenceTypes) and \
|
|
||||||
(field.getName() in self.fieldsToMarshall):
|
|
||||||
mustDump = True
|
mustDump = True
|
||||||
if mustDump:
|
elif self.fieldsToMarshall == 'all_with_metadata':
|
||||||
fieldType = 'basic'
|
mustDump = True
|
||||||
if field.type in self.atFiles:
|
else:
|
||||||
fieldType = 'file'
|
if (type(self.fieldsToMarshall) in self.sequenceTypes) \
|
||||||
elif field.type == 'reference':
|
and (field.getName() in self.fieldsToMarshall):
|
||||||
fieldType = 'ref'
|
mustDump = True
|
||||||
self.dumpField(res, field.getName(), field.get(instance),
|
if mustDump:
|
||||||
fieldType=fieldType)
|
fieldType = 'basic'
|
||||||
if objectType == 'appy':
|
if field.type in self.atFiles:
|
||||||
# Dump the object history.
|
fieldType = 'file'
|
||||||
res.write('<history type="list">')
|
elif field.type == 'reference':
|
||||||
wfInfo = instance.portal_workflow.getWorkflowsFor(instance)
|
fieldType = 'ref'
|
||||||
if wfInfo:
|
self.dumpField(res, field.getName(),field.get(instance),
|
||||||
history = instance.workflow_history[wfInfo[0].id]
|
fieldType=fieldType)
|
||||||
for event in history:
|
if objectType == 'appy':
|
||||||
res.write('<event type="object">')
|
# Dump the object history.
|
||||||
for k, v in event.iteritems(): self.dumpField(res, k, v)
|
res.write('<history type="list">')
|
||||||
res.write('</event>')
|
wfInfo = instance.portal_workflow.getWorkflowsFor(instance)
|
||||||
res.write('</history>')
|
if wfInfo:
|
||||||
self.marshallSpecificElements(instance, res)
|
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)
|
||||||
|
res.write('</event>')
|
||||||
|
res.write('</history>')
|
||||||
|
self.marshallSpecificElements(instance, res)
|
||||||
|
res.write('</'); res.write(self.rootElementName); res.write('>')
|
||||||
|
else:
|
||||||
|
self.dumpField(res, self.rootElementName, instance)
|
||||||
# Return the result
|
# Return the result
|
||||||
res.write('</'); res.write(self.rootElementName); res.write('>')
|
|
||||||
res = res.getValue()
|
res = res.getValue()
|
||||||
if not self.dumpUnicode:
|
if not self.dumpUnicode:
|
||||||
res = res.encode('utf-8')
|
res = res.encode('utf-8')
|
||||||
|
|
Loading…
Reference in a new issue