from xml.dom import minidom from zope.interface import implements from zope.component import adapts from Products.Archetypes import atapi from Products.Archetypes.interfaces import IBaseObject from Products.ATContentTypes.interface import IATTopicCriterion from Products.Marshall.registry import getComponent from Products.Archetypes import config as atcfg from collective.transmogrifier.interfaces import ITransmogrifier from quintagroup.transmogrifier.interfaces import IExportDataCorrector class ReferenceExporter(object): """ Add reference fields to XML, generated by Marshall product. """ implements(IExportDataCorrector) adapts(IBaseObject, ITransmogrifier) def __init__(self, context, transmogrifier): self.context = context self.transmogrifier = transmogrifier def __call__(self, data): data['data'] = self.exportReferences(data['data']) return data def exportReferences(self, xml): """ Marshall 1.0.0 doesn't export references, do it manually. """ doc = minidom.parseString(xml) root = doc.documentElement for fname in self.context.Schema().keys(): if not isinstance(self.context.Schema()[fname], atapi.ReferenceField): continue values = self.context[fname] if not values: continue elem = doc.createElement("field") attr = doc.createAttribute("name") attr.value = fname elem.setAttributeNode(attr) if type(values) not in (tuple, list): values = [values,] for value in values: ref = doc.createElement('reference') uid = doc.createElement('uid') value = doc.createTextNode(str(value)) uid.appendChild(value) ref.appendChild(uid) elem.appendChild(ref) root.appendChild(elem) return doc.toxml('utf-8') class CriterionExporter(ReferenceExporter): """ Special marshalling adapter for topic criterias. """ implements(IExportDataCorrector) adapts(IATTopicCriterion, ITransmogrifier) def __init__(self, context, transmogrifier): self.context = context self.transmogrifier = transmogrifier self.marshaller = getComponent('atxml') def __call__(self, data): if data['data'] is not None: return super(CriterionExporter, self).__call__(data) # Marshall fails when object has UID that is equal to None # fix it here by setting it to empty string and after marshalling setting back to old value old_uid_attr = getattr(self.context, atcfg.UUID_ATTR) setattr(self.context, atcfg.UUID_ATTR, "") ct, length, xml = self.marshaller.marshall(self.context) xml = self.exportReferences(xml) data['data'] = xml setattr(self.context, atcfg.UUID_ATTR, old_uid_attr) return data