41 time_model = re.compile('([0-9]{2}):([0-9]{2}):([0-9]{2}(?:.[0-9]*)?)') |
41 time_model = re.compile('([0-9]{2}):([0-9]{2}):([0-9]{2}(?:.[0-9]*)?)') |
42 date_model = re.compile('([0-9]{4})-([0-9]{2})-([0-9]{2})') |
42 date_model = re.compile('([0-9]{4})-([0-9]{2})-([0-9]{2})') |
43 datetime_model = re.compile('([0-9]{4})-([0-9]{2})-([0-9]{2})[ T]([0-9]{2}):([0-9]{2}):([0-9]{2}(?:.[0-9]*)?)') |
43 datetime_model = re.compile('([0-9]{4})-([0-9]{2})-([0-9]{2})[ T]([0-9]{2}):([0-9]{2}):([0-9]{2}(?:.[0-9]*)?)') |
44 |
44 |
45 """ |
45 """ |
46 Dictionaries for stocking Classes and Types created from XML |
|
47 """ |
|
48 XMLClasses = {} |
|
49 |
|
50 """ |
|
51 This function calculates the number of whitespace for indentation |
46 This function calculates the number of whitespace for indentation |
52 """ |
47 """ |
53 def getIndent(indent, balise): |
48 def getIndent(indent, balise): |
54 first = indent * 2 |
49 first = indent * 2 |
55 second = first + len(balise) + 1 |
50 second = first + len(balise) + 1 |
56 return "\t".expandtabs(first), "\t".expandtabs(second) |
51 return "\t".expandtabs(first), "\t".expandtabs(second) |
57 |
52 |
58 """ |
|
59 This function opens the xsd file and generate the classes from the xml tree |
|
60 """ |
|
61 def GenerateClassesFromXSD(filename): |
|
62 xsdfile = open(filename, 'r') |
|
63 Generate_xsd_classes(minidom.parse(xsdfile), None) |
|
64 xsdfile.close() |
|
65 |
|
66 """ |
|
67 This function generate the classes from the xsd given as a string |
|
68 """ |
|
69 def GenerateClassesFromXSDstring(xsdstring): |
|
70 Generate_xsd_classes(minidom.parseString(xsdstring), None) |
|
71 |
|
72 """ |
|
73 This function recursively creates a definition of the classes and their attributes |
|
74 for plcopen from the xsd file of plcopen opened in a DOM model |
|
75 """ |
|
76 def Generate_xsd_classes(tree, parent, sequence = False): |
|
77 attributes = {} |
|
78 inheritance = [] |
|
79 if sequence: |
|
80 order = [] |
|
81 # The lists of attributes and inheritance of the node are generated from the childrens |
|
82 for node in tree.childNodes: |
|
83 # We make fun of #text elements and all other tags that don't are xsd tags |
|
84 if node.nodeName != "#text" and node.nodeName.startswith("xsd:"): |
|
85 recursion = False |
|
86 name = node.nodeName[4:].encode() |
|
87 |
|
88 # This tags defines an attribute of the class |
|
89 if name in ["element", "attribute"]: |
|
90 nodename = GetAttributeValue(node._attrs["name"]) |
|
91 if "type" in node._attrs: |
|
92 nodetype = GetAttributeValue(node._attrs["type"]) |
|
93 if nodetype.startswith("xsd"): |
|
94 nodetype = nodetype.replace("xsd", "bse") |
|
95 elif nodetype.startswith("ppx"): |
|
96 nodetype = nodetype.replace("ppx", "cls") |
|
97 else: |
|
98 # The type of attribute is defines in the child tree so we generate a new class |
|
99 # No name is defined so we create one from nodename and parent class name |
|
100 # (because some different nodes can have the same name) |
|
101 if parent: |
|
102 classname = "%s_%s"%(parent, nodename) |
|
103 else: |
|
104 classname = nodename |
|
105 Generate_xsd_classes(node, classname) |
|
106 nodetype = "cls:%s"%classname |
|
107 if name == "attribute": |
|
108 if "use" in node._attrs: |
|
109 use = GetAttributeValue(node._attrs["use"]) |
|
110 else: |
|
111 use = "optional" |
|
112 if name == "element": |
|
113 # If a tag can be written more than one time we define a list attribute |
|
114 if "maxOccurs" in node._attrs and GetAttributeValue(node._attrs["maxOccurs"]) == "unbounded": |
|
115 nodetype = "%s[]"%nodetype |
|
116 if "minOccurs" in node._attrs and GetAttributeValue(node._attrs["minOccurs"]) == "0": |
|
117 use = "optional" |
|
118 else: |
|
119 use = "required" |
|
120 attributes[nodename] = (nodetype, name, use) |
|
121 if sequence: |
|
122 order.append(nodename) |
|
123 |
|
124 # This tag defines a new class |
|
125 elif name == "complexType" or name == "simpleType": |
|
126 if "name" in node._attrs: |
|
127 classname = GetAttributeValue(node._attrs["name"]) |
|
128 super, attrs = Generate_xsd_classes(node, classname) |
|
129 else: |
|
130 classname = parent |
|
131 super, attrs = Generate_xsd_classes(node, classname.split("_")[-1]) |
|
132 # When all attributes and inheritances have been extracted, the |
|
133 # values are added in the list of classes to create |
|
134 if classname not in XMLClasses: |
|
135 XMLClasses[classname] = (super, attrs) |
|
136 elif XMLClasses[classname] != (super, attrs): |
|
137 print "A different class has already got %s for name"%classname |
|
138 |
|
139 # This tag defines an attribute that can have different types |
|
140 elif name == "choice": |
|
141 super, attrs = Generate_xsd_classes(node, parent) |
|
142 if "ref" in attrs.keys(): |
|
143 choices = attrs |
|
144 else: |
|
145 choices = {} |
|
146 for attr, (attr_type, xml_type, write_type) in attrs.items(): |
|
147 choices[attr] = attr_type |
|
148 if "maxOccurs" in node._attrs and GetAttributeValue(node._attrs["maxOccurs"]) == "unbounded": |
|
149 attributes["multichoice_content"] = choices |
|
150 if sequence: |
|
151 order.append("multichoice_content") |
|
152 else: |
|
153 attributes["choice_content"] = choices |
|
154 if sequence: |
|
155 order.append("choice_content") |
|
156 |
|
157 # This tag defines the order in which class attributes must be written |
|
158 # in plcopen xml file. We have to store this order like an attribute |
|
159 elif name in "sequence": |
|
160 super, attrs, order = Generate_xsd_classes(node, parent, True) |
|
161 if "maxOccurs" in node._attrs and GetAttributeValue(node._attrs["maxOccurs"]) == "unbounded": |
|
162 for attr, (attr_type, xml_type, write_type) in attrs.items(): |
|
163 attrs[attr] = ("%s[]"%attr_type, xml_type, write_type) |
|
164 if "minOccurs" in node._attrs and GetAttributeValue(node._attrs["minOccurs"]) == "0": |
|
165 for attr, (attr_type, xml_type, write_type) in attrs.items(): |
|
166 attrs[attr] = (attr_type, xml_type, "optional") |
|
167 inheritance.extend(super) |
|
168 attributes.update(attrs) |
|
169 attributes["order"] = order |
|
170 |
|
171 # This tag defines of types |
|
172 elif name == "group": |
|
173 if "name" in node._attrs: |
|
174 nodename = GetAttributeValue(node._attrs["name"]) |
|
175 super, attrs = Generate_xsd_classes(node, None) |
|
176 XMLClasses[nodename] = (super, {"group":attrs["choice_content"]}) |
|
177 elif "ref" in node._attrs: |
|
178 if "ref" not in attributes: |
|
179 attributes["ref"] = [GetAttributeValue(node._attrs["ref"])] |
|
180 else: |
|
181 attributes["ref"].append(GetAttributeValue(node._attrs["ref"])) |
|
182 |
|
183 # This tag define a base class for the node |
|
184 elif name == "extension": |
|
185 super = GetAttributeValue(node._attrs["base"]) |
|
186 if super.startswith("xsd"): |
|
187 super = super.replace("xsd", "bse") |
|
188 elif super.startswith("ppx"): |
|
189 super = super.replace("ppx", "cls") |
|
190 inheritance.append(super[4:]) |
|
191 recursion = True |
|
192 |
|
193 # This tag defines a restriction on the type of attribute |
|
194 elif name == "restriction": |
|
195 basetype = GetAttributeValue(node._attrs["base"]) |
|
196 if basetype.startswith("xsd"): |
|
197 basetype = basetype.replace("xsd", "bse") |
|
198 elif basetype.startswith("ppx"): |
|
199 basetype = basetype.replace("ppx", "cls") |
|
200 attributes["basetype"] = basetype |
|
201 recursion = True |
|
202 |
|
203 # This tag defines an enumerated type |
|
204 elif name == "enumeration": |
|
205 if "enum" not in attributes: |
|
206 attributes["enum"] = [GetAttributeValue(node._attrs["value"])] |
|
207 else: |
|
208 attributes["enum"].append(GetAttributeValue(node._attrs["value"])) |
|
209 |
|
210 # This tags defines a restriction on a numerical value |
|
211 elif name in ["minInclusive","maxInclusive"]: |
|
212 if "limit" not in attributes: |
|
213 attributes["limit"] = {} |
|
214 if name == "minInclusive": |
|
215 attributes["limit"]["min"] = eval(GetAttributeValue(node._attrs["value"])) |
|
216 elif name == "maxInclusive": |
|
217 attributes["limit"]["max"] = eval(GetAttributeValue(node._attrs["value"])) |
|
218 |
|
219 # This tag are not important but their childrens are. The childrens are then parsed. |
|
220 elif name in ["complexContent", "schema"]: |
|
221 recursion = True |
|
222 |
|
223 # We make fun of xsd documentation |
|
224 elif name in ["annotation"]: |
|
225 pass |
|
226 |
|
227 else: |
|
228 #print name |
|
229 Generate_xsd_classes(node, parent) |
|
230 |
|
231 # Parse the childrens of node |
|
232 if recursion: |
|
233 super, attrs = Generate_xsd_classes(node, parent) |
|
234 inheritance.extend(super) |
|
235 attributes.update(attrs) |
|
236 |
|
237 # if sequence tag have been found, order is returned |
|
238 if sequence: |
|
239 return inheritance, attributes, order |
|
240 else: |
|
241 return inheritance, attributes |
|
242 """ |
53 """ |
243 Function that extracts data from a node |
54 Function that extracts data from a node |
244 """ |
55 """ |
245 def GetAttributeValue(attr): |
56 def GetAttributeValue(attr): |
246 if len(attr.childNodes) == 1: |
57 if len(attr.childNodes) == 1: |
337 else: |
122 else: |
338 print "Can't affect: %s"%type_compute |
123 print "Can't affect: %s"%type_compute |
339 return None |
124 return None |
340 |
125 |
341 """ |
126 """ |
|
127 Class that generate class from an XML Tree |
|
128 """ |
|
129 class ClassFactory: |
|
130 |
|
131 def __init__(self, xsd_tree): |
|
132 self.XML_Tree = xsd_tree |
|
133 |
|
134 # Dictionary for stocking Classes and Types definitions created from the XML tree |
|
135 self.XMLClassDefinitions = {} |
|
136 |
|
137 # Dictionaries for stocking Classes and Types generated |
|
138 self.ComputedClasses = {} |
|
139 self.ComputedTypes = {} |
|
140 self.AlreadyComputed = {} |
|
141 |
|
142 """ |
|
143 This function recursively creates a definition of the classes and their attributes |
|
144 for plcopen from the xsd file of plcopen opened in a DOM model |
|
145 """ |
|
146 def GenerateXSDClasses(self, tree, parent, sequence = False): |
|
147 attributes = {} |
|
148 inheritance = [] |
|
149 if sequence: |
|
150 order = [] |
|
151 # The lists of attributes and inheritance of the node are generated from the childrens |
|
152 for node in tree.childNodes: |
|
153 # We make fun of #text elements and all other tags that don't are xsd tags |
|
154 if node.nodeName != "#text" and node.nodeName.startswith("xsd:"): |
|
155 recursion = False |
|
156 name = node.nodeName[4:].encode() |
|
157 |
|
158 # This tags defines an attribute of the class |
|
159 if name in ["element", "attribute"]: |
|
160 nodename = GetAttributeValue(node._attrs["name"]) |
|
161 if "type" in node._attrs: |
|
162 nodetype = GetAttributeValue(node._attrs["type"]) |
|
163 if nodetype.startswith("xsd"): |
|
164 nodetype = nodetype.replace("xsd", "bse") |
|
165 elif nodetype.startswith("ppx"): |
|
166 nodetype = nodetype.replace("ppx", "cls") |
|
167 else: |
|
168 # The type of attribute is defines in the child tree so we generate a new class |
|
169 # No name is defined so we create one from nodename and parent class name |
|
170 # (because some different nodes can have the same name) |
|
171 if parent: |
|
172 classname = "%s_%s"%(parent, nodename) |
|
173 else: |
|
174 classname = nodename |
|
175 self.GenerateXSDClasses(node, classname) |
|
176 nodetype = "cls:%s"%classname |
|
177 if name == "attribute": |
|
178 if "use" in node._attrs: |
|
179 use = GetAttributeValue(node._attrs["use"]) |
|
180 else: |
|
181 use = "optional" |
|
182 if name == "element": |
|
183 # If a tag can be written more than one time we define a list attribute |
|
184 if "maxOccurs" in node._attrs and GetAttributeValue(node._attrs["maxOccurs"]) == "unbounded": |
|
185 nodetype = "%s[]"%nodetype |
|
186 if "minOccurs" in node._attrs and GetAttributeValue(node._attrs["minOccurs"]) == "0": |
|
187 use = "optional" |
|
188 else: |
|
189 use = "required" |
|
190 attributes[nodename] = (nodetype, name, use) |
|
191 if sequence: |
|
192 order.append(nodename) |
|
193 |
|
194 # This tag defines a new class |
|
195 elif name == "complexType" or name == "simpleType": |
|
196 if "name" in node._attrs: |
|
197 classname = GetAttributeValue(node._attrs["name"]) |
|
198 super, attrs = self.GenerateXSDClasses(node, classname) |
|
199 else: |
|
200 classname = parent |
|
201 super, attrs = self.GenerateXSDClasses(node, classname.split("_")[-1]) |
|
202 # When all attributes and inheritances have been extracted, the |
|
203 # values are added in the list of classes to create |
|
204 if self.XMLClassDefinitions.get(classname, None) == None: |
|
205 self.XMLClassDefinitions[classname] = (super, attrs) |
|
206 elif self.XMLClassDefinitions[classname] != (super, attrs): |
|
207 print "A different class has already got %s for name"%classname |
|
208 |
|
209 # This tag defines an attribute that can have different types |
|
210 elif name == "choice": |
|
211 super, attrs = self.GenerateXSDClasses(node, parent) |
|
212 |
|
213 if "ref" in attrs.keys(): |
|
214 choices = attrs |
|
215 else: |
|
216 choices = {} |
|
217 for attr, (attr_type, xml_type, write_type) in attrs.items(): |
|
218 choices[attr] = attr_type |
|
219 if "maxOccurs" in node._attrs and GetAttributeValue(node._attrs["maxOccurs"]) == "unbounded": |
|
220 attributes["multichoice_content"] = choices |
|
221 if sequence: |
|
222 order.append("multichoice_content") |
|
223 else: |
|
224 attributes["choice_content"] = choices |
|
225 if sequence: |
|
226 order.append("choice_content") |
|
227 |
|
228 # This tag defines the order in which class attributes must be written |
|
229 # in plcopen xml file. We have to store this order like an attribute |
|
230 elif name in "sequence": |
|
231 super, attrs, order = self.GenerateXSDClasses(node, parent, True) |
|
232 if "maxOccurs" in node._attrs and GetAttributeValue(node._attrs["maxOccurs"]) == "unbounded": |
|
233 for attr, (attr_type, xml_type, write_type) in attrs.items(): |
|
234 attrs[attr] = ("%s[]"%attr_type, xml_type, write_type) |
|
235 if "minOccurs" in node._attrs and GetAttributeValue(node._attrs["minOccurs"]) == "0": |
|
236 for attr, (attr_type, xml_type, write_type) in attrs.items(): |
|
237 attrs[attr] = (attr_type, xml_type, "optional") |
|
238 inheritance.extend(super) |
|
239 attributes.update(attrs) |
|
240 attributes["order"] = order |
|
241 |
|
242 # This tag defines of types |
|
243 elif name == "group": |
|
244 if "name" in node._attrs: |
|
245 nodename = GetAttributeValue(node._attrs["name"]) |
|
246 super, attrs = self.GenerateXSDClasses(node, None) |
|
247 self.XMLClassDefinitions[nodename] = (super, {"group":attrs["choice_content"]}) |
|
248 elif "ref" in node._attrs: |
|
249 if "ref" not in attributes: |
|
250 attributes["ref"] = [GetAttributeValue(node._attrs["ref"])] |
|
251 else: |
|
252 attributes["ref"].append(GetAttributeValue(node._attrs["ref"])) |
|
253 |
|
254 # This tag define a base class for the node |
|
255 elif name == "extension": |
|
256 super = GetAttributeValue(node._attrs["base"]) |
|
257 if super.startswith("xsd"): |
|
258 super = super.replace("xsd", "bse") |
|
259 elif super.startswith("ppx"): |
|
260 super = super.replace("ppx", "cls") |
|
261 inheritance.append(super[4:]) |
|
262 recursion = True |
|
263 |
|
264 # This tag defines a restriction on the type of attribute |
|
265 elif name == "restriction": |
|
266 basetype = GetAttributeValue(node._attrs["base"]) |
|
267 if basetype.startswith("xsd"): |
|
268 basetype = basetype.replace("xsd", "bse") |
|
269 elif basetype.startswith("ppx"): |
|
270 basetype = basetype.replace("ppx", "cls") |
|
271 attributes["basetype"] = basetype |
|
272 recursion = True |
|
273 |
|
274 # This tag defines an enumerated type |
|
275 elif name == "enumeration": |
|
276 if "enum" not in attributes: |
|
277 attributes["enum"] = [GetAttributeValue(node._attrs["value"])] |
|
278 else: |
|
279 attributes["enum"].append(GetAttributeValue(node._attrs["value"])) |
|
280 |
|
281 # This tags defines a restriction on a numerical value |
|
282 elif name in ["minInclusive","maxInclusive"]: |
|
283 if "limit" not in attributes: |
|
284 attributes["limit"] = {} |
|
285 if name == "minInclusive": |
|
286 attributes["limit"]["min"] = eval(GetAttributeValue(node._attrs["value"])) |
|
287 elif name == "maxInclusive": |
|
288 attributes["limit"]["max"] = eval(GetAttributeValue(node._attrs["value"])) |
|
289 |
|
290 # This tag are not important but their childrens are. The childrens are then parsed. |
|
291 elif name in ["complexContent", "schema"]: |
|
292 recursion = True |
|
293 |
|
294 # We make fun of xsd documentation |
|
295 elif name in ["annotation"]: |
|
296 pass |
|
297 |
|
298 else: |
|
299 # Unable this line to print XSD element that is not yet supported |
|
300 #print name |
|
301 self.GenerateXSDClasses(node, parent) |
|
302 |
|
303 # Parse the childrens of node |
|
304 if recursion: |
|
305 super, attrs = self.GenerateXSDClasses(node, parent) |
|
306 inheritance.extend(super) |
|
307 attributes.update(attrs) |
|
308 |
|
309 # if sequence tag have been found, order is returned |
|
310 if sequence: |
|
311 return inheritance, attributes, order |
|
312 else: |
|
313 return inheritance, attributes |
|
314 |
|
315 """ |
|
316 Funtion that returns the Python type and default value for a given type |
|
317 """ |
|
318 def GetTypeInitialValue(self, attr_type): |
|
319 type_compute = attr_type[4:].replace("[]", "") |
|
320 if attr_type.startswith("bse:"): |
|
321 if type_compute == "boolean": |
|
322 return BooleanType, "False" |
|
323 elif type_compute in ["decimal","unsignedLong","long","integer"]: |
|
324 return IntType, "0" |
|
325 elif type_compute in ["string","anyURI","NMTOKEN"]: |
|
326 return StringType, "\"\"" |
|
327 elif type_compute == "time": |
|
328 return TimeType, "time(0,0,0,0)" |
|
329 elif type_compute == "date": |
|
330 return DateType, "date(1,1,1)" |
|
331 elif type_compute == "dateTime": |
|
332 return DateTimeType, "datetime(1,1,1,0,0,0,0)" |
|
333 elif type_compute == "language": |
|
334 return StringType, "\"en-US\"" |
|
335 else: |
|
336 print "Can't affect: %s"%type_compute |
|
337 elif attr_type.startswith("cls:"): |
|
338 if self.XMLClassDefinitions.get(type_compute, None) != None: |
|
339 return self.XMLClassDefinitions[type_compute],"%s()"%type_compute |
|
340 |
|
341 """ |
|
342 Methods that generate the classes |
|
343 """ |
|
344 def CreateClasses(self): |
|
345 self.GenerateXSDClasses(self.XML_Tree, None) |
|
346 for classname in self.XMLClassDefinitions.keys(): |
|
347 self.CreateClass(classname) |
|
348 for classname in self.XMLClassDefinitions.keys(): |
|
349 self.MarkUsedClasses(classname) |
|
350 return self.ComputedClasses, self.ComputedTypes |
|
351 |
|
352 def CreateClass(self, classname): |
|
353 # Checks that classe haven't been generated yet |
|
354 if not self.AlreadyComputed.get(classname, False) and classname in self.XMLClassDefinitions: |
|
355 self.AlreadyComputed[classname] = True |
|
356 inheritance, attributes = self.XMLClassDefinitions[classname] |
|
357 #print classname, inheritance, attributes |
|
358 members = {} |
|
359 bases = [] |
|
360 |
|
361 # If inheritance classes haven't been generated |
|
362 for base in inheritance: |
|
363 self.CreateClass(base) |
|
364 bases.append(self.ComputedClasses[base]) |
|
365 |
|
366 # Checks that all attribute types are available |
|
367 for attribute, type_attribute in attributes.items(): |
|
368 if attribute == "group": |
|
369 self.ComputedTypes[classname] = type_attribute |
|
370 elif attribute in ["choice_content","multichoice_content"]: |
|
371 element_types = {} |
|
372 for attr, value in type_attribute.items(): |
|
373 if attr == "ref": |
|
374 for ref in value: |
|
375 self.CreateClass(ref[4:]) |
|
376 element_types.update(self.ComputedTypes[ref[4:]]) |
|
377 else: |
|
378 element_types[attr] = value |
|
379 members[attribute] = element_types |
|
380 else: |
|
381 members[attribute] = type_attribute |
|
382 if attribute == "enum": |
|
383 self.ComputedTypes["%s_enum"%classname] = type_attribute |
|
384 elif attribute not in ["limit", "order"]: |
|
385 if type_attribute[0].startswith("cls:"): |
|
386 type_compute = type_attribute[0][4:].replace("[]","") |
|
387 self.CreateClass(type_compute) |
|
388 if "group" not in attributes: |
|
389 bases = tuple(bases) |
|
390 classmembers = {"IsBaseClass" : True} |
|
391 initialValues = {} |
|
392 for attr, values in members.items(): |
|
393 if attr in ["order", "basetype"]: |
|
394 pass |
|
395 |
|
396 # Class is a enumerated type |
|
397 elif attr == "enum": |
|
398 value_type, initial = self.GetTypeInitialValue(members["basetype"]) |
|
399 initialValues["value"] = "\"%s\""%values[0] |
|
400 classmembers["value"] = values[0] |
|
401 classmembers["setValue"] = generateSetEnumMethod(values, value_type) |
|
402 classmembers["getValue"] = generateGetMethod("value") |
|
403 |
|
404 # Class is a limited type |
|
405 elif attr == "limit": |
|
406 value_type, initial = self.GetTypeInitialValue(members["basetype"]) |
|
407 initial = 0 |
|
408 if "min" in values: |
|
409 initial = max(initial, values["min"]) |
|
410 if "max" in values: |
|
411 initial = min(initial, values["max"]) |
|
412 initialValues["value"] = "%d"%initial |
|
413 classmembers["value"] = initial |
|
414 classmembers["setValue"] = generateSetLimitMethod(values, value_type) |
|
415 classmembers["getValue"] = generateGetMethod("value") |
|
416 |
|
417 # Class has an attribute that can have different value types |
|
418 elif attr == "choice_content": |
|
419 classmembers["content"] = None |
|
420 initialValues["content"] = "None" |
|
421 classmembers["deleteContent"] = generateDeleteMethod("content") |
|
422 classmembers["setContent"] = generateSetChoiceMethod(values) |
|
423 classmembers["getContent"] = generateGetMethod("content") |
|
424 elif attr == "multichoice_content": |
|
425 classmembers["content"] = [] |
|
426 initialValues["content"] = "[]" |
|
427 classmembers["appendContent"] = generateAppendChoiceMethod(values) |
|
428 classmembers["insertContent"] = generateInsertChoiceMethod(values) |
|
429 classmembers["removeContent"] = generateRemoveMethod("content") |
|
430 classmembers["countContent"] = generateCountMethod("content") |
|
431 classmembers["setContent"] = generateSetMethod("content", ListType) |
|
432 classmembers["getContent"] = generateGetMethod("content") |
|
433 |
|
434 # It's an attribute of the class |
|
435 else: |
|
436 attrname = attr[0].upper()+attr[1:] |
|
437 attr_type, xml_type, write_type = values |
|
438 value_type, initial = self.GetTypeInitialValue(attr_type) |
|
439 # Value of the attribute is a list |
|
440 if attr_type.endswith("[]"): |
|
441 classmembers[attr] = [] |
|
442 initialValues[attr] = "[]" |
|
443 classmembers["append"+attrname] = generateAppendMethod(attr, value_type) |
|
444 classmembers["insert"+attrname] = generateInsertMethod(attr, value_type) |
|
445 classmembers["remove"+attrname] = generateRemoveMethod(attr) |
|
446 classmembers["count"+attrname] = generateCountMethod(attr) |
|
447 classmembers["set"+attrname] = generateSetMethod(attr, ListType) |
|
448 else: |
|
449 if write_type == "optional": |
|
450 classmembers[attr] = None |
|
451 initialValues[attr] = "None" |
|
452 classmembers["add"+attrname] = generateAddMethod(attr, initial, self.ComputedClasses) |
|
453 classmembers["delete"+attrname] = generateDeleteMethod(attr) |
|
454 else: |
|
455 classmembers[attr] = initial |
|
456 initialValues[attr] = initial |
|
457 classmembers["set"+attrname] = generateSetMethod(attr, value_type) |
|
458 classmembers["get"+attrname] = generateGetMethod(attr) |
|
459 classmembers["__init__"] = generateInitMethod(bases, initialValues, self.ComputedClasses) |
|
460 classmembers["loadXMLTree"] = generateLoadXMLTree(bases, members, self.ComputedClasses) |
|
461 classmembers["generateXMLText"] = generateGenerateXMLText(bases, members) |
|
462 classmembers["getElementAttributes"] = generategetElementAttributes(bases, members) |
|
463 classmembers["singleLineAttributes"] = True |
|
464 |
|
465 self.ComputedClasses[classname] = classobj(classname, bases, classmembers) |
|
466 |
|
467 def MarkUsedClasses(self, classname): |
|
468 # Checks that classe haven't been generated yet |
|
469 if classname in self.XMLClassDefinitions: |
|
470 inheritance, attributes = self.XMLClassDefinitions[classname] |
|
471 |
|
472 # If inheritance classes haven't been generated |
|
473 for base in inheritance: |
|
474 if base in self.ComputedClasses: |
|
475 self.ComputedClasses[base].IsBaseClass = False |
|
476 |
|
477 # Checks that all attribute types are available |
|
478 for attribute, type_attribute in attributes.items(): |
|
479 if attribute in ["choice_content","multichoice_content"]: |
|
480 element_types = {} |
|
481 for attr, value in type_attribute.items(): |
|
482 if attr == "ref": |
|
483 for ref in value: |
|
484 element_types.update(self.ComputedTypes[ref[4:]]) |
|
485 else: |
|
486 element_types[attr] = value |
|
487 for type_name in element_types.values(): |
|
488 type_compute = type_name[4:].replace("[]","") |
|
489 if type_compute in self.ComputedClasses: |
|
490 self.ComputedClasses[type_compute].IsBaseClass = False |
|
491 elif attribute != "group": |
|
492 if attribute not in ["enum", "limit", "order"]: |
|
493 if type_attribute[0].startswith("cls:"): |
|
494 type_compute = type_attribute[0][4:].replace("[]","") |
|
495 if type_compute in self.ComputedClasses: |
|
496 self.ComputedClasses[type_compute].IsBaseClass = False |
|
497 |
|
498 """ |
|
499 Methods that print the classes generated |
|
500 """ |
|
501 def PrintClasses(self): |
|
502 for classname, xmlclass in self.ComputedClasses.items(): |
|
503 print "%s : %s"%(classname, str(xmlclass)) |
|
504 |
|
505 def PrintClassNames(self): |
|
506 classnames = self.XMLClassDefinitions.keys() |
|
507 classnames.sort() |
|
508 for classname in classnames: |
|
509 print classname |
|
510 |
|
511 """ |
342 Method that generate the method for loading an xml tree by following the |
512 Method that generate the method for loading an xml tree by following the |
343 attributes list defined |
513 attributes list defined |
344 """ |
514 """ |
345 def generateLoadXMLTree(bases, members, user_classes): |
515 def generateLoadXMLTree(bases, members, classes): |
346 def loadXMLTreeMethod(self, tree): |
516 def loadXMLTreeMethod(self, tree): |
347 # If class is derived, values of inheritance classes are loaded |
517 # If class is derived, values of inheritance classes are loaded |
348 for base in bases: |
518 for base in bases: |
349 base.loadXMLTree(self, tree) |
519 base.loadXMLTree(self, tree) |
350 # Class is a enumerated or limited value |
520 # Class is a enumerated or limited value |
656 def countMethod(self): |
825 def countMethod(self): |
657 return len(getattr(self, attr)) |
826 return len(getattr(self, attr)) |
658 return countMethod |
827 return countMethod |
659 |
828 |
660 """ |
829 """ |
661 This is the Metaclass for PLCOpen element classes. It generates automatically |
830 This function generate the classes from a class factory |
662 the basic useful methods for manipulate the differents attributes of the classes |
831 """ |
663 """ |
832 def GenerateClasses(factory, declare = False): |
664 def MetaClass(name, bases, members, user_classes): |
833 ComputedClasses, ComputedTypes = factory.CreateClasses() |
665 classmembers = {} |
834 if declare: |
666 initialValues = {} |
835 for ClassName, Class in pluginClasses.items(): |
667 for attr, values in members.items(): |
836 sys._getframe(1).f_locals[ClassName] = Class |
668 if attr in ["order", "basetype"]: |
837 for TypeName, Type in pluginTypes.items(): |
669 pass |
838 sys._getframe(1).f_locals[TypeName] = Type |
670 |
839 return ComputedClasses, ComputedTypes |
671 # Class is a enumerated type |
840 |
672 elif attr == "enum": |
841 """ |
673 value_type, initial = GetTypeInitialValue(members["basetype"]) |
842 This function opens the xsd file and generate the classes from the xml tree |
674 initialValues["value"] = "\"%s\""%values[0] |
843 """ |
675 classmembers["value"]= values[0] |
844 def GenerateClassesFromXSD(filename, declare = False): |
676 classmembers["setValue"]= generateSetEnumMethod(values, value_type) |
845 xsdfile = open(filename, 'r') |
677 classmembers["getValue"]= generateGetMethod("value") |
846 factory = ClassFactory(minidom.parse(xsdfile)) |
678 |
847 xsdfile.close() |
679 # Class is a limited type |
848 return GenerateClasses(factory, declare) |
680 elif attr == "limit": |
849 |
681 value_type, initial = GetTypeInitialValue(members["basetype"]) |
850 """ |
682 initial = 0 |
851 This function generate the classes from the xsd given as a string |
683 if "min" in values: |
852 """ |
684 initial = max(initial, values["min"]) |
853 def GenerateClassesFromXSDstring(xsdstring, declare = False): |
685 if "max" in values: |
854 factory = ClassFactory(minidom.parseString(xsdstring)) |
686 initial = min(initial, values["max"]) |
855 return GenerateClasses(factory, declare) |
687 initialValues["value"] = "%d"%initial |
856 |
688 classmembers["value"]= initial |
857 |
689 classmembers["setValue"]= generateSetLimitMethod(values, value_type) |
|
690 classmembers["getValue"]= generateGetMethod("value") |
|
691 |
|
692 # Class has an attribute that can have different value types |
|
693 elif attr == "choice_content": |
|
694 classmembers["content"]= None |
|
695 initialValues["content"] = "None" |
|
696 classmembers["deleteContent"]= generateDeleteMethod("content") |
|
697 classmembers["setContent"]= generateSetChoiceMethod(values) |
|
698 classmembers["getContent"]= generateGetMethod("content") |
|
699 elif attr == "multichoice_content": |
|
700 classmembers["content"]= [] |
|
701 initialValues["content"] = "[]" |
|
702 classmembers["appendContent"]= generateAppendChoiceMethod(values) |
|
703 classmembers["insertContent"]= generateInsertChoiceMethod(values) |
|
704 classmembers["removeContent"]= generateRemoveMethod("content") |
|
705 classmembers["countContent"]= generateCountMethod("content") |
|
706 classmembers["setContent"]= generateSetMethod("content", ListType) |
|
707 classmembers["getContent"]= generateGetMethod("content") |
|
708 |
|
709 # It's an attribute of the class |
|
710 else: |
|
711 attrname = attr[0].upper()+attr[1:] |
|
712 attr_type, xml_type, write_type = values |
|
713 value_type, initial = GetTypeInitialValue(attr_type) |
|
714 # Value of the attribute is a list |
|
715 if attr_type.endswith("[]"): |
|
716 classmembers[attr]= [] |
|
717 initialValues[attr] = "[]" |
|
718 classmembers["append"+attrname] = generateAppendMethod(attr, value_type) |
|
719 classmembers["insert"+attrname] = generateInsertMethod(attr, value_type) |
|
720 classmembers["remove"+attrname] = generateRemoveMethod(attr) |
|
721 classmembers["count"+attrname] = generateCountMethod(attr) |
|
722 classmembers["set"+attrname] = generateSetMethod(attr, ListType) |
|
723 else: |
|
724 if write_type == "optional": |
|
725 classmembers[attr] = None |
|
726 initialValues[attr] = "None" |
|
727 classmembers["add"+attrname] = generateAddMethod(attr, initial, user_classes) |
|
728 classmembers["delete"+attrname] = generateDeleteMethod(attr) |
|
729 else: |
|
730 classmembers[attr] = initial |
|
731 initialValues[attr] = initial |
|
732 classmembers["set"+attrname] = generateSetMethod(attr, value_type) |
|
733 classmembers["get"+attrname] = generateGetMethod(attr) |
|
734 classmembers["__init__"]= generateInitMethod(bases, initialValues, user_classes) |
|
735 classmembers["loadXMLTree"]= generateLoadXMLTree(bases, members, user_classes) |
|
736 classmembers["generateXMLText"]= generateGenerateXMLText(bases, members) |
|
737 classmembers["getElementAttributes"]= generategetElementAttributes(bases, members) |
|
738 classmembers["singleLineAttributes"]= True |
|
739 |
|
740 return classobj(name, bases, classmembers) |
|
741 |
|
742 |
|
743 |
|
744 """ |
|
745 Methods that generate the classes |
|
746 """ |
|
747 def CreateClasses(user_classes, user_types): |
|
748 for classname in XMLClasses.keys(): |
|
749 CreateClass(classname, user_classes, user_types) |
|
750 |
|
751 def CreateClass(classname, user_classes, user_types): |
|
752 # Checks that classe haven't been generated yet |
|
753 if classname not in user_classes and classname not in user_types and classname in XMLClasses: |
|
754 inheritance, attributes = XMLClasses[classname] |
|
755 #print classe, inheritance, attributes |
|
756 members = {} |
|
757 bases = [] |
|
758 |
|
759 # If inheritance classes haven't been generated |
|
760 for base in inheritance: |
|
761 if base not in user_classes: |
|
762 CreateClass(base, user_classes, user_types) |
|
763 bases.append(user_classes[base]) |
|
764 |
|
765 # Checks that all attribute types are available |
|
766 for attribute, type_attribute in attributes.items(): |
|
767 if attribute == "group": |
|
768 user_types[classname] = type_attribute |
|
769 elif attribute == "ref": |
|
770 user_types[classname] = {} |
|
771 for attr in type_attribute: |
|
772 if attr[4:] not in user_types: |
|
773 CreateClass(attr[4:], user_classes, user_types) |
|
774 user_types[classname].update(user_types[attr[4:]]) |
|
775 elif attribute in ["choice_content","multichoice_content"]: |
|
776 element_types = {} |
|
777 for attr, value in type_attribute.items(): |
|
778 if attr == "ref": |
|
779 for ref in value: |
|
780 if ref[4:] not in user_types: |
|
781 CreateClass(ref[4:], user_classes, user_types) |
|
782 element_types.update(user_types[ref[4:]]) |
|
783 else: |
|
784 element_types[attr] = value |
|
785 members[attribute] = element_types |
|
786 else: |
|
787 members[attribute] = type_attribute |
|
788 if attribute == "enum": |
|
789 user_types["%s_enum"%classname] = type_attribute |
|
790 elif attribute not in ["limit", "order"]: |
|
791 if type_attribute[0].startswith("ppx:"): |
|
792 type_compute = type_attribute[0][4:].replace("[]","") |
|
793 if type_compute not in user_classes: |
|
794 CreateClass(type_compute, user_classes, user_types) |
|
795 if "group" not in attributes.keys() and "ref" not in attributes.keys(): |
|
796 cls = MetaClass(classname, tuple(bases), members, user_classes) |
|
797 user_classes[classname] = cls |
|
798 |
|
799 """ |
|
800 Methods that print the classes generated |
|
801 """ |
|
802 def PrintClasses(): |
|
803 for classname, xmlclass in XMLClasses.items(): |
|
804 print "%s : %s\n"%(classname, str(xmlclass)) |
|
805 |
|
806 def PrintClassNames(): |
|
807 classnames = XMLClasses.keys() |
|
808 classnames.sort() |
|
809 for classname in classnames: |
|
810 print classname |
|
811 |
|
812 def DeclareXSDClass(XSDstring): |
|
813 pluginClasses = {} |
|
814 pluginTypes = {} |
|
815 GenerateClassesFromXSDstring(XSDstring) |
|
816 CreateClasses(pluginClasses, pluginTypes) |
|
817 |
|
818 for ClassName, Class in pluginClasses.items(): |
|
819 sys._getframe(1).f_locals[ClassName] = Class |
|