|
@@ -0,0 +1,247 @@
|
|
1
|
+# -*- coding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+## @package EditorialModel.backend.lodel1_backend
|
|
4
|
+# @brief Handle convertion of lodel 1.0 model.xml
|
|
5
|
+#
|
|
6
|
+
|
|
7
|
+import xml.etree.ElementTree as ET
|
|
8
|
+import datetime
|
|
9
|
+import re
|
|
10
|
+from Lodel.utils.mlstring import MlString
|
|
11
|
+from EditorialModel.backend.dummy_backend import EmBackendDummy
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+## Manages a Json file based backend structure
|
|
15
|
+class EmBackendLodel1(EmBackendDummy):
|
|
16
|
+ def __init__(self, xml_file=None, xml_string=None):
|
|
17
|
+ if (not xml_file and not xml_string) or (xml_file and xml_string):
|
|
18
|
+ raise AttributeError
|
|
19
|
+ self._xml_file = xml_file
|
|
20
|
+ self._xml_string = xml_string
|
|
21
|
+ self.lodel2_components = self._components = {'uids': {}, 'EmClass': [], 'EmType': [], 'EmField': [], 'EmFieldGroup': []}
|
|
22
|
+ self._uids = []
|
|
23
|
+ self._fieldgroups_map = {}
|
|
24
|
+
|
|
25
|
+ ## Loads the data from given file or string
|
|
26
|
+ #
|
|
27
|
+ # @return list
|
|
28
|
+ def load(self):
|
|
29
|
+ xml_string = self._load_from_file() if self._xml_file else self._xml_string
|
|
30
|
+
|
|
31
|
+ root_element = ET.fromstring(xml_string)
|
|
32
|
+ self._import_components(root_element)
|
|
33
|
+
|
|
34
|
+ # change uid of EmField and EmFieldGroup DONE
|
|
35
|
+ # take care of fieldgroup_id 0 !!
|
|
36
|
+
|
|
37
|
+ # add relational fields and rel_to_type_id
|
|
38
|
+
|
|
39
|
+ # add superiors_list in types
|
|
40
|
+
|
|
41
|
+ # create dict with all components DONE
|
|
42
|
+
|
|
43
|
+ #print (self.lodel2_components)
|
|
44
|
+ return self.lodel2_components['uids']
|
|
45
|
+
|
|
46
|
+ ## Import the four basic components
|
|
47
|
+ def _import_components(self, root_element):
|
|
48
|
+ # component name and xpath to find them in the xml model
|
|
49
|
+ # the order is very important
|
|
50
|
+ # class and type first, they put their uid in self._uids
|
|
51
|
+ # fieldgroups must change their uid, it will be used by fields later
|
|
52
|
+ to_import = [
|
|
53
|
+ ('EmClass', "./table[@name='#_TP_classes']/datas/row"),
|
|
54
|
+ ('EmType', "./table[@name='##_TP_types']/datas/row"),
|
|
55
|
+ ('EmFieldGroup', "./table[@name='#_TP_tablefieldgroups']/datas/row"),
|
|
56
|
+ ('EmField', "./table[@name='#_TP_tablefields']/datas/row")
|
|
57
|
+ ]
|
|
58
|
+ for comp in to_import:
|
|
59
|
+ component_name, xpath = comp
|
|
60
|
+ #print (component_name, xpath)
|
|
61
|
+ components = root_element.findall(xpath)
|
|
62
|
+ for lodel1_component in components:
|
|
63
|
+ cols = lodel1_component.findall('*')
|
|
64
|
+ fields = self._dom_elements_to_dict(cols)
|
|
65
|
+ #print(fields)
|
|
66
|
+ lodel2_component = self._map_component(component_name, fields)
|
|
67
|
+ lodel2_component['component'] = component_name
|
|
68
|
+ #print(lodel2_component)
|
|
69
|
+ uid = lodel2_component['uid']
|
|
70
|
+ self.lodel2_components[component_name].append(lodel2_component)
|
|
71
|
+ #if component_name in ['EmClass', 'EmType']:
|
|
72
|
+ self._uids.append(uid)
|
|
73
|
+ #del lodel2_component['uid']
|
|
74
|
+ self.lodel2_components['uids'][uid] = lodel2_component
|
|
75
|
+ #print ('————')
|
|
76
|
+
|
|
77
|
+ def _get_uid(self):
|
|
78
|
+ uid = 1
|
|
79
|
+ while True:
|
|
80
|
+ if uid not in self._uids:
|
|
81
|
+ return uid
|
|
82
|
+ uid += 1
|
|
83
|
+
|
|
84
|
+ ## map lodel1 values to lodel2 values
|
|
85
|
+ def _map_component(self, component, fields):
|
|
86
|
+ new_dic = {}
|
|
87
|
+ for mapping in ONE_TO_TWO[component]:
|
|
88
|
+ lodel1_fieldname, lodel2_fieldname = mapping[0:2]
|
|
89
|
+ if len(mapping) == 3:
|
|
90
|
+ cast_function = mapping[2]
|
|
91
|
+ if callable(cast_function):
|
|
92
|
+ value = cast_function(fields[lodel1_fieldname])
|
|
93
|
+ values = {lodel2_fieldname: value}
|
|
94
|
+ else:
|
|
95
|
+ values = getattr(self, cast_function)(lodel2_fieldname, fields[lodel1_fieldname], fields)
|
|
96
|
+ else:
|
|
97
|
+ values = {lodel2_fieldname: fields[lodel1_fieldname]}
|
|
98
|
+ if values:
|
|
99
|
+ for name, value in values.items():
|
|
100
|
+ new_dic[name] = value
|
|
101
|
+ #print (lodel1_fieldname, lodel2_fieldname, value)
|
|
102
|
+ return new_dic
|
|
103
|
+
|
|
104
|
+ ## convert collection of dom element to a dict
|
|
105
|
+ # <col name="id">252</col> => {'id':'252'}
|
|
106
|
+ def _dom_elements_to_dict(self, elements):
|
|
107
|
+ fields = {}
|
|
108
|
+ for element in elements:
|
|
109
|
+ if 'name' in element.attrib:
|
|
110
|
+ fields[element.attrib['name']] = element.text if element.text is not None else ''
|
|
111
|
+ return fields
|
|
112
|
+
|
|
113
|
+ def _load_from_file(self):
|
|
114
|
+ with open(self._xml_file) as content:
|
|
115
|
+ data = content.read()
|
|
116
|
+ return data
|
|
117
|
+
|
|
118
|
+ def save(self, model, filename=None):
|
|
119
|
+ pass
|
|
120
|
+
|
|
121
|
+ # Map methods lodel1 to lodel2
|
|
122
|
+
|
|
123
|
+ ## combine title and altertitle into one MlString
|
|
124
|
+ def title_to_mlstring(self, name, value, fields):
|
|
125
|
+ title = MlString({'fre': value})
|
|
126
|
+ if 'altertitle' in fields:
|
|
127
|
+ langs = re.findall('lang="(..)">([^<]*)', fields['altertitle'])
|
|
128
|
+ for string in langs:
|
|
129
|
+ title.set(string[0], string[1])
|
|
130
|
+ return {name: title}
|
|
131
|
+
|
|
132
|
+ ## set a new unused uid for EmFieldGroup
|
|
133
|
+ # save the oldid to apply to fields
|
|
134
|
+ def new_fieldgroup_id(self, name, value, fields):
|
|
135
|
+ uid = self._get_uid()
|
|
136
|
+ print(value)
|
|
137
|
+ self._fieldgroups_map[int(value)] = uid
|
|
138
|
+ return {name: uid}
|
|
139
|
+
|
|
140
|
+ # give a new unused uid
|
|
141
|
+ def new_uid(self, name, value, fields):
|
|
142
|
+ uid = self._get_uid()
|
|
143
|
+ return {name: uid}
|
|
144
|
+
|
|
145
|
+ # return the new fieldgroup_id given the old one
|
|
146
|
+ def fieldgroup_id(self, name, value, fields):
|
|
147
|
+ old_id = int(value)
|
|
148
|
+ try:
|
|
149
|
+ new_id = self._fieldgroups_map[old_id]
|
|
150
|
+ except KeyError:
|
|
151
|
+ print(old_id, fields)
|
|
152
|
+ return False
|
|
153
|
+ return {name: new_id}
|
|
154
|
+
|
|
155
|
+ def mlstring_cast(self, name, value, fields):
|
|
156
|
+ return {name: MlString({'fre': value})}
|
|
157
|
+
|
|
158
|
+ def to_classid(self, name, value, fields):
|
|
159
|
+ for em_class in self.lodel2_components['EmClass']:
|
|
160
|
+ if em_class['name'] == value:
|
|
161
|
+ return {name: em_class['uid']}
|
|
162
|
+ return False
|
|
163
|
+
|
|
164
|
+ def date_cast(self, name, value, fields):
|
|
165
|
+ date = None
|
|
166
|
+ if len(value):
|
|
167
|
+ try: # 2015-09-14 14:20:28
|
|
168
|
+ date = datetime.datetime.strptime(value, '%Y-%m-%d %H:%M:%S')
|
|
169
|
+ except ValueError:
|
|
170
|
+ pass
|
|
171
|
+ return {name: date}
|
|
172
|
+
|
|
173
|
+ def classtype_cast(self, name, value, fields):
|
|
174
|
+ classtype_map = {'entries': 'entry', 'entities': 'entity', 'persons': 'person'}
|
|
175
|
+ if value in classtype_map:
|
|
176
|
+ return {name: classtype_map[value]}
|
|
177
|
+ return False
|
|
178
|
+
|
|
179
|
+ def map_fieldtypes(self, name, value, fields):
|
|
180
|
+ fieldtypes = {
|
|
181
|
+ 'longtext': 'text',
|
|
182
|
+ 'date': 'datetime',
|
|
183
|
+ 'tinytext': 'text',
|
|
184
|
+ 'lang': 'char',
|
|
185
|
+ 'boolean': 'bool',
|
|
186
|
+ 'email': 'char',
|
|
187
|
+ 'url': 'char',
|
|
188
|
+ 'mltext': 'text',
|
|
189
|
+ 'image': 'text',
|
|
190
|
+ 'number': 'int',
|
|
191
|
+ #'persons': 'rel2type',
|
|
192
|
+ #'entries': 'rel2type',
|
|
193
|
+ #'entities': 'rel2type',
|
|
194
|
+ 'persons': 'text',
|
|
195
|
+ 'entries': 'text',
|
|
196
|
+ 'entities': 'text'
|
|
197
|
+ }
|
|
198
|
+ if value in fieldtypes:
|
|
199
|
+ return {name: fieldtypes[value]}
|
|
200
|
+ return {name: value}
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+ONE_TO_TWO = {
|
|
204
|
+ 'EmClass': [
|
|
205
|
+ ("id", "uid", int),
|
|
206
|
+ ("icon", "icon"),
|
|
207
|
+ ("class", "name"),
|
|
208
|
+ ("title", "string", 'title_to_mlstring'),
|
|
209
|
+ ("classtype", "classtype", 'classtype_cast'),
|
|
210
|
+ ("comment", "help_text", 'mlstring_cast'),
|
|
211
|
+ #("status",""),
|
|
212
|
+ ("rank", "rank", int),
|
|
213
|
+ ("upd", "date_update", 'date_cast')
|
|
214
|
+ ],
|
|
215
|
+ 'EmFieldGroup': [
|
|
216
|
+ ("id", "uid", 'new_fieldgroup_id'),
|
|
217
|
+ ("name", "name"),
|
|
218
|
+ ("class", "class_id", 'to_classid'),
|
|
219
|
+ ("title", "string", 'title_to_mlstring'),
|
|
220
|
+ ("comment", "help_text", 'mlstring_cast'),
|
|
221
|
+ #("status",""),
|
|
222
|
+ ("rank", "rank", int),
|
|
223
|
+ ("upd", "date_update", 'date_cast')
|
|
224
|
+ ],
|
|
225
|
+ 'EmType': [
|
|
226
|
+ ("id", "uid", int),
|
|
227
|
+ ("icon", "icon"),
|
|
228
|
+ ("type", "name"),
|
|
229
|
+ ("title", "string", 'title_to_mlstring'),
|
|
230
|
+ ("class", "class_id", 'to_classid'),
|
|
231
|
+ ("comment", "help_text", 'mlstring_cast'),
|
|
232
|
+ #("status",""),
|
|
233
|
+ ("rank", "rank", int),
|
|
234
|
+ ("upd", "date_update", 'date_cast')
|
|
235
|
+ ],
|
|
236
|
+ 'EmField': [
|
|
237
|
+ ("id", "uid", 'new_uid'),
|
|
238
|
+ ("name", "name"),
|
|
239
|
+ ("idgroup", "fieldgroup_id", 'fieldgroup_id'),
|
|
240
|
+ ("type", "fieldtype", 'map_fieldtypes'),
|
|
241
|
+ ("title", "string", 'title_to_mlstring'),
|
|
242
|
+ ("comment", "help_text", 'mlstring_cast'),
|
|
243
|
+ #("status",""),
|
|
244
|
+ ("rank", "rank", int),
|
|
245
|
+ ("upd", "date_update", 'date_cast')
|
|
246
|
+ ]
|
|
247
|
+}
|