source: products/quintagroup.transmogrifier/branches/dictionary/quintagroup/transmogrifier/namespaces/atns.py @ 2719

Last change on this file since 2719 was 2719, checked in by mylan, 14 years ago

Refactoring serializing for dictionary type field

File size: 6.4 KB
Line 
1"""
2    Archetypes Marshall namespace but which can safely handle
3    Control Characters for you
4"""
5
6from Products.Archetypes.interfaces.base import IBaseUnit
7
8from Products.Marshall import config
9from Products.Marshall.handlers.atxml import XmlNamespace
10from Products.Marshall.handlers.atxml import SchemaAttribute
11from Products.Marshall.handlers.atxml import getRegisteredNamespaces
12from Products.Marshall.exceptions import MarshallingException
13from Products.Marshall import utils
14
15from Products.Marshall.namespaces import atns as base
16
17from quintagroup.transmogrifier.namespaces.util import has_ctrlchars
18
19#######################################
20#         Setup logging system        #
21#######################################
22import logging
23DEFAULT_LOG = "/tmp/quintagroup.transmogrifier.log"
24FORMAT = "[%(asctime)s]: %(message)s"
25#FORMAT = "[%H:%M:%S]: %(message)s"
26def createHandler(hndlr_cls, level, *args, **kwargs):
27    hndlr = hndlr_cls(*args, **kwargs)
28    hndlr.setLevel(level)
29    hndlr.setFormatter(logging.Formatter(FORMAT, datefmt="%H:%M:%S"))
30    return hndlr
31
32# Very IMPORTANT create logger as logging.Logger NOT logging.getLogger !!!
33logger = logging.Logger("Quintagroup Transmogrifier", logging.NOTSET)
34logger.addHandler(createHandler(
35        logging.FileHandler, logging.DEBUG, DEFAULT_LOG))
36
37#######################################
38
39_marker = ()
40
41
42class ATAttribute(base.ATAttribute):
43
44    def serialize(self, dom, parent_node, instance, options={}):
45
46        def getPreparedValue(value):
47            if isinstance(value, unicode):
48                value = value.encode('utf-8')
49            elif IBaseUnit.isImplementedBy(value):
50                value = value.getRaw(encoding='utf-8')
51            else:
52                value = str(value)
53            return value
54
55
56        def addNode(node, value, nspref):
57            # Create text node and add *value* to the *node*.
58            # Use *nspref* if needed.
59            if is_ref:
60                if config.HANDLE_REFS:
61                    ref_node = dom.createElementNS(nspref, 'reference')
62                    uid_node = dom.createElementNS(nspref, 'uid')
63                    value = response.createTextNode(value)
64                    uid_node.append(value)
65                    ref_node.append(uid_node)
66                    node.append(ref_node)
67
68            elif isinstance(value, str) and has_ctrlchars(value):
69                value = value.encode('base64')
70                attr = dom.createAttributeNS(nspref, 'transfer_encoding')
71                attr.value = 'base64'
72                node.setAttributeNode(attr)
73                value_node = dom.createCDATASection(value)
74                node.appendChild(value_node)
75            else:
76                value_node = dom.createTextNode(value)
77                node.appendChild(value_node)
78
79        values = self.get(instance)
80        if not values:
81            return
82
83        # if self.name in ['payablesMap', 'fieldMap']:
84        #     import ipdb;ipdb.set_trace()
85
86        is_ref = self.isReference(instance)
87       
88        for value in values:
89            node = dom.createElementNS(self.namespace.xmlns, "field")
90            name_attr = dom.createAttribute("name")
91            name_attr.value = self.name
92            node.setAttributeNode(name_attr)
93           
94            # try to get 'utf-8' encoded string
95            items = getattr(value, 'items', _marker)
96            if items is not _marker and callable(items):
97                # set type attribute for the field
98                type_attr = dom.createAttribute("type")
99                type_attr.value = "dict"
100                node.setAttributeNode(type_attr)
101                for k, v in items():
102                    # create item node with key attribute
103                    good_key = getPreparedValue(k)
104                    item_node = dom.createElementNS(self.namespace.xmlns, "item")
105                    key_attr = dom.createAttribute("key")
106                    key_attr.value = good_key
107                    item_node.setAttributeNode(key_attr)
108                    # prepare value for the item
109                    good_value = getPreparedValue(v)
110                    addNode(item_node, good_value, self.namespace.xmlns)
111                    item_node.normalize()
112                    node.appendChild(item_node)
113            else:
114                value = getPreparedValue(value)
115                addNode(node, value, self.namespace.xmlns)
116       
117            node.normalize()
118            parent_node.appendChild(node)
119
120        return True
121
122    def processXmlValue(self, context, value):
123        if value is None:
124            return
125
126        value = value.strip()
127        if not value:
128            return
129
130        # decode node value if needed
131        te = context.node.get('transfer_encoding', None)
132        if te is not None:
133            value = value.decode(te)
134        # process dictionary type
135        vtype = context.node.attrib.get('type', None)
136        if vtype and vtype=='dict':
137            try:
138                s = value.strip("{}\t\n")
139                # value = dict([map(lambda x:x.strip(" '\""), item.split("': '")) \
140                #              for item in s.split("', '")])
141                value = dict([map(lambda x:x.strip(" '\""), item.split(": ")) \
142                             for item in s.split(", ")])
143            except:
144                #import ipdb;ipdb.set_trace()
145                logger.error("Error on processing '%s' dict type field,\n"\
146                    " for object: '%s'\n  " \
147                    " for the following data: '%s'" % (str(context.instance.id),
148                     context.instance.absolute_url(), str(value)))
149
150
151        data = context.getDataFor(self.namespace.xmlns)
152        if data.has_key(self.name):
153            svalues = data[self.name]
154            if not isinstance(svalues, list):
155                data[self.name] = svalues = [svalues]
156            svalues.append(value)
157            return
158        else:
159            data[self.name] = value
160
161class Archetypes(base.Archetypes):
162
163    def getAttributeByName(self, schema_name, context=None):
164        if context is not None and schema_name not in self.at_fields:
165            if not context.instance.Schema().has_key(schema_name):
166                return
167                raise AssertionError, \
168                      "invalid attribute %s"%(schema_name)
169       
170        if schema_name in self.at_fields:
171            return self.at_fields[schema_name]
172
173        attribute = ATAttribute(schema_name)
174        attribute.setNamespace(self)
175       
176        return attribute
Note: See TracBrowser for help on using the repository browser.