54 return self.__name |
69 return self.__name |
55 |
70 |
56 def dst(self, dt): |
71 def dst(self, dt): |
57 return ZERO |
72 return ZERO |
58 |
73 |
59 XSD_INTEGER_TYPES = ["integer","nonPositiveInteger","negativeInteger","long", |
74 [SYNTAXELEMENT, SYNTAXATTRIBUTE, SIMPLETYPE, COMPLEXTYPE, COMPILEDCOMPLEXTYPE, |
60 "int","short","byte","nonNegativeInteger","unsignedLong","unsignedInt", |
75 ATTRIBUTESGROUP, ELEMENTSGROUP, ATTRIBUTE, ELEMENT, CHOICE, ANY, TAG |
61 "unsignedShort","unsignedByte","positiveInteger"] |
76 ] = range(12) |
62 |
77 |
63 XSD_STRING_TYPES = ["string","normalizedString","token","anyURI","NMTOKEN","language"] |
78 def NotSupportedYet(type): |
|
79 """ |
|
80 Function that generates a function that point out to user that datatype asked |
|
81 are not yet supported by xmlclass |
|
82 @param type: data type |
|
83 @return: function generated |
|
84 """ |
|
85 def GetUnknownValue(attr): |
|
86 raise ValueError, "\"%s\" type isn't supported by \"xmlclass\" yet!"%type |
|
87 return GetUnknownValue |
64 |
88 |
65 """ |
89 """ |
66 This function calculates the number of whitespace for indentation |
90 This function calculates the number of whitespace for indentation |
67 """ |
91 """ |
68 def getIndent(indent, balise): |
92 def getIndent(indent, balise): |
69 first = indent * 2 |
93 first = indent * 2 |
70 second = first + len(balise) + 1 |
94 second = first + len(balise) + 1 |
71 return "\t".expandtabs(first), "\t".expandtabs(second) |
95 return "\t".expandtabs(first), "\t".expandtabs(second) |
72 |
96 |
73 """ |
97 |
74 Function that extracts data from a node |
98 def GetAttributeValue(attr, extract = True): |
75 """ |
99 """ |
76 def GetAttributeValue(attr): |
100 Function that extracts data from a tree node |
|
101 @param attr: tree node containing data to extract |
|
102 @param extract: attr is a tree node or not |
|
103 @return: data extracted as string |
|
104 """ |
|
105 if not extract: |
|
106 return attr |
77 if len(attr.childNodes) == 1: |
107 if len(attr.childNodes) == 1: |
78 return attr.childNodes[0].data.encode() |
108 return attr.childNodes[0].data.encode() |
79 else: |
109 else: |
|
110 # content is a CDATA |
80 text = "" |
111 text = "" |
81 for node in attr.childNodes: |
112 for node in attr.childNodes: |
82 if node.nodeName != "#text": |
113 if node.nodeName != "#text": |
83 text += node.data.encode() |
114 text += node.data.encode() |
84 return text |
115 return text |
85 |
116 |
86 """ |
117 |
87 Function that computes value from a python type (Only Boolean are critical because |
118 def GetNormalizedString(attr, extract = True): |
88 there is no uppercase in plcopen) |
119 """ |
89 """ |
120 Function that normalizes a string according to XML 1.0. Replace tabulations, |
90 def ComputeValue(value): |
121 line feed and carriage return by white space |
91 if type(value) == BooleanType: |
122 @param attr: tree node containing data to extract or data to normalize |
92 if value: |
123 @param extract: attr is a tree node or not |
93 return "true" |
124 @return: data normalized as string |
94 else: |
125 """ |
95 return "false" |
126 if extract: |
|
127 return GetAttributeValue(attr).replace("\n", " ").replace("\t", " ") |
96 else: |
128 else: |
97 return str(value) |
129 return attr.replace("\n", " ").replace("\t", " ") |
98 |
130 |
99 """ |
131 |
100 Function that extracts a value from a string following the xsd type given |
132 def GetToken(attr, extract = True): |
101 """ |
133 """ |
102 def GetComputedValue(attr_type, value): |
134 Function that tokenizes a string according to XML 1.0. Remove any leading and |
103 type_compute = attr_type[4:].replace("[]", "") |
135 trailing white space and replace internal sequence of two or more spaces by |
104 if type_compute == "boolean": |
136 only one white space |
105 if value == "true": |
137 @param attr: tree node containing data to extract or data to tokenize |
106 return True |
138 @param extract: attr is a tree node or not |
107 elif value == "false": |
139 @return: data tokenized as string |
108 return False |
140 """ |
109 else: |
141 return " ".join([part for part in GetNormalizedString(attr, extract).split(" ") if part]) |
110 raise ValueError, "\"%s\" is not a valid boolean!"%value |
142 |
111 elif type_compute in XSD_INTEGER_TYPES: |
143 |
112 return int(value) |
144 def GetHexInteger(attr, extract = True): |
113 elif type_compute in ["decimal", "float", "double"]: |
145 """ |
114 computed_value = float(value) |
146 Function that extracts an hexadecimal integer from a tree node or a string |
115 if computed_value % 1 == 0: |
147 @param attr: tree node containing data to extract or data as a string |
116 return int(computed_value) |
148 @param extract: attr is a tree node or not |
117 return computed_value |
149 @return: data as an integer |
118 elif type_compute in XSD_STRING_TYPES: |
150 """ |
|
151 if extract: |
|
152 value = GetAttributeValue(attr) |
|
153 else: |
|
154 value = attr |
|
155 try: |
|
156 return int(value, 16) |
|
157 except: |
|
158 raise ValueError, "\"%s\" isn't a valid hexadecimal integer!"%value |
|
159 |
|
160 |
|
161 def GenerateIntegerExtraction(minInclusive = None, maxInclusive = None, minExclusive = None, maxExclusive = None): |
|
162 """ |
|
163 Function that generates an extraction function for integer defining min and max |
|
164 of integer value |
|
165 @param minInclusive: inclusive minimum |
|
166 @param maxInclusive: inclusive maximum |
|
167 @param minExclusive: exclusive minimum |
|
168 @param maxExclusive: exclusive maximum |
|
169 @return: function generated |
|
170 """ |
|
171 def GetInteger(attr, extract = True): |
|
172 """ |
|
173 Function that extracts an integer from a tree node or a string |
|
174 @param attr: tree node containing data to extract or data as a string |
|
175 @param extract: attr is a tree node or not |
|
176 @return: data as an integer |
|
177 """ |
|
178 |
|
179 if extract: |
|
180 value = GetAttributeValue(attr) |
|
181 else: |
|
182 value = attr |
|
183 try: |
|
184 # TODO: permit to write value like 1E2 |
|
185 value = int(value) |
|
186 except: |
|
187 raise ValueError, "\"%s\" isn't a valid integer!"%value |
|
188 if minInclusive is not None and value < minInclusive: |
|
189 raise ValueError, "%d isn't greater or equal to %d!"%(value, minInclusive) |
|
190 if maxInclusive is not None and value > maxInclusive: |
|
191 raise ValueError, "%d isn't lesser or equal to %d!"%(value, maxInclusive) |
|
192 if minExclusive is not None and value <= minExclusive: |
|
193 raise ValueError, "%d isn't greater than %d!"%(value, minExclusive) |
|
194 if maxExclusive is not None and value >= maxExclusive: |
|
195 raise ValueError, "%d isn't lesser than %d!"%(value, maxExclusive) |
119 return value |
196 return value |
120 elif type_compute == "time": |
197 return GetInteger |
121 result = time_model.match(value) |
198 |
122 if result: |
199 |
123 values = result.groups() |
200 def GenerateFloatExtraction(type, extra_values = []): |
124 time_values = [int(v) for v in values[:2]] |
201 """ |
125 seconds = float(values[2]) |
202 Function that generates an extraction function for float |
126 time_values.extend([int(seconds), int((seconds % 1) * 1000000)]) |
203 @param type: name of the type of float |
127 return time(*time_values) |
204 @return: function generated |
128 else: |
205 """ |
129 raise ValueError, "\"%s\" is not a valid time!"%value |
206 def GetFloat(attr, extract = True): |
130 elif type_compute == "date": |
207 """ |
131 result = date_model.match(value) |
208 Function that extracts a float from a tree node or a string |
132 if result: |
209 @param attr: tree node containing data to extract or data as a string |
133 values = result.groups() |
210 @param extract: attr is a tree node or not |
134 date_values = [int(v) for v in values[:3]] |
211 @return: data as a float |
135 if values[3] is not None: |
212 """ |
136 tz = xml_timezone() |
213 if extract: |
137 tz.SetOffset(values[3]) |
214 value = GetAttributeValue(attr) |
138 date_values.append(tz) |
215 else: |
139 return date(*date_values) |
216 value = attr |
140 else: |
217 try: |
141 raise ValueError, "\"%s\" is not a valid date!"%value |
218 if value in extra_values: |
142 elif type_compute == "dateTime": |
219 return value |
143 result = datetime_model.match(value) |
220 return float(value) |
144 if result: |
221 except: |
145 values = result.groups() |
222 raise ValueError, "\"%s\" isn't a valid %s!"%(value, type) |
146 datetime_values = [int(v) for v in values[:5]] |
223 return GetFloat |
147 seconds = float(values[5]) |
224 |
148 datetime_values.extend([int(seconds), int((seconds % 1) * 1000000)]) |
225 |
149 if values[6] is not None: |
226 def GetBoolean(attr, extract = True): |
150 tz = xml_timezone() |
227 """ |
151 tz.SetOffset(values[6]) |
228 Function that extracts a boolean from a tree node or a string |
152 datetime_values.append(tz) |
229 @param attr: tree node containing data to extract or data as a string |
153 return datetime(*datetime_values) |
230 @param extract: attr is a tree node or not |
154 else: |
231 @return: data as a boolean |
155 raise ValueError, "\"%s\" is not a valid datetime!"%value |
232 """ |
|
233 if extract: |
|
234 value = GetAttributeValue(attr) |
156 else: |
235 else: |
157 print "Can't affect: %s"%type_compute |
236 value = attr |
|
237 if value == "true" or value == "1": |
|
238 return True |
|
239 elif value == "false" or value == "0": |
|
240 return False |
|
241 else: |
|
242 raise ValueError, "\"%s\" isn't a valid boolean!"%value |
|
243 |
|
244 |
|
245 def GetTime(attr, extract = True): |
|
246 """ |
|
247 Function that extracts a time from a tree node or a string |
|
248 @param attr: tree node containing data to extract or data as a string |
|
249 @param extract: attr is a tree node or not |
|
250 @return: data as a time |
|
251 """ |
|
252 if extract: |
|
253 result = time_model.match(GetAttributeValue(attr)) |
|
254 else: |
|
255 result = time_model.match(attr) |
|
256 if result: |
|
257 values = result.groups() |
|
258 time_values = [int(v) for v in values[:2]] |
|
259 seconds = float(values[2]) |
|
260 time_values.extend([int(seconds), int((seconds % 1) * 1000000)]) |
|
261 return datetime.time(*time_values) |
|
262 else: |
|
263 raise ValueError, "\"%s\" is not a valid time!"%value |
|
264 |
|
265 |
|
266 def GetDate(attr, extract = True): |
|
267 """ |
|
268 Function that extracts a date from a tree node or a string |
|
269 @param attr: tree node containing data to extract or data as a string |
|
270 @param extract: attr is a tree node or not |
|
271 @return: data as a date |
|
272 """ |
|
273 if extract: |
|
274 result = date_model.match(GetAttributeValue(attr)) |
|
275 else: |
|
276 result = date_model.match(attr) |
|
277 if result: |
|
278 values = result.groups() |
|
279 date_values = [int(v) for v in values[:3]] |
|
280 if values[3] is not None: |
|
281 tz = xml_timezone() |
|
282 tz.SetOffset(values[3]) |
|
283 date_values.append(tz) |
|
284 return datetime.date(*date_values) |
|
285 else: |
|
286 raise ValueError, "\"%s\" is not a valid date!"%value |
|
287 |
|
288 |
|
289 def GetDateTime(attr, extract = True): |
|
290 """ |
|
291 Function that extracts date and time from a tree node or a string |
|
292 @param attr: tree node containing data to extract or data as a string |
|
293 @param extract: attr is a tree node or not |
|
294 @return: data as date and time |
|
295 """ |
|
296 if extract: |
|
297 result = datetime_model.match(GetAttributeValue(attr)) |
|
298 else: |
|
299 result = datetime_model.match(attr) |
|
300 if result: |
|
301 values = result.groups() |
|
302 datetime_values = [int(v) for v in values[:5]] |
|
303 seconds = float(values[5]) |
|
304 datetime_values.extend([int(seconds), int((seconds % 1) * 1000000)]) |
|
305 if values[6] is not None: |
|
306 tz = xml_timezone() |
|
307 tz.SetOffset(values[6]) |
|
308 datetime_values.append(tz) |
|
309 return datetime.datetime(*datetime_values) |
|
310 else: |
|
311 raise ValueError, "\"%s\" is not a valid datetime!"%value |
|
312 |
|
313 |
|
314 def GenerateModelNameExtraction(type, model): |
|
315 """ |
|
316 Function that generates an extraction function for string matching a model |
|
317 @param type: name of the data type |
|
318 @param model: model that data must match |
|
319 @return: function generated |
|
320 """ |
|
321 def GetModelName(attr, extract = True): |
|
322 """ |
|
323 Function that extracts a string from a tree node or not and check that |
|
324 string extracted or given match the model |
|
325 @param attr: tree node containing data to extract or data as a string |
|
326 @param extract: attr is a tree node or not |
|
327 @return: data as a string if matching |
|
328 """ |
|
329 if extract: |
|
330 value = GetAttributeValue(attr) |
|
331 else: |
|
332 value = attr |
|
333 result = model.match(value) |
|
334 if not result: |
|
335 raise ValueError, "\"%s\" is not a valid %s!"%(value, type) |
|
336 return value |
|
337 return GetModelName |
|
338 |
|
339 |
|
340 def GenerateLimitExtraction(min = None, max = None, unbounded = True): |
|
341 """ |
|
342 Function that generates an extraction function for integer defining min and max |
|
343 of integer value |
|
344 @param min: minimum limit value |
|
345 @param max: maximum limit value |
|
346 @param unbounded: value can be "unbounded" or not |
|
347 @return: function generated |
|
348 """ |
|
349 def GetLimit(attr, extract = True): |
|
350 """ |
|
351 Function that extracts a string from a tree node or not and check that |
|
352 string extracted or given is in a list of values |
|
353 @param attr: tree node containing data to extract or data as a string |
|
354 @param extract: attr is a tree node or not |
|
355 @return: data as a string |
|
356 """ |
|
357 if extract: |
|
358 value = GetAttributeValue(attr) |
|
359 else: |
|
360 value = attr |
|
361 if value == "unbounded": |
|
362 if unbounded: |
|
363 return value |
|
364 else: |
|
365 raise "\"%s\" isn't a valid value for this member limit!"%value |
|
366 try: |
|
367 limit = int(value) |
|
368 except: |
|
369 raise "\"%s\" isn't a valid value for this member limit!"%value |
|
370 if limit < 0: |
|
371 raise "\"%s\" isn't a valid value for this member limit!"%value |
|
372 elif min is not None and limit < min: |
|
373 raise "\"%s\" isn't a valid value for this member limit!"%value |
|
374 elif max is not None and limit > max: |
|
375 raise "\"%s\" isn't a valid value for this member limit!"%value |
|
376 return limit |
|
377 return GetLimit |
|
378 |
|
379 |
|
380 def GenerateEnumeratedExtraction(type, list): |
|
381 """ |
|
382 Function that generates an extraction function for enumerated values |
|
383 @param type: name of the data type |
|
384 @param list: list of possible values |
|
385 @return: function generated |
|
386 """ |
|
387 def GetEnumerated(attr, extract = True): |
|
388 """ |
|
389 Function that extracts a string from a tree node or not and check that |
|
390 string extracted or given is in a list of values |
|
391 @param attr: tree node containing data to extract or data as a string |
|
392 @param extract: attr is a tree node or not |
|
393 @return: data as a string |
|
394 """ |
|
395 if extract: |
|
396 value = GetAttributeValue(attr) |
|
397 else: |
|
398 value = attr |
|
399 if value in list: |
|
400 return value |
|
401 else: |
|
402 raise ValueError, "\"%s\" isn't a valid value for %s!"%(value, type) |
|
403 return GetEnumerated |
|
404 |
|
405 |
|
406 def GetNamespaces(attr, extract = True): |
|
407 """ |
|
408 Function that extracts a list of namespaces from a tree node or a string |
|
409 @param attr: tree node containing data to extract or data as a string |
|
410 @param extract: attr is a tree node or not |
|
411 @return: list of namespaces |
|
412 """ |
|
413 if extract: |
|
414 value = GetAttributeValue(attr) |
|
415 else: |
|
416 value = attr |
|
417 if value == "": |
|
418 return [] |
|
419 elif value == "##any" or value == "##other": |
|
420 namespaces = [value] |
|
421 else: |
|
422 namespaces = [] |
|
423 for item in value.split(" "): |
|
424 if item == "##targetNamespace" or item == "##local": |
|
425 namespaces.append(item) |
|
426 else: |
|
427 result = URI_model.match(item) |
|
428 if result is not None: |
|
429 namespaces.append(item) |
|
430 else: |
|
431 raise ValueError, "\"%s\" isn't a valid value for namespace!"%value |
|
432 return namespaces |
|
433 |
|
434 |
|
435 def GenerateGetList(type, list): |
|
436 """ |
|
437 Function that generates an extraction function for a list of values |
|
438 @param type: name of the data type |
|
439 @param list: list of possible values |
|
440 @return: function generated |
|
441 """ |
|
442 def GetLists(attr, extract = True): |
|
443 """ |
|
444 Function that extracts a list of values from a tree node or a string |
|
445 @param attr: tree node containing data to extract or data as a string |
|
446 @param extract: attr is a tree node or not |
|
447 @return: list of values |
|
448 """ |
|
449 if extract: |
|
450 value = GetAttributeValue(attr) |
|
451 else: |
|
452 value = attr |
|
453 if value == "": |
|
454 return [] |
|
455 elif value == "#all": |
|
456 return [value] |
|
457 else: |
|
458 values = [] |
|
459 for item in value.split(" "): |
|
460 if item in list: |
|
461 values.append(item) |
|
462 else: |
|
463 raise ValueError, "\"%s\" isn't a valid value for %s!"%(value, type) |
|
464 return values |
|
465 return GetLists |
|
466 |
|
467 |
|
468 def GenerateModelNameListExtraction(type, model): |
|
469 """ |
|
470 Function that generates an extraction function for list of string matching a model |
|
471 @param type: name of the data type |
|
472 @param model: model that list elements must match |
|
473 @return: function generated |
|
474 """ |
|
475 def GetModelNameList(attr, extract = True): |
|
476 """ |
|
477 Function that extracts a list of string from a tree node or not and check |
|
478 that all the items extracted match the model |
|
479 @param attr: tree node containing data to extract or data as a string |
|
480 @param extract: attr is a tree node or not |
|
481 @return: data as a list of string if matching |
|
482 """ |
|
483 if extract: |
|
484 value = GetAttributeValue(attr) |
|
485 else: |
|
486 value = attr |
|
487 values = [] |
|
488 for item in value.split(" "): |
|
489 result = model.match(item) |
|
490 if result is not None: |
|
491 values.append(item) |
|
492 else: |
|
493 raise ValueError, "\"%s\" isn't a valid value for %s!"%(value, type) |
|
494 return values |
|
495 return GetModelNameList |
|
496 |
|
497 def GenerateAnyInfos(): |
|
498 def ExtractAny(tree): |
|
499 return tree.data.encode() |
|
500 |
|
501 def GenerateAny(value, name = None, indent = 0): |
|
502 return "<![CDATA[%s]]>\n"%str(value) |
|
503 |
|
504 return { |
|
505 "type" : COMPLEXTYPE, |
|
506 "extract" : ExtractAny, |
|
507 "generate" : GenerateAny, |
|
508 "initial" : lambda: "", |
|
509 "check" : lambda x: isinstance(x, (StringType, UnicodeType)) |
|
510 } |
|
511 |
|
512 def GenerateTagInfos(name): |
|
513 def ExtractTag(tree): |
|
514 if len(tree._attrs) > 0: |
|
515 raise ValueError, "\"%s\" musn't have attributes!"%name |
|
516 if len(tree.childNodes) > 0: |
|
517 raise ValueError, "\"%s\" musn't have children!"%name |
158 return None |
518 return None |
159 |
519 |
160 def GetInitialValueFunction(value): |
520 def GenerateTag(value, name = None, indent = 0): |
161 def GetInitialValue(): |
521 if name is not None: |
162 return value |
522 ind1, ind2 = getIndent(indent, name) |
163 return GetInitialValue |
523 return ind1 + "<%s/>\n"%name |
164 |
524 else: |
165 """ |
525 return "" |
166 Class that generate class from an XML Tree |
526 |
|
527 return { |
|
528 "type" : TAG, |
|
529 "extract" : ExtractTag, |
|
530 "generate" : GenerateTag, |
|
531 "initial" : lambda: None, |
|
532 "check" : lambda x: x == None |
|
533 } |
|
534 |
|
535 def GenerateContentInfos(factory, choices): |
|
536 def GetContentInitial(): |
|
537 content_name, infos = choices[0] |
|
538 if isinstance(infos["elmt_type"], (UnicodeType, StringType)): |
|
539 namespace, name = DecomposeQualifiedName(infos["elmt_type"]) |
|
540 infos["elmt_type"] = factory.GetQualifiedNameInfos(name, namespace) |
|
541 if infos["maxOccurs"] == "unbounded" or infos["maxOccurs"] > 1: |
|
542 return {"name" : content_name, "value" : map(infos["elmt_type"]["initial"], range(infos["minOccurs"]))} |
|
543 else: |
|
544 return {"name" : content_name, "value" : infos["elmt_type"]["initial"]()} |
|
545 |
|
546 def CheckContent(value): |
|
547 for content_name, infos in choices: |
|
548 if content_name == value["name"]: |
|
549 if isinstance(infos["elmt_type"], (UnicodeType, StringType)): |
|
550 namespace, name = DecomposeQualifiedName(infos["elmt_type"]) |
|
551 infos["elmt_type"] = factory.GetQualifiedNameInfos(name, namespace) |
|
552 if infos["maxOccurs"] == "unbounded" or infos["maxOccurs"] > 1: |
|
553 if isinstance(value["value"], ListType) and infos["minOccurs"] <= len(value["value"]) <= infos["maxOccurs"]: |
|
554 return reduce(lambda x, y: x and y, map(infos["elmt_type"]["check"], value["value"]), True) |
|
555 else: |
|
556 return infos["elmt_type"]["check"](value["value"]) |
|
557 return False |
|
558 |
|
559 def ExtractContent(tree, content): |
|
560 for content_name, infos in choices: |
|
561 if content_name == tree.nodeName: |
|
562 if isinstance(infos["elmt_type"], (UnicodeType, StringType)): |
|
563 namespace, name = DecomposeQualifiedName(infos["elmt_type"]) |
|
564 infos["elmt_type"] = factory.GetQualifiedNameInfos(name, namespace) |
|
565 if infos["maxOccurs"] == "unbounded" or infos["maxOccurs"] > 1: |
|
566 if isinstance(content, ListType) and len(content) > 0 and content[-1]["name"] == content_name: |
|
567 content_item = content.pop(-1) |
|
568 content_item["value"].append(infos["elmt_type"]["extract"](tree)) |
|
569 return content_item |
|
570 elif not isinstance(content, ListType) and content is not None and content["name"] == content_name: |
|
571 return {"name" : content_name, "value" : content["value"] + [infos["elmt_type"]["extract"](tree)]} |
|
572 else: |
|
573 return {"name" : content_name, "value" : [infos["elmt_type"]["extract"](tree)]} |
|
574 else: |
|
575 return {"name" : content_name, "value" : infos["elmt_type"]["extract"](tree)} |
|
576 raise ValueError, "Invalid element \"%s\" for content!"%tree.nodeName |
|
577 |
|
578 def GenerateContent(value, name = None, indent = 0): |
|
579 for content_name, infos in choices: |
|
580 if content_name == value["name"]: |
|
581 if isinstance(infos["elmt_type"], (UnicodeType, StringType)): |
|
582 namespace, name = DecomposeQualifiedName(infos["elmt_type"]) |
|
583 infos["elmt_type"] = factory.GetQualifiedNameInfos(name, namespace) |
|
584 if infos["maxOccurs"] == "unbounded" or infos["maxOccurs"] > 1: |
|
585 text = "" |
|
586 for item in value["value"]: |
|
587 text += infos["elmt_type"]["generate"](item, content_name, indent) |
|
588 return text |
|
589 else: |
|
590 return infos["elmt_type"]["generate"](value["value"], content_name, indent) |
|
591 return "" |
|
592 |
|
593 return { |
|
594 "initial" : GetContentInitial, |
|
595 "check" : CheckContent, |
|
596 "extract" : ExtractContent, |
|
597 "generate" : GenerateContent |
|
598 } |
|
599 |
|
600 #------------------------------------------------------------------------------- |
|
601 # Structure extraction functions |
|
602 #------------------------------------------------------------------------------- |
|
603 |
|
604 |
|
605 def DecomposeQualifiedName(name): |
|
606 result = QName_model.match(name) |
|
607 if not result: |
|
608 raise ValueError, "\"%s\" isn't a valid QName value!"%name |
|
609 parts = result.groups()[0].split(':') |
|
610 if len(parts) == 1: |
|
611 return None, parts[0] |
|
612 return parts |
|
613 |
|
614 def GenerateElement(element_name, attributes, elements_model, accept_text = False): |
|
615 def ExtractElement(factory, node): |
|
616 attrs = factory.ExtractNodeAttrs(element_name, node, attributes) |
|
617 children_structure = "" |
|
618 children_infos = [] |
|
619 children = [] |
|
620 for child in node.childNodes: |
|
621 if child.nodeName not in ["#comment", "#text"]: |
|
622 namespace, childname = DecomposeQualifiedName(child.nodeName) |
|
623 children_structure += "%s "%childname |
|
624 result = elements_model.match(children_structure) |
|
625 if not result: |
|
626 raise ValueError, "Invalid structure for \"%s\" children!. First element invalid."%node.nodeName |
|
627 valid = result.groups()[0] |
|
628 if len(valid) < len(children_structure): |
|
629 raise ValueError, "Invalid structure for \"%s\" children!. Element number %d invalid."%(node.nodeName, len(valid.split(" ")) - 1) |
|
630 for child in node.childNodes: |
|
631 if child.nodeName != "#comment" and (accept_text or child.nodeName != "#text"): |
|
632 if child.nodeName == "#text": |
|
633 children.append(GetAttributeValue(node)) |
|
634 else: |
|
635 namespace, childname = DecomposeQualifiedName(child.nodeName) |
|
636 infos = factory.GetQualifiedNameInfos(childname, namespace) |
|
637 if infos["type"] != SYNTAXELEMENT: |
|
638 raise ValueError, "\"%s\" can't be a member child!"%name |
|
639 if element_name in infos["extract"]: |
|
640 children.append(infos["extract"][element_name](factory, child)) |
|
641 else: |
|
642 children.append(infos["extract"]["default"](factory, child)) |
|
643 return node.nodeName, attrs, children |
|
644 return ExtractElement |
|
645 |
|
646 |
|
647 """ |
|
648 Class that generate class from an XML Tree |
167 """ |
649 """ |
168 class ClassFactory: |
650 class ClassFactory: |
169 |
651 |
170 def __init__(self, xsd_tree): |
652 def __init__(self, document, debug = False): |
171 self.XML_Tree = xsd_tree |
653 self.Document = document |
|
654 self.Debug = debug |
172 |
655 |
173 # Dictionary for stocking Classes and Types definitions created from the XML tree |
656 # Dictionary for stocking Classes and Types definitions created from the XML tree |
174 self.XMLClassDefinitions = {} |
657 self.XMLClassDefinitions = {} |
175 |
658 |
|
659 self.DefinedNamespaces = {} |
|
660 self.Namespaces = {} |
|
661 self.SchemaNamespace = None |
|
662 self.TargetNamespace = None |
|
663 |
|
664 self.CurrentCompilations = [] |
|
665 |
176 # Dictionaries for stocking Classes and Types generated |
666 # Dictionaries for stocking Classes and Types generated |
|
667 self.ComputeAfter = [] |
177 self.ComputedClasses = {} |
668 self.ComputedClasses = {} |
178 self.ComputedTypes = {} |
|
179 self.AlreadyComputed = {} |
669 self.AlreadyComputed = {} |
180 |
670 |
181 """ |
671 def GetQualifiedNameInfos(self, name, namespace = None, canbenone = False): |
182 This function recursively creates a definition of the classes and their attributes |
672 if namespace is None: |
183 for plcopen from the xsd file of plcopen opened in a DOM model |
673 if name in self.Namespaces[self.SchemaNamespace]: |
184 """ |
674 return self.Namespaces[self.SchemaNamespace][name] |
185 def GenerateXSDClasses(self, tree, parent, sequence = False): |
675 for space, elements in self.Namespaces.items(): |
186 attributes = {} |
676 if space != self.SchemaNamespace and name in elements: |
187 inheritance = [] |
677 return elements[name] |
188 if sequence: |
678 parts = name.split("_", 1) |
189 order = [] |
679 if len(parts) > 1: |
190 # The lists of attributes and inheritance of the node are generated from the childrens |
680 group = self.GetQualifiedNameInfos(parts[0], namespace) |
191 for node in tree.childNodes: |
681 if group is not None and group["type"] == ELEMENTSGROUP: |
192 # We make fun of #text elements and all other tags that don't are xsd tags |
682 elements = [] |
193 if node.nodeName != "#text" and node.nodeName.startswith("xsd:"): |
683 if "elements" in group: |
194 recursion = False |
684 elements = group["elements"] |
195 name = node.nodeName[4:].encode() |
685 elif "choices" in group: |
196 |
686 elements = group["choices"] |
197 # This tags defines an attribute of the class |
687 for element in elements: |
198 if name in ["element", "attribute"]: |
688 if element["name"] == parts[1]: |
199 nodename = GetAttributeValue(node._attrs["name"]) |
689 return element |
200 default = None |
690 if not canbenone: |
201 if "type" in node._attrs: |
691 raise ValueError, "Unknown element \"%s\" for any defined namespaces!"%name |
202 nodetype = GetAttributeValue(node._attrs["type"]) |
692 elif namespace in self.Namespaces: |
203 if nodetype.startswith("xsd"): |
693 if name in self.Namespaces[namespace]: |
204 nodetype = nodetype.replace("xsd", "bse") |
694 return self.Namespaces[namespace][name] |
205 elif nodetype.startswith("ppx"): |
695 parts = name.split("_", 1) |
206 nodetype = nodetype.replace("ppx", "cls") |
696 if len(parts) > 1: |
|
697 group = self.GetQualifiedNameInfos(parts[0], namespace) |
|
698 if group is not None and group["type"] == ELEMENTSGROUP: |
|
699 elements = [] |
|
700 if "elements" in group: |
|
701 elements = group["elements"] |
|
702 elif "choices" in group: |
|
703 elements = group["choices"] |
|
704 for element in elements: |
|
705 if element["name"] == parts[1]: |
|
706 return element |
|
707 if not canbenone: |
|
708 raise ValueError, "Unknown element \"%s\" for namespace \"%s\"!"%(name, namespace) |
|
709 elif not canbenone: |
|
710 raise ValueError, "Unknown namespace \"%s\"!"%namespace |
|
711 return None |
|
712 |
|
713 def SplitQualifiedName(self, name, namespace = None, canbenone = False): |
|
714 if namespace is None: |
|
715 if name in self.Namespaces[self.SchemaNamespace]: |
|
716 return name, None |
|
717 for space, elements in self.Namespaces.items(): |
|
718 if space != self.SchemaNamespace and name in elements: |
|
719 return name, None |
|
720 parts = name.split("_", 1) |
|
721 if len(parts) > 1: |
|
722 group = self.GetQualifiedNameInfos(parts[0], namespace) |
|
723 if group is not None and group["type"] == ELEMENTSGROUP: |
|
724 elements = [] |
|
725 if "elements" in group: |
|
726 elements = group["elements"] |
|
727 elif "choices" in group: |
|
728 elements = group["choices"] |
|
729 for element in elements: |
|
730 if element["name"] == parts[1]: |
|
731 return part[1], part[0] |
|
732 if not canbenone: |
|
733 raise ValueError, "Unknown element \"%s\" for any defined namespaces!"%name |
|
734 elif namespace in self.Namespaces: |
|
735 if name in self.Namespaces[namespace]: |
|
736 return name, None |
|
737 parts = name.split("_", 1) |
|
738 if len(parts) > 1: |
|
739 group = self.GetQualifiedNameInfos(parts[0], namespace) |
|
740 if group is not None and group["type"] == ELEMENTSGROUP: |
|
741 elements = [] |
|
742 if "elements" in group: |
|
743 elements = group["elements"] |
|
744 elif "choices" in group: |
|
745 elements = group["choices"] |
|
746 for element in elements: |
|
747 if element["name"] == parts[1]: |
|
748 return parts[1], parts[0] |
|
749 if not canbenone: |
|
750 raise ValueError, "Unknown element \"%s\" for namespace \"%s\"!"%(name, namespace) |
|
751 elif not canbenone: |
|
752 raise ValueError, "Unknown namespace \"%s\"!"%namespace |
|
753 return None, None |
|
754 |
|
755 def ExtractNodeAttrs(self, element_name, node, valid_attrs): |
|
756 attrs = {} |
|
757 for qualified_name, attr in node._attrs.items(): |
|
758 namespace, name = DecomposeQualifiedName(qualified_name) |
|
759 if name in valid_attrs: |
|
760 infos = self.GetQualifiedNameInfos(name, namespace) |
|
761 if infos["type"] != SYNTAXATTRIBUTE: |
|
762 raise ValueError, "\"%s\" can't be a member attribute!"%name |
|
763 elif name in attrs: |
|
764 raise ValueError, "\"%s\" attribute has been twice!"%name |
|
765 elif element_name in infos["extract"]: |
|
766 attrs[name] = infos["extract"][element_name](attr) |
|
767 else: |
|
768 attrs[name] = infos["extract"]["default"](attr) |
|
769 elif namespace == "xmlns": |
|
770 infos = self.GetQualifiedNameInfos("anyURI", self.SchemaNamespace) |
|
771 self.DefinedNamespaces[infos["extract"](attr)] = name |
|
772 else: |
|
773 raise ValueError, "Invalid attribute \"%s\" for member \"%s\"!"%(qualified_name, node.nodeName) |
|
774 for attr in valid_attrs: |
|
775 if attr not in attrs and attr in self.Namespaces[self.SchemaNamespace] and "default" in self.Namespaces[self.SchemaNamespace][attr]: |
|
776 if element_name in self.Namespaces[self.SchemaNamespace][attr]["default"]: |
|
777 default = self.Namespaces[self.SchemaNamespace][attr]["default"][element_name] |
|
778 else: |
|
779 default = self.Namespaces[self.SchemaNamespace][attr]["default"]["default"] |
|
780 if default is not None: |
|
781 attrs[attr] = default |
|
782 return attrs |
|
783 |
|
784 def ReduceElements(self, elements, schema=False): |
|
785 result = [] |
|
786 for child_infos in elements: |
|
787 if "name" in child_infos[1] and schema: |
|
788 self.CurrentCompilations.append(child_infos[1]["name"]) |
|
789 namespace, name = DecomposeQualifiedName(child_infos[0]) |
|
790 infos = self.GetQualifiedNameInfos(name, namespace) |
|
791 if infos["type"] != SYNTAXELEMENT: |
|
792 raise ValueError, "\"%s\" can't be a member child!"%name |
|
793 result.append(infos["reduce"](self, child_infos[1], child_infos[2])) |
|
794 if "name" in child_infos[1] and schema: |
|
795 self.CurrentCompilations.pop(-1) |
|
796 annotations = [] |
|
797 children = [] |
|
798 for element in result: |
|
799 if element["type"] == "annotation": |
|
800 annotations.append(element) |
|
801 else: |
|
802 children.append(element) |
|
803 return annotations, children |
|
804 |
|
805 def AddComplexType(self, typename, infos): |
|
806 if typename not in self.XMLClassDefinitions: |
|
807 self.XMLClassDefinitions[typename] = infos |
|
808 else: |
|
809 raise ValueError, "\"%s\" class already defined. Choose another name!"%typename |
|
810 |
|
811 def ParseSchema(self): |
|
812 pass |
|
813 |
|
814 def ExtractTypeInfos(self, name, parent, typeinfos): |
|
815 if isinstance(typeinfos, (StringType, UnicodeType)): |
|
816 namespace, name = DecomposeQualifiedName(typeinfos) |
|
817 infos = self.GetQualifiedNameInfos(name, namespace) |
|
818 if infos["type"] == COMPLEXTYPE: |
|
819 name, parent = self.SplitQualifiedName(name, namespace) |
|
820 result = self.CreateClass(name, parent, infos) |
|
821 if result is not None and not isinstance(result, (UnicodeType, StringType)): |
|
822 self.Namespaces[self.TargetNamespace][result["name"]] = result |
|
823 return result |
|
824 elif infos["type"] == ELEMENT and infos["elmt_type"]["type"] == COMPLEXTYPE: |
|
825 name, parent = self.SplitQualifiedName(name, namespace) |
|
826 result = self.CreateClass(name, parent, infos["elmt_type"]) |
|
827 if result is not None and not isinstance(result, (UnicodeType, StringType)): |
|
828 self.Namespaces[self.TargetNamespace][result["name"]] = result |
|
829 return result |
|
830 else: |
|
831 return infos |
|
832 elif typeinfos["type"] == COMPLEXTYPE: |
|
833 return self.CreateClass(name, parent, typeinfos) |
|
834 elif typeinfos["type"] == SIMPLETYPE: |
|
835 return typeinfos |
|
836 |
|
837 """ |
|
838 Methods that generates the classes |
|
839 """ |
|
840 def CreateClasses(self): |
|
841 self.ParseSchema() |
|
842 for name, infos in self.Namespaces[self.TargetNamespace].items(): |
|
843 if infos["type"] == ELEMENT: |
|
844 if not isinstance(infos["elmt_type"], (UnicodeType, StringType)) and infos["elmt_type"]["type"] == COMPLEXTYPE: |
|
845 self.ComputeAfter.append((name, None, infos["elmt_type"], True)) |
|
846 while len(self.ComputeAfter) > 0: |
|
847 result = self.CreateClass(*self.ComputeAfter.pop(0)) |
|
848 if result is not None and not isinstance(result, (UnicodeType, StringType)): |
|
849 self.Namespaces[self.TargetNamespace][result["name"]] = result |
|
850 elif infos["type"] == COMPLEXTYPE: |
|
851 self.ComputeAfter.append((name, None, infos)) |
|
852 while len(self.ComputeAfter) > 0: |
|
853 result = self.CreateClass(*self.ComputeAfter.pop(0)) |
|
854 if result is not None and not isinstance(result, (UnicodeType, StringType)): |
|
855 self.Namespaces[self.TargetNamespace][result["name"]] = result |
|
856 elif infos["type"] == ELEMENTSGROUP: |
|
857 elements = [] |
|
858 if "elements" in infos: |
|
859 elements = infos["elements"] |
|
860 elif "choices" in infos: |
|
861 elements = infos["choices"] |
|
862 for element in elements: |
|
863 if not isinstance(element["elmt_type"], (UnicodeType, StringType)) and element["elmt_type"]["type"] == COMPLEXTYPE: |
|
864 self.ComputeAfter.append((element["name"], infos["name"], element["elmt_type"])) |
|
865 while len(self.ComputeAfter) > 0: |
|
866 result = self.CreateClass(*self.ComputeAfter.pop(0)) |
|
867 if result is not None and not isinstance(result, (UnicodeType, StringType)): |
|
868 self.Namespaces[self.TargetNamespace][result["name"]] = result |
|
869 return self.ComputedClasses |
|
870 |
|
871 def CreateClass(self, name, parent, classinfos, baseclass = False): |
|
872 if parent is not None: |
|
873 classname = "%s_%s"%(parent, name) |
|
874 else: |
|
875 classname = name |
|
876 |
|
877 # Checks that classe haven't been generated yet |
|
878 if self.AlreadyComputed.get(classname, False): |
|
879 if baseclass: |
|
880 self.AlreadyComputed[classname].IsBaseClass = baseclass |
|
881 return None |
|
882 |
|
883 # If base classes haven't been generated |
|
884 bases = [] |
|
885 if "base" in classinfos: |
|
886 result = self.ExtractTypeInfos("base", name, classinfos["base"]) |
|
887 if result is None: |
|
888 namespace, base_name = DecomposeQualifiedName(classinfos["base"]) |
|
889 if self.AlreadyComputed.get(base_name, False): |
|
890 self.ComputeAfter.append((name, parent, classinfos)) |
|
891 if self.TargetNamespace is not None: |
|
892 return "%s:%s"%(self.TargetNamespace, classname) |
207 else: |
893 else: |
208 # The type of attribute is defines in the child tree so we generate a new class |
894 return classname |
209 # No name is defined so we create one from nodename and parent class name |
895 elif result is not None: |
210 # (because some different nodes can have the same name) |
896 classinfos["base"] = self.ComputedClasses[result["name"]] |
211 if parent: |
897 bases.append(self.ComputedClasses[result["name"]]) |
212 classname = "%s_%s"%(parent, nodename) |
898 bases.append(object) |
213 else: |
899 bases = tuple(bases) |
214 classname = nodename |
900 classmembers = {"__doc__" : classinfos.get("doc", ""), "IsBaseClass" : baseclass} |
215 if len(node.childNodes) > 0: |
901 |
216 self.GenerateXSDClasses(node, classname) |
902 self.AlreadyComputed[classname] = True |
217 nodetype = "cls:%s"%classname |
903 |
218 else: |
904 for attribute in classinfos["attributes"]: |
219 nodetype = classname |
905 infos = self.ExtractTypeInfos(attribute["name"], name, attribute["attr_type"]) |
220 if name == "attribute": |
906 if infos is not None: |
221 if "use" in node._attrs: |
907 if infos["type"] != SIMPLETYPE: |
222 use = GetAttributeValue(node._attrs["use"]) |
908 raise ValueError, "\"%s\" type is not a simple type!"%attribute["attr_type"] |
223 else: |
909 attrname = attribute["name"] |
224 use = "optional" |
910 if attribute["use"] == "optional": |
225 if "default" in node._attrs: |
911 classmembers[attrname] = None |
226 default = GetAttributeValue(node._attrs["default"]) |
912 classmembers["add%s"%attrname] = generateAddMethod(attrname, self, attribute) |
227 elif name == "element": |
913 classmembers["delete%s"%attrname] = generateDeleteMethod(attrname) |
228 # If a tag can be written more than one time we define a list attribute |
914 else: |
229 if "maxOccurs" in node._attrs and GetAttributeValue(node._attrs["maxOccurs"]) == "unbounded": |
915 classmembers[attrname] = infos["initial"]() |
230 nodetype = "%s[]"%nodetype |
916 classmembers["set%s"%attrname] = generateSetMethod(attrname) |
231 if "minOccurs" in node._attrs and GetAttributeValue(node._attrs["minOccurs"]) == "0": |
917 classmembers["get%s"%attrname] = generateGetMethod(attrname) |
232 use = "optional" |
918 else: |
233 else: |
919 raise ValueError, "\"%s\" type unrecognized!"%attribute["attr_type"] |
234 use = "required" |
920 attribute["attr_type"] = infos |
235 attributes[nodename] = (nodetype, name, use, default) |
921 |
236 if sequence: |
922 for element in classinfos["elements"]: |
237 order.append(nodename) |
923 if element["type"] == CHOICE: |
238 |
924 elmtname = element["name"] |
239 # This tag defines a new class |
925 choices = [] |
240 elif name == "complexType" or name == "simpleType": |
926 for choice in element["choices"]: |
241 if "name" in node._attrs: |
927 if choice["elmt_type"] == "tag": |
242 classname = GetAttributeValue(node._attrs["name"]) |
928 choice["elmt_type"] = GenerateTagInfos(choice["name"]) |
243 super, attrs = self.GenerateXSDClasses(node, classname) |
|
244 else: |
929 else: |
245 classname = parent |
930 infos = self.ExtractTypeInfos(choice["name"], name, choice["elmt_type"]) |
246 super, attrs = self.GenerateXSDClasses(node, classname.split("_")[-1]) |
931 if infos is not None: |
247 # When all attributes and inheritances have been extracted, the |
932 choice["elmt_type"] = infos |
248 # values are added in the list of classes to create |
933 choices.append((choice["name"], choice)) |
249 if self.XMLClassDefinitions.get(classname, None) == None: |
934 classmembers["get%schoices"%elmtname] = generateGetChoicesMethod(element["choices"]) |
250 self.XMLClassDefinitions[classname] = (super, attrs) |
935 classmembers["add%sbytype"%elmtname] = generateAddChoiceByTypeMethod(element["choices"]) |
251 elif self.XMLClassDefinitions[classname] != (super, attrs): |
936 infos = GenerateContentInfos(self, choices) |
252 print "A different class has already got %s for name"%classname |
937 elif element["type"] == ANY: |
253 |
938 elmtname = element["name"] = "text" |
254 # This tag defines an attribute that can have different types |
939 element["minOccurs"] = element["maxOccurs"] = 1 |
255 elif name == "choice": |
940 infos = GenerateAnyInfos() |
256 super, attrs = self.GenerateXSDClasses(node, parent) |
941 else: |
257 |
942 elmtname = element["name"] |
258 choices = {} |
943 infos = self.ExtractTypeInfos(element["name"], name, element["elmt_type"]) |
259 for attr, values in attrs.items(): |
944 if infos is not None: |
260 if attr == "ref": |
945 element["elmt_type"] = infos |
261 choices[attr] = values |
946 if element["maxOccurs"] == "unbounded" or element["maxOccurs"] > 1: |
262 else: |
947 classmembers[elmtname] = [] |
263 choices[attr] = values[0] |
948 classmembers["append%s"%elmtname] = generateAppendMethod(elmtname, element["maxOccurs"], self, element) |
264 if "maxOccurs" in node._attrs and GetAttributeValue(node._attrs["maxOccurs"]) == "unbounded": |
949 classmembers["insert%s"%elmtname] = generateInsertMethod(elmtname, element["maxOccurs"], self, element) |
265 attributes["multichoice_content"] = choices |
950 classmembers["remove%s"%elmtname] = generateRemoveMethod(elmtname, element["minOccurs"]) |
266 if sequence: |
951 classmembers["count%s"%elmtname] = generateCountMethod(elmtname) |
267 order.append("multichoice_content") |
952 else: |
268 else: |
953 if element["minOccurs"] == 0: |
269 attributes["choice_content"] = choices |
954 classmembers[elmtname] = None |
270 if sequence: |
955 classmembers["add%s"%elmtname] = generateAddMethod(elmtname, self, element) |
271 order.append("choice_content") |
956 classmembers["delete%s"%elmtname] = generateDeleteMethod(elmtname) |
272 |
957 elif not isinstance(element["elmt_type"], (UnicodeType, StringType)): |
273 # This tag defines the order in which class attributes must be written |
958 classmembers[elmtname] = element["elmt_type"]["initial"]() |
274 # in plcopen xml file. We have to store this order like an attribute |
959 else: |
275 elif name in "sequence": |
960 classmembers[elmtname] = None |
276 super, attrs, order = self.GenerateXSDClasses(node, parent, True) |
961 classmembers["set%s"%elmtname] = generateSetMethod(elmtname) |
277 if "maxOccurs" in node._attrs and GetAttributeValue(node._attrs["maxOccurs"]) == "unbounded": |
962 classmembers["get%s"%elmtname] = generateGetMethod(elmtname) |
278 for attr, (attr_type, xml_type, write_type, default) in attrs.items(): |
|
279 attrs[attr] = ("%s[]"%attr_type, xml_type, write_type, default) |
|
280 if "minOccurs" in node._attrs and GetAttributeValue(node._attrs["minOccurs"]) == "0": |
|
281 for attr, (attr_type, xml_type, write_type, default) in attrs.items(): |
|
282 attrs[attr] = (attr_type, xml_type, "optional", default) |
|
283 inheritance.extend(super) |
|
284 attributes.update(attrs) |
|
285 attributes["order"] = order |
|
286 |
|
287 # This tag defines of types |
|
288 elif name == "group": |
|
289 if "name" in node._attrs: |
|
290 nodename = GetAttributeValue(node._attrs["name"]) |
|
291 super, attrs = self.GenerateXSDClasses(node, None) |
|
292 self.XMLClassDefinitions[nodename] = (super, {"group":attrs["choice_content"]}) |
|
293 elif "ref" in node._attrs: |
|
294 if "ref" not in attributes: |
|
295 attributes["ref"] = [GetAttributeValue(node._attrs["ref"])] |
|
296 else: |
|
297 attributes["ref"].append(GetAttributeValue(node._attrs["ref"])) |
|
298 |
|
299 # This tag define a base class for the node |
|
300 elif name == "extension": |
|
301 super = GetAttributeValue(node._attrs["base"]) |
|
302 if super.startswith("xsd"): |
|
303 super = super.replace("xsd", "bse") |
|
304 elif super.startswith("ppx"): |
|
305 super = super.replace("ppx", "cls") |
|
306 inheritance.append(super[4:]) |
|
307 recursion = True |
|
308 |
|
309 # This tag defines a restriction on the type of attribute |
|
310 elif name == "restriction": |
|
311 basetype = GetAttributeValue(node._attrs["base"]) |
|
312 if basetype.startswith("xsd"): |
|
313 basetype = basetype.replace("xsd", "bse") |
|
314 elif basetype.startswith("ppx"): |
|
315 basetype = basetype.replace("ppx", "cls") |
|
316 attributes["basetype"] = basetype |
|
317 recursion = True |
|
318 |
|
319 # This tag defines an enumerated type |
|
320 elif name == "enumeration": |
|
321 if "enum" not in attributes: |
|
322 attributes["enum"] = [GetAttributeValue(node._attrs["value"])] |
|
323 else: |
|
324 attributes["enum"].append(GetAttributeValue(node._attrs["value"])) |
|
325 |
|
326 # This tags defines a restriction on a numerical value |
|
327 elif name in ["minInclusive","maxInclusive"]: |
|
328 if "limit" not in attributes: |
|
329 attributes["limit"] = {} |
|
330 if name == "minInclusive": |
|
331 attributes["limit"]["min"] = eval(GetAttributeValue(node._attrs["value"])) |
|
332 elif name == "maxInclusive": |
|
333 attributes["limit"]["max"] = eval(GetAttributeValue(node._attrs["value"])) |
|
334 |
|
335 # This tag are not important but their childrens are. The childrens are then parsed. |
|
336 elif name in ["complexContent", "schema"]: |
|
337 recursion = True |
|
338 |
|
339 # We make fun of xsd documentation |
|
340 elif name in ["annotation"]: |
|
341 pass |
|
342 |
|
343 else: |
|
344 # Unable this line to print XSD element that is not yet supported |
|
345 #print name |
|
346 self.GenerateXSDClasses(node, parent) |
|
347 |
|
348 # Parse the childrens of node |
|
349 if recursion: |
|
350 super, attrs = self.GenerateXSDClasses(node, parent) |
|
351 inheritance.extend(super) |
|
352 attributes.update(attrs) |
|
353 |
|
354 # if sequence tag have been found, order is returned |
|
355 if sequence: |
|
356 return inheritance, attributes, order |
|
357 else: |
|
358 return inheritance, attributes |
|
359 |
|
360 """ |
|
361 Funtion that returns the Python type and default value for a given type |
|
362 """ |
|
363 def GetTypeInitialValue(self, attr_type, default = None): |
|
364 type_compute = attr_type[4:].replace("[]", "") |
|
365 if attr_type.startswith("bse:"): |
|
366 if type_compute == "boolean": |
|
367 if default: |
|
368 def GetBooleanInitialValue(): |
|
369 return default == "true" |
|
370 return BooleanType, GetBooleanInitialValue |
|
371 else: |
|
372 return BooleanType, lambda:False |
|
373 elif type_compute in ["unsignedLong","long","integer"]: |
|
374 if default: |
|
375 def GetIntegerInitialValue(): |
|
376 return int(default) |
|
377 return IntType, GetIntegerInitialValue |
|
378 else: |
|
379 return IntType, lambda:0 |
|
380 elif type_compute == "decimal": |
|
381 if default: |
|
382 def GetFloatInitialValue(): |
|
383 return float(default) |
|
384 return FloatType, GetFloatInitialValue |
|
385 else: |
|
386 return FloatType, lambda:0. |
|
387 elif type_compute in ["string","anyURI","NMTOKEN"]: |
|
388 if default: |
|
389 def GetStringInitialValue(): |
|
390 return default |
|
391 return StringType, GetStringInitialValue |
|
392 else: |
|
393 return StringType, lambda:"" |
|
394 elif type_compute == "time": |
|
395 if default: |
|
396 def GetTimeInitialValue(): |
|
397 result = time_model.match(value) |
|
398 if result: |
|
399 values = result.groups() |
|
400 time_values = [int(v) for v in values[:2]] |
|
401 seconds = float(values[2]) |
|
402 time_values.extend([int(seconds), int((seconds % 1) * 1000000)]) |
|
403 return time(*time_values) |
|
404 return time(0,0,0,0) |
|
405 return time, GetTimeInitialValue |
|
406 else: |
|
407 return time, lambda:time(0,0,0,0) |
|
408 elif type_compute == "date": |
|
409 if default: |
|
410 def GetDateInitialValue(): |
|
411 result = date_model.match(value) |
|
412 if result: |
|
413 date_values = [int(v) for v in result.groups()] |
|
414 return date(*date_values) |
|
415 return date(1,1,1) |
|
416 return date, GetDateInitialValue |
|
417 else: |
|
418 return date, lambda:date(1,1,1) |
|
419 elif type_compute == "dateTime": |
|
420 if default: |
|
421 def GetDateTimeInitialValue(): |
|
422 result = datetime_model.match(value) |
|
423 if result: |
|
424 values = result.groups() |
|
425 datetime_values = [int(v) for v in values[:5]] |
|
426 seconds = float(values[5]) |
|
427 datetime_values.extend([int(seconds), int((seconds % 1) * 1000000)]) |
|
428 return datetime(*datetime_values) |
|
429 return datetime(1,1,1,0,0,0,0) |
|
430 return datetime, GetDateTimeInitialValue |
|
431 else: |
|
432 return datetime, lambda:datetime(1,1,1,0,0,0,0) |
|
433 elif type_compute == "language": |
|
434 if default: |
|
435 def GetStringInitialValue(): |
|
436 return default |
|
437 return StringType, GetStringInitialValue |
|
438 else: |
|
439 return StringType, lambda:"en-US" |
|
440 else: |
|
441 print "Can't affect: %s"%type_compute |
|
442 elif attr_type.startswith("cls:"): |
|
443 if self.XMLClassDefinitions.get(type_compute, None) != None: |
|
444 def GetClassInitialValue(): |
|
445 if self.XMLClassDefinitions.get(type_compute, None) != None: |
|
446 obj = self.ComputedClasses[type_compute]() |
|
447 if default: |
|
448 obj.setValue(default) |
|
449 return obj |
|
450 return None |
|
451 return self.XMLClassDefinitions[type_compute], GetClassInitialValue |
|
452 return None, lambda:None |
|
453 |
|
454 """ |
|
455 Funtion that returns the Python type and default value for a given type |
|
456 """ |
|
457 def GetInitialValues(self, value_types): |
|
458 initial_values = {} |
|
459 for name, value_type in value_types.items(): |
|
460 result = self.GetTypeInitialValue(value_type) |
|
461 if result: |
|
462 initial_values[name] = result[1] |
|
463 return initial_values |
|
464 |
|
465 """ |
|
466 Methods that generate the classes |
|
467 """ |
|
468 def CreateClasses(self): |
|
469 self.GenerateXSDClasses(self.XML_Tree, None) |
|
470 for classname in self.XMLClassDefinitions.keys(): |
|
471 self.CreateClass(classname) |
|
472 for classname in self.XMLClassDefinitions.keys(): |
|
473 self.MarkUsedClasses(classname) |
|
474 return self.ComputedClasses, self.ComputedTypes |
|
475 |
|
476 def CreateClass(self, classname): |
|
477 # Checks that classe haven't been generated yet |
|
478 if not self.AlreadyComputed.get(classname, False) and classname in self.XMLClassDefinitions: |
|
479 self.AlreadyComputed[classname] = True |
|
480 inheritance, attributes = self.XMLClassDefinitions[classname] |
|
481 #print classname, inheritance, attributes |
|
482 members = {} |
|
483 bases = [] |
|
484 |
963 |
485 # If inheritance classes haven't been generated |
964 classmembers["__init__"] = generateInitMethod(self, classinfos) |
486 for base in inheritance: |
965 classmembers["__setattr__"] = generateSetattrMethod(self, classinfos) |
487 self.CreateClass(base) |
966 classmembers["getStructure"] = generateStructureMethod(classinfos) |
488 bases.append(self.ComputedClasses[base]) |
967 classmembers["loadXMLTree"] = generateLoadXMLTree(self, classinfos) |
489 |
968 classmembers["generateXMLText"] = generateGenerateXMLText(self, classinfos) |
490 # Checks that all attribute types are available |
969 classmembers["getElementAttributes"] = generateGetElementAttributes(self, classinfos) |
491 for attribute, type_attribute in attributes.items(): |
970 classmembers["getElementInfos"] = generateGetElementInfos(self, classinfos) |
492 if attribute == "group": |
971 classmembers["setElementValue"] = generateSetElementValue(self, classinfos) |
493 self.ComputedTypes[classname] = type_attribute |
972 classmembers["singleLineAttributes"] = True |
494 elif attribute in ["choice_content","multichoice_content"]: |
973 |
495 element_types = {} |
974 class_definition = classobj(str(classname), bases, classmembers) |
496 for attr, value in type_attribute.items(): |
975 |
497 if attr == "ref": |
976 self.ComputedClasses[classname] = class_definition |
498 for ref in value: |
977 |
499 self.CreateClass(ref[4:]) |
978 return {"type" : COMPILEDCOMPLEXTYPE, |
500 element_types.update(self.ComputedTypes[ref[4:]]) |
979 "name" : classname, |
501 else: |
980 "check" : generateClassCheckFunction(class_definition), |
502 element_types[attr] = value |
981 "initial" : generateClassCreateFunction(class_definition), |
503 members[attribute] = element_types |
982 "extract" : generateClassExtractFunction(class_definition), |
504 else: |
983 "generate" : class_definition.generateXMLText} |
505 members[attribute] = type_attribute |
|
506 if attribute == "enum": |
|
507 self.ComputedTypes["%s_enum"%classname] = type_attribute |
|
508 elif attribute not in ["limit", "order"]: |
|
509 if type_attribute[0].startswith("cls:"): |
|
510 type_compute = type_attribute[0][4:].replace("[]","") |
|
511 self.CreateClass(type_compute) |
|
512 if "group" not in attributes: |
|
513 bases = tuple(bases) |
|
514 classmembers = {"IsBaseClass" : True} |
|
515 initialValues = {} |
|
516 for attr, values in members.items(): |
|
517 if attr in ["order", "basetype"]: |
|
518 pass |
|
519 |
|
520 # Class is a enumerated type |
|
521 elif attr == "enum": |
|
522 value_type, initial = self.GetTypeInitialValue(members["basetype"]) |
|
523 initialValues["value"] = GetInitialValueFunction(values[0]) |
|
524 classmembers["value"] = values[0] |
|
525 classmembers["setValue"] = generateSetEnumMethod(values, value_type) |
|
526 classmembers["getValue"] = generateGetMethod("value") |
|
527 classmembers["getValidValues"] = generateGetChoicesMethod(values) |
|
528 |
|
529 # Class is a limited type |
|
530 elif attr == "limit": |
|
531 value_type, initial = self.GetTypeInitialValue(members["basetype"]) |
|
532 if "min" in values: |
|
533 initial = max(initial, values["min"]) |
|
534 elif "max" in values: |
|
535 initial = min(initial, values["max"]) |
|
536 initialValues["value"] = GetInitialValueFunction(initial) |
|
537 classmembers["value"] = initial |
|
538 classmembers["setValue"] = generateSetLimitMethod(values, value_type) |
|
539 classmembers["getValue"] = generateGetMethod("value") |
|
540 |
|
541 # Class has an attribute that can have different value types |
|
542 elif attr == "choice_content": |
|
543 classmembers["content"] = None |
|
544 initialValues["content"] = lambda:None |
|
545 classmembers["deleteContent"] = generateDeleteMethod("content") |
|
546 classmembers["addContent"] = generateAddChoiceMethod(values, self.GetInitialValues(values)) |
|
547 classmembers["setContent"] = generateSetChoiceMethod(values) |
|
548 classmembers["getContent"] = generateGetMethod("content") |
|
549 classmembers["getChoices"] = generateGetChoicesMethod(values) |
|
550 elif attr == "multichoice_content": |
|
551 classmembers["content"] = [] |
|
552 initialValues["content"] = lambda:[] |
|
553 classmembers["appendContent"] = generateAppendChoiceMethod(values) |
|
554 classmembers["appendContentByType"] = generateAppendChoiceByTypeMethod(values, self.GetInitialValues(values)) |
|
555 classmembers["insertContent"] = generateInsertChoiceMethod(values) |
|
556 classmembers["removeContent"] = generateRemoveMethod("content") |
|
557 classmembers["countContent"] = generateCountMethod("content") |
|
558 classmembers["setContent"] = generateSetMethod("content", ListType) |
|
559 classmembers["getContent"] = generateGetMethod("content") |
|
560 classmembers["getChoices"] = generateGetChoicesMethod(values) |
|
561 |
|
562 # It's an attribute of the class |
|
563 else: |
|
564 attrname = attr[0].upper()+attr[1:] |
|
565 attr_type, xml_type, write_type, default = values |
|
566 value_type, initial = self.GetTypeInitialValue(attr_type, default) |
|
567 # Value of the attribute is a list |
|
568 if attr_type.endswith("[]"): |
|
569 classmembers[attr] = [] |
|
570 initialValues[attr] = lambda:[] |
|
571 classmembers["append"+attrname] = generateAppendMethod(attr, value_type) |
|
572 classmembers["insert"+attrname] = generateInsertMethod(attr, value_type) |
|
573 classmembers["remove"+attrname] = generateRemoveMethod(attr) |
|
574 classmembers["count"+attrname] = generateCountMethod(attr) |
|
575 classmembers["set"+attrname] = generateSetMethod(attr, ListType) |
|
576 else: |
|
577 if write_type == "optional": |
|
578 classmembers[attr] = None |
|
579 initialValues[attr] = lambda:None |
|
580 classmembers["add"+attrname] = generateAddMethod(attr, initial) |
|
581 classmembers["delete"+attrname] = generateDeleteMethod(attr) |
|
582 else: |
|
583 classmembers[attr] = initial() |
|
584 initialValues[attr] = initial |
|
585 classmembers["set"+attrname] = generateSetMethod(attr, value_type) |
|
586 classmembers["get"+attrname] = generateGetMethod(attr) |
|
587 classmembers["__init__"] = generateInitMethod(bases, initialValues) |
|
588 classmembers["loadXMLTree"] = generateLoadXMLTree(bases, members, self.ComputedClasses) |
|
589 classmembers["generateXMLText"] = generateGenerateXMLText(bases, members) |
|
590 classmembers["getElementAttributes"] = generateGetElementAttributes(members, self.ComputedClasses) |
|
591 classmembers["getElementInfos"] = generateGetElementInfos(members, self.ComputedClasses) |
|
592 classmembers["setElementValue"] = generateSetElementValue(members) |
|
593 classmembers["singleLineAttributes"] = True |
|
594 |
|
595 self.ComputedClasses[classname] = classobj(classname, bases, classmembers) |
|
596 |
984 |
597 def MarkUsedClasses(self, classname): |
985 def MarkUsedClasses(self, classname): |
598 # Checks that classe haven't been generated yet |
986 # Checks that classe haven't been generated yet |
599 if classname in self.XMLClassDefinitions: |
987 if classname in self.XMLClassDefinitions: |
600 inheritance, attributes = self.XMLClassDefinitions[classname] |
988 inheritance, attributes = self.XMLClassDefinitions[classname] |
627 |
1015 |
628 """ |
1016 """ |
629 Methods that print the classes generated |
1017 Methods that print the classes generated |
630 """ |
1018 """ |
631 def PrintClasses(self): |
1019 def PrintClasses(self): |
632 for classname, xmlclass in self.ComputedClasses.items(): |
1020 items = self.ComputedClasses.items() |
|
1021 items.sort() |
|
1022 for classname, xmlclass in items: |
633 print "%s : %s"%(classname, str(xmlclass)) |
1023 print "%s : %s"%(classname, str(xmlclass)) |
634 |
1024 |
635 def PrintClassNames(self): |
1025 def PrintClassNames(self): |
636 classnames = self.XMLClassDefinitions.keys() |
1026 classnames = self.XMLClassDefinitions.keys() |
637 classnames.sort() |
1027 classnames.sort() |
638 for classname in classnames: |
1028 for classname in classnames: |
639 print classname |
1029 print classname |
640 |
1030 |
641 """ |
1031 """ |
|
1032 Method that generate the method for checking a class instance |
|
1033 """ |
|
1034 def generateClassCheckFunction(class_definition): |
|
1035 def classCheckfunction(instance): |
|
1036 return isinstance(instance, class_definition) |
|
1037 return classCheckfunction |
|
1038 |
|
1039 """ |
|
1040 Method that generate the method for creating a class instance |
|
1041 """ |
|
1042 def generateClassCreateFunction(class_definition): |
|
1043 def classCreatefunction(): |
|
1044 return class_definition() |
|
1045 return classCreatefunction |
|
1046 |
|
1047 """ |
|
1048 Method that generate the method for extracting a class instance |
|
1049 """ |
|
1050 def generateClassExtractFunction(class_definition): |
|
1051 def classExtractfunction(node): |
|
1052 instance = class_definition() |
|
1053 instance.loadXMLTree(node) |
|
1054 return instance |
|
1055 return classExtractfunction |
|
1056 |
|
1057 """ |
642 Method that generate the method for loading an xml tree by following the |
1058 Method that generate the method for loading an xml tree by following the |
643 attributes list defined |
1059 attributes list defined |
644 """ |
1060 """ |
645 def generateLoadXMLTree(bases, members, classes): |
1061 def generateSetattrMethod(factory, classinfos): |
646 def loadXMLTreeMethod(self, tree): |
1062 attributes = dict([(attr["name"], attr) for attr in classinfos["attributes"] if attr["use"] != "prohibited"]) |
647 # If class is derived, values of inheritance classes are loaded |
1063 optional_attributes = [attr["name"] for attr in classinfos["attributes"] if attr["use"] == "optional"] |
648 for base in bases: |
1064 elements = dict([(element["name"], element) for element in classinfos["elements"]]) |
649 base.loadXMLTree(self, tree) |
1065 |
650 # Class is a enumerated or limited value |
1066 def setattrMethod(self, name, value): |
651 if "enum" in members.keys() or "limit" in members.keys(): |
1067 if name in attributes: |
652 attr_value = GetAttributeValue(tree) |
1068 if isinstance(attributes[name]["attr_type"], (UnicodeType, StringType)): |
653 attr_type = members["basetype"] |
1069 namespace, name = DecomposeQualifiedName(infos) |
654 val = GetComputedValue(attr_type, attr_value) |
1070 attributes[name]["attr_type"] = factory.GetQualifiedNameInfos(name, namespace) |
655 self.setValue(val) |
1071 if value is None: |
656 else: |
1072 if name in optional_attributes: |
657 |
1073 return object.__setattr__(self, name, None) |
658 # Load the node attributes if they are defined in the list |
1074 else: |
659 for attrname, attr in tree._attrs.items(): |
1075 raise ValueError, "Attribute '%s' isn't optional."%name |
660 if attrname in members.keys(): |
1076 elif "fixed" in attributes[name] and value != attributes[name]["fixed"]: |
661 attr_type, xml_type, write_type, default = members[attrname] |
1077 raise ValueError, "Value of attribute '%s' can only be '%s'."%(name, str(attributes[name]["fixed"])) |
662 attr_value = GetAttributeValue(attr) |
1078 elif attributes[name]["attr_type"]["check"](value): |
663 if write_type != "optional" or attr_value != "": |
1079 return object.__setattr__(self, name, value) |
664 # Extracts the value |
1080 else: |
665 if attr_type.startswith("bse:"): |
1081 raise ValueError, "Invalid value for attribute '%s'."%(name) |
666 val = GetComputedValue(attr_type, attr_value) |
1082 elif name in elements: |
667 elif attr_type.startswith("cls:"): |
1083 if isinstance(elements[name]["elmt_type"], (UnicodeType, StringType)): |
668 val = classes[attr_type[4:]]() |
1084 namespace, name = DecomposeQualifiedName(infos) |
669 val.loadXMLTree(attr) |
1085 elements[name]["elmt_type"] = factory.GetQualifiedNameInfos(name, namespace) |
670 setattr(self, attrname, val) |
1086 if value is None: |
671 |
1087 if elements[name]["minOccurs"] == 0 and elements[name]["maxOccurs"] == 1: |
672 # Load the node childs if they are defined in the list |
1088 return object.__setattr__(self, name, None) |
|
1089 else: |
|
1090 raise ValueError, "Attribute '%s' isn't optional."%name |
|
1091 elif elements[name]["maxOccurs"] == "unbounded" or elements[name]["maxOccurs"] > 1: |
|
1092 if isinstance(value, ListType) and elements[name]["minOccurs"] <= len(value) <= elements[name]["maxOccurs"]: |
|
1093 if reduce(lambda x, y: x and y, map(elements[name]["elmt_type"]["check"], value), True): |
|
1094 return object.__setattr__(self, name, value) |
|
1095 raise ValueError, "Attribute '%s' must be a list of valid elements."%name |
|
1096 elif "fixed" in elements[name] and value != elements[name]["fixed"]: |
|
1097 raise ValueError, "Value of attribute '%s' can only be '%s'."%(name, str(elements[name]["fixed"])) |
|
1098 elif elements[name]["elmt_type"]["check"](value): |
|
1099 return object.__setattr__(self, name, value) |
|
1100 else: |
|
1101 raise ValueError, "Invalid value for attribute '%s'."%(name) |
|
1102 elif "base" in classinfos: |
|
1103 return classinfos["base"].__setattr__(self, name, value) |
|
1104 else: |
|
1105 raise AttributeError, "'%s' can't have an attribute '%s'."%(classinfos["name"], name) |
|
1106 |
|
1107 return setattrMethod |
|
1108 |
|
1109 """ |
|
1110 Method that generate the method for generating the xml tree structure model by |
|
1111 following the attributes list defined |
|
1112 """ |
|
1113 def ComputeMultiplicity(name, infos): |
|
1114 if infos["minOccurs"] == 0: |
|
1115 if infos["maxOccurs"] == "unbounded": |
|
1116 return "(?:%s)*"%name |
|
1117 elif infos["maxOccurs"] == 1: |
|
1118 return "(?:%s)?"%name |
|
1119 else: |
|
1120 return "(?:%s){0, %d}"%(name, infos["maxOccurs"]) |
|
1121 elif infos["minOccurs"] == 1: |
|
1122 if infos["maxOccurs"] == "unbounded": |
|
1123 return "(?:%s)+"%name |
|
1124 elif infos["maxOccurs"] == 1: |
|
1125 return name |
|
1126 else: |
|
1127 return "(?:%s){1, %d}"%(name, infos["maxOccurs"]) |
|
1128 else: |
|
1129 if infos["maxOccurs"] == "unbounded": |
|
1130 return "(?:%s){%d}(?:%s )*"%(name, infos["minOccurs"], name) |
|
1131 else: |
|
1132 return "(?:%s){%d, %d}"%(name, infos["minOccurs"], infos["maxOccurs"]) |
|
1133 |
|
1134 def generateStructureMethod(classinfos): |
|
1135 elements = [] |
|
1136 for element in classinfos["elements"]: |
|
1137 if element["type"] == ANY: |
|
1138 elements.append(ComputeMultiplicity("(?:#cdata-section )?", element)) |
|
1139 elif element["type"] == CHOICE: |
|
1140 elements.append(ComputeMultiplicity( |
|
1141 "|".join([ComputeMultiplicity("%s "%infos["name"], infos) for infos in element["choices"]]), |
|
1142 element)) |
|
1143 else: |
|
1144 elements.append(ComputeMultiplicity("%s "%element["name"], element)) |
|
1145 if classinfos.get("order") or len(elements) == 0: |
|
1146 structure = "".join(elements) |
|
1147 else: |
|
1148 raise ValueError, "XSD structure not yet supported!" |
|
1149 |
|
1150 def getStructureMethod(self): |
|
1151 if "base" in classinfos: |
|
1152 return classinfos["base"].getStructure(self) + structure |
|
1153 return structure |
|
1154 return getStructureMethod |
|
1155 |
|
1156 """ |
|
1157 Method that generate the method for loading an xml tree by following the |
|
1158 attributes list defined |
|
1159 """ |
|
1160 def generateLoadXMLTree(factory, classinfos): |
|
1161 attributes = dict([(attr["name"], attr) for attr in classinfos["attributes"] if attr["use"] != "prohibited"]) |
|
1162 elements = dict([(element["name"], element) for element in classinfos["elements"]]) |
|
1163 |
|
1164 def loadXMLTreeMethod(self, tree, extras = [], derived = False): |
|
1165 if not derived: |
|
1166 children_structure = "" |
673 for node in tree.childNodes: |
1167 for node in tree.childNodes: |
674 if node.nodeType == node.COMMENT_NODE: |
1168 if node.nodeName not in ["#comment", "#text"]: |
675 continue |
1169 children_structure += "%s "%node.nodeName |
676 name = node.nodeName |
1170 structure_model = re.compile("(%s)$"%self.getStructure()) |
677 # We make fun of #text elements |
1171 result = structure_model.match(children_structure) |
678 if name != "#text": |
1172 if not result: |
679 |
1173 raise ValueError, "Invalid structure for \"%s\" children!."%tree.nodeName |
680 # Class has an attribute that can have different value types |
1174 required_attributes = [attr["name"] for attr in classinfos["attributes"] if attr["use"] == "required"] |
681 if "choice_content" in members.keys() and name in members["choice_content"].keys(): |
1175 if "base" in classinfos: |
682 attr_type = members["choice_content"][name] |
1176 extras.extend([attr["name"] for attr in classinfos["attributes"] if attr["use"] != "prohibited"]) |
683 # Extracts the value |
1177 classinfos["base"].loadXMLTree(self, tree, extras, True) |
684 if attr_type.startswith("bse:"): |
1178 for attrname, attr in tree._attrs.items(): |
685 val = GetComputedValue(attr_type.replace("[]",""), GetAttributeValue(node)) |
1179 if attrname in attributes: |
686 elif attr_type.startswith("cls:"): |
1180 if isinstance(attributes[attrname]["attr_type"], (UnicodeType, StringType)): |
687 val = classes[attr_type[4:].replace("[]","")]() |
1181 namespace, name = DecomposeQualifiedName(infos) |
688 val.loadXMLTree(node) |
1182 attributes[attrname]["attr_type"] = factory.GetQualifiedNameInfos(name, namespace) |
689 else: |
1183 setattr(self, attrname, attributes[attrname]["attr_type"]["extract"](attr)) |
690 val = None |
1184 elif "base" not in classinfos and attrname not in extras: |
691 # Stock value in content attribute |
1185 raise ValueError, "Invalid attribute \"%s\" for \"%s\" element!"%(attrname, tree.nodeName) |
692 if val is not None: |
1186 if attrname in required_attributes: |
693 if attr_type.endswith("[]"): |
1187 required_attributes.remove(attrname) |
694 if self.content: |
1188 if len(required_attributes) > 0: |
695 self.content["value"].append(val) |
1189 raise ValueError, "Required attributes %s missing for \"%s\" element!"%(", ".join(["\"%s\""%name for name in required_attributes]), tree.nodeName) |
696 else: |
1190 first = {} |
697 self.content = {"name":name,"value":[val]} |
1191 for node in tree.childNodes: |
698 else: |
1192 name = node.nodeName |
699 self.content = {"name":name,"value":val} |
1193 if name in ["#text", "#comment"]: |
700 else: |
1194 continue |
701 self.content = {"name":name,"value":None} |
1195 if name in elements: |
702 |
1196 if isinstance(elements[name]["elmt_type"], (UnicodeType, StringType)): |
703 # Class has a list of attributes that can have different value types |
1197 namespace, name = DecomposeQualifiedName(infos) |
704 elif "multichoice_content" in members.keys() and name in members["multichoice_content"].keys(): |
1198 elements[name]["elmt_type"] = factory.GetQualifiedNameInfos(name, namespace) |
705 attr_type = members["multichoice_content"][name] |
1199 if elements[name]["maxOccurs"] == "unbounded" or elements[name]["maxOccurs"] > 1: |
706 # Extracts the value |
1200 if first.get(name, True): |
707 if attr_type.startswith("bse:"): |
1201 setattr(self, name, [elements[name]["elmt_type"]["extract"](node)]) |
708 val = GetComputedValue(attr_type, GetAttributeValue(node)) |
1202 first[name] = False |
709 elif attr_type.startswith("cls:"): |
1203 else: |
710 val = classes[attr_type[4:]]() |
1204 getattr(self, name).append(elements[name]["elmt_type"]["extract"](node)) |
711 val.loadXMLTree(node) |
1205 else: |
712 # Add to content attribute list |
1206 setattr(self, name, elements[name]["elmt_type"]["extract"](node)) |
713 if val: |
1207 elif name == "#cdata-section" and "text" in elements: |
714 self.content.append({"name":name,"value":val}) |
1208 if elements["text"]["maxOccurs"] == "unbounded" or elements["text"]["maxOccurs"] > 1: |
715 |
1209 if first.get("text", True): |
716 # The node child is defined in the list |
1210 setattr(self, "text", [elements["text"]["elmt_type"]["extract"](node)]) |
717 elif name in members.keys(): |
1211 first["text"] = False |
718 attr_type, xml_type, write_type, default = members[name] |
1212 else: |
719 # Extracts the value |
1213 getattr(self, "text").append(elements["text"]["elmt_type"]["extract"](node)) |
720 if attr_type.startswith("bse:"): |
1214 else: |
721 attr_value = GetAttributeValue(node) |
1215 setattr(self, "text", elements["text"]["elmt_type"]["extract"](node)) |
722 if write_type != "optional" or attr_value != "": |
1216 elif "content" in elements: |
723 val = GetComputedValue(attr_type.replace("[]",""), attr_value) |
1217 content = getattr(self, "content") |
724 else: |
1218 if elements["content"]["maxOccurs"] == "unbounded" or elements["content"]["maxOccurs"] > 1: |
725 val = None |
1219 if first.get("content", True): |
726 elif attr_type.startswith("cls:"): |
1220 setattr(self, "content", [elements["content"]["elmt_type"]["extract"](node, None)]) |
727 val = classes[attr_type[4:].replace("[]","")]() |
1221 first["content"] = False |
728 val.loadXMLTree(node) |
1222 else: |
729 # Stock value in attribute |
1223 content.append(elements["content"]["elmt_type"]["extract"](node, content)) |
730 if val: |
1224 else: |
731 if attr_type.endswith("[]"): |
1225 setattr(self, "content", elements["content"]["elmt_type"]["extract"](node, content)) |
732 getattr(self, name).append(val) |
|
733 else: |
|
734 setattr(self, name, val) |
|
735 return loadXMLTreeMethod |
1226 return loadXMLTreeMethod |
|
1227 |
736 |
1228 |
737 """ |
1229 """ |
738 Method that generates the method for generating an xml text by following the |
1230 Method that generates the method for generating an xml text by following the |
739 attributes list defined |
1231 attributes list defined |
740 """ |
1232 """ |
741 def generateGenerateXMLText(bases, members): |
1233 def generateGenerateXMLText(factory, classinfos): |
742 def generateXMLTextMethod(self, name, indent, extras = {}, derived = False): |
1234 def generateXMLTextMethod(self, name, indent = 0, extras = {}, derived = False): |
743 ind1, ind2 = getIndent(indent, name) |
1235 ind1, ind2 = getIndent(indent, name) |
744 if not derived: |
1236 if not derived: |
745 text = ind1 + "<%s"%name |
1237 text = ind1 + "<%s"%name |
746 else: |
1238 else: |
747 text = "" |
1239 text = "" |
748 if len(bases) > 0: |
1240 |
749 base_extras = {} |
|
750 if "order" in members.keys(): |
|
751 order = members["order"] |
|
752 else: |
|
753 order = [] |
|
754 for attr, values in members.items(): |
|
755 if attr != "order" and (attr in ("choice_content", "multichoice_content") or values[1] != "attribute"): |
|
756 if attr not in order: |
|
757 order.append(attr) |
|
758 size = 0 |
|
759 first = True |
1241 first = True |
760 for attr, value in extras.items(): |
1242 if "base" not in classinfos: |
761 if not first and not self.singleLineAttributes: |
1243 for attr, value in extras.items(): |
762 text += "\n%s"%(ind2) |
1244 if not first and not self.singleLineAttributes: |
763 text += " %s=\"%s\""%(attr, ComputeValue(value)) |
1245 text += "\n%s"%(ind2) |
764 first = False |
1246 text += " %s=\"%s\""%(attr, value) |
765 for attr, values in members.items(): |
1247 first = False |
766 if attr in ["order","choice_content","multichoice_content"]: |
1248 extras.clear() |
767 pass |
1249 for attr in classinfos["attributes"]: |
768 elif attr in ["enum","limit"]: |
1250 if attr["use"] != "prohibited": |
769 if not derived: |
1251 if isinstance(attr["attr_type"], (UnicodeType, StringType)): |
770 text += ">%s</%s>\n"%(ComputeValue(self.value),name) |
1252 namespace, name = DecomposeQualifiedName(infos) |
771 else: |
1253 attr["attr_type"] = factory.GetQualifiedNameInfos(name, namespace) |
772 text += ComputeValue(self.value) |
1254 value = getattr(self, attr["name"], None) |
773 return text |
|
774 elif values[1] == "attribute": |
|
775 value = getattr(self, attr, None) |
|
776 if value != None: |
1255 if value != None: |
777 if values[0].startswith("cls"): |
1256 computed_value = attr["attr_type"]["generate"](value) |
778 value = value.getValue() |
|
779 computed_value = ComputeValue(value) |
|
780 else: |
1257 else: |
781 computed_value = None |
1258 computed_value = None |
782 if values[2] != "optional" or (value != None and computed_value != values[3]): |
1259 if attr["use"] != "optional" or (value != None and computed_value != attr.get("default", attr["attr_type"]["generate"](attr["attr_type"]["initial"]()))): |
783 if len(bases) > 0: |
1260 if "base" in classinfos: |
784 base_extras[attr] = value |
1261 extras[attr["name"]] = computed_value |
785 else: |
1262 else: |
786 if not first and not self.singleLineAttributes: |
1263 if not first and not self.singleLineAttributes: |
787 text += "\n%s"%(ind2) |
1264 text += "\n%s"%(ind2) |
788 text += " %s=\"%s\""%(attr, computed_value) |
1265 text += " %s=\"%s\""%(attr["name"], computed_value) |
789 first = False |
1266 first = False |
790 if len(bases) > 0: |
1267 if "base" in classinfos: |
791 first, new_text = bases[0].generateXMLText(self, name, indent, base_extras, True) |
1268 first, new_text = classinfos["base"].generateXMLText(self, name, indent, extras, True) |
792 text += new_text |
1269 text += new_text |
793 else: |
1270 else: |
794 first = True |
1271 first = True |
795 ind3, ind4 = getIndent(indent + 1, name) |
1272 for element in classinfos["elements"]: |
796 for attr in order: |
1273 if isinstance(element["elmt_type"], (UnicodeType, StringType)): |
797 value = getattr(self, attr, None) |
1274 namespace, name = DecomposeQualifiedName(infos) |
798 if attr == "choice_content": |
1275 element["elmt_type"] = factory.GetQualifiedNameInfos(name, namespace) |
799 if self.content: |
1276 value = getattr(self, element["name"], None) |
|
1277 if element["minOccurs"] == 0 and element["maxOccurs"] == 1: |
|
1278 if value is not None: |
800 if first: |
1279 if first: |
801 text += ">\n" |
1280 text += ">\n" |
802 first = False |
1281 first = False |
803 value_type = members[attr][self.content["name"]] |
1282 text += element["elmt_type"]["generate"](value, element["name"], indent + 1) |
804 if value_type.startswith("bse:"): |
1283 elif element["minOccurs"] == 1 and element["maxOccurs"] == 1: |
805 if value_type.endswith("[]"): |
1284 if first: |
806 for content in self.content["value"]: |
1285 text += ">\n" |
807 text += ind1 + "<%s>%s</%s>\n"%(self.content["name"], ComputeValue(content), self.content["name"]) |
1286 first = False |
808 else: |
1287 text += element["elmt_type"]["generate"](value, element["name"], indent + 1) |
809 text += ind1 + "<%s>%s</%s>\n"%(self.content["name"], ComputeValue(self.content["value"]), self.content["name"]) |
1288 else: |
810 elif value_type.endswith("[]"): |
1289 if first and len(value) > 0: |
811 for content in self.content["value"]: |
1290 text += ">\n" |
812 text += content.generateXMLText(self.content["name"], indent + 1) |
1291 first = False |
813 elif self.content["value"] is not None: |
1292 for item in value: |
814 text += self.content["value"].generateXMLText(self.content["name"], indent + 1) |
1293 text += element["elmt_type"]["generate"](item, element["name"], indent + 1) |
815 else: |
|
816 ind5, ind6 = getIndent(indent + 1, self.content["name"]) |
|
817 text += ind5 + "<%s/>\n"%self.content["name"] |
|
818 elif attr == "multichoice_content": |
|
819 if len(self.content) > 0: |
|
820 for element in self.content: |
|
821 if first: |
|
822 text += ">\n" |
|
823 first = False |
|
824 value_type = members[attr][element["name"]] |
|
825 if value_type.startswith("bse:"): |
|
826 text += ind1 + "<%s>%s</%s>\n"%(element["name"], ComputeValue(element["value"]), element["name"]) |
|
827 else: |
|
828 text += element["value"].generateXMLText(element["name"], indent + 1) |
|
829 elif members[attr][2] != "optional" or value != None: |
|
830 if members[attr][0].endswith("[]"): |
|
831 if first and len(value) > 0: |
|
832 text += ">\n" |
|
833 first = False |
|
834 for element in value: |
|
835 if members[attr][0].startswith("bse:"): |
|
836 text += ind3 + "<%s>%s</%s>\n"%(attr, ComputeValue(element), attr) |
|
837 else: |
|
838 text += element.generateXMLText(attr, indent + 1) |
|
839 else: |
|
840 if first: |
|
841 text += ">\n" |
|
842 first = False |
|
843 if members[attr][0].startswith("bse:"): |
|
844 text += ind3 + "<%s>%s</%s>\n"%(attr, ComputeValue(value), attr) |
|
845 else: |
|
846 text += getattr(self, attr).generateXMLText(attr, indent + 1) |
|
847 if not derived: |
1294 if not derived: |
848 if first: |
1295 if first: |
849 text += "/>\n" |
1296 text += "/>\n" |
850 else: |
1297 else: |
851 text += ind1 + "</%s>\n"%(name) |
1298 text += ind1 + "</%s>\n"%(name) |
852 return text |
1299 return text |
853 else: |
1300 else: |
854 return first, text |
1301 return first, text |
855 return generateXMLTextMethod |
1302 return generateXMLTextMethod |
856 |
1303 |
857 |
1304 def gettypeinfos(name, facets): |
858 def generateGetElementAttributes(members, classes): |
1305 if "enumeration" in facets and facets["enumeration"][0] is not None: |
|
1306 return facets["enumeration"][0] |
|
1307 elif "maxInclusive" in facets: |
|
1308 limits = {"max" : None, "min" : None} |
|
1309 if facets["maxInclusive"][0] is not None: |
|
1310 limits["max"] = facets["maxInclusive"][0] |
|
1311 elif facets["maxExclusive"][0] is not None: |
|
1312 limits["max"] = facets["maxExclusive"][0] - 1 |
|
1313 if facets["minInclusive"][0] is not None: |
|
1314 limits["min"] = facets["minInclusive"][0] |
|
1315 elif facets["minExclusive"][0] is not None: |
|
1316 limits["min"] = facets["minExclusive"][0] + 1 |
|
1317 if limits["max"] is not None or limits["min"] is not None: |
|
1318 return limits |
|
1319 return name |
|
1320 |
|
1321 def generateGetElementAttributes(factory, classinfos): |
859 def getElementAttributes(self): |
1322 def getElementAttributes(self): |
860 attr_list = [] |
1323 attr_list = [] |
861 for attr, values in members.items(): |
1324 for attr in classinfos["attributes"]: |
862 if attr in ["order","choice_content","multichoice_content"]: |
1325 if attr["use"] != "prohibited": |
863 pass |
1326 attr_params = {"name" : attr["name"], "require" : attr["use"] == "required", |
864 elif values[1] == "attribute": |
1327 "type" : gettypeinfos(attr["attr_type"]["basename"], attr["attr_type"]["facets"]), |
865 attr_params = {"name": attr, "require": values[2] == "required"} |
1328 "value" : getattr(self, attr["name"], "")} |
866 if values[0].startswith("cls:"): |
|
867 attr_value = getattr(self, attr, None) |
|
868 if attr_value: |
|
869 attr_params["value"] = attr_value.getValue() |
|
870 else: |
|
871 attr_params["value"] = "" |
|
872 attr_params["type"] = classes[values[0][4:]]().getValidValues() |
|
873 else: |
|
874 attr_params["value"] = getattr(self, attr, "") |
|
875 attr_params["type"] = values[0][4:] |
|
876 attr_list.append(attr_params) |
1329 attr_list.append(attr_params) |
877 return attr_list |
1330 return attr_list |
878 return getElementAttributes |
1331 return getElementAttributes |
879 |
1332 |
880 def generateGetElementInfos(members, classes): |
1333 def generateGetElementInfos(factory, classinfos): |
|
1334 attributes = dict([(attr["name"], attr) for attr in classinfos["attributes"] if attr["use"] != "prohibited"]) |
|
1335 elements = dict([(element["name"], element) for element in classinfos["elements"]]) |
|
1336 |
881 def getElementInfos(self, name, path = None): |
1337 def getElementInfos(self, name, path = None): |
882 attr_type = "element" |
1338 attr_type = "element" |
883 value = None |
1339 value = None |
884 children = [] |
1340 children = [] |
885 if "enum" in members: |
1341 if path is not None: |
886 attr_type = self.getValidValues() |
1342 parts = path.split(".", 1) |
887 value = self.value |
1343 if parts[0] in attributes: |
888 elif "limit" in members: |
1344 if len(parts) != 0: |
889 attr_type = {"min" : None, "max" : None} |
1345 raise ValueError, "Wrong path!" |
890 if "min" in members: |
1346 attr_type = gettypeinfos(attributes[parts[0]]["attr_type"]["basename"], |
891 attr_type["min"] = members["min"] |
1347 attributes[parts[0]]["attr_type"]["facets"]) |
892 if "max" in members: |
1348 value = getattr(self, parts[0], "") |
893 attr_type["max"] = members["max"] |
1349 elif parts[0] in elements: |
894 value = self.value |
1350 if element["elmt_type"]["type"] == SIMPLETYPE: |
895 elif path: |
1351 if len(parts) != 0: |
896 if "choice_content" in members: |
1352 raise ValueError, "Wrong path!" |
897 return self.content["value"].getElementInfos(self.content["name"], path) |
1353 attr_type = gettypeinfos(elements[parts[0]]["elmt_type"]["basename"], |
898 elif "multichoice_content" not in members: |
1354 elements[parts[0]]["elmt_type"]["facets"]) |
899 parts = path.split(".", 1) |
1355 value = getattr(self, parts[0], "") |
900 if parts[0] in members: |
1356 elif parts[0] == "content": |
901 values = members[parts[0]] |
1357 return self.content["value"].getElementInfos(self.content["name"], path) |
902 if values[1] == "attribute" and len(parts) == 1: |
1358 elif len(parts) == 1: |
903 attr = getattr(self, parts[0], None) |
1359 return attr.getElementInfos(parts[0]) |
904 if attr != None: |
1360 else: |
905 if values[0].startswith("cls:"): |
1361 return attr.getElementInfos(parts[0], parts[1]) |
906 return attr.getElementInfos(parts[0]) |
1362 else: |
907 else: |
1363 raise ValueError, "Wrong path!" |
908 attr_type = values[0][4:] |
1364 else: |
909 value = getattr(self, attr, "") |
1365 children.extend(self.getElementAttributes()) |
910 elif values[1] == "element": |
1366 for element_name, element in elements.items(): |
911 attr = getattr(self, parts[0], None) |
1367 if element_name == "content": |
912 if attr != None: |
1368 attr_type = [(choice["name"], None) for choice in element["choices"]] |
913 if len(parts) == 1: |
1369 value = self.content["name"] |
914 return attr.getElementInfos(parts[0]) |
1370 children.extend(self.content["value"].getElementInfos(self.content["name"])["children"]) |
915 else: |
1371 elif element["elmt_type"]["type"] == SIMPLETYPE: |
916 return attr.getElementInfos(parts[0], parts[1]) |
1372 children.append({"name" : element_name, "require" : element["minOccurs"] != 0, |
917 else: |
1373 "type" : gettypeinfos(element["elmt_type"]["basename"], |
918 for attr, values in members.items(): |
1374 element["elmt_type"]["facets"]), |
919 if attr == "order": |
1375 "value" : getattr(self, element_name, None)}) |
920 pass |
1376 else: |
921 elif attr == "choice_content": |
1377 instance = getattr(self, element_name, None) |
922 attr_type = self.getChoices().items() |
1378 if instance is None: |
923 if self.content: |
1379 instance = elmt_type["elmt_type"]["initial"]() |
924 value = self.content["name"] |
1380 children.append(instance.getElementInfos(element_name)) |
925 children.extend(self.content["value"].getElementInfos(self.content["name"])["children"]) |
|
926 elif attr == "multichoice_content": |
|
927 for element_infos in self.content: |
|
928 children.append(element_infos["value"].getElementInfos(element_infos["name"])) |
|
929 elif values[1] == "attribute" and not values[0].startswith("cls:"): |
|
930 children.append({"name" : attr, "value" : getattr(self, attr, ""), "type" : values[0][4:], "children" : []}) |
|
931 else: |
|
932 element = getattr(self, attr, None) |
|
933 if not element: |
|
934 element = classes[values[0][4:]]() |
|
935 children.append(element.getElementInfos(attr)) |
|
936 return {"name" : name, "type" : attr_type, "value" : value, "children" : children} |
1381 return {"name" : name, "type" : attr_type, "value" : value, "children" : children} |
937 return getElementInfos |
1382 return getElementInfos |
938 |
1383 |
939 def generateSetElementValue(members): |
1384 def generateSetElementValue(factory, classinfos): |
|
1385 attributes = dict([(attr["name"], attr) for attr in classinfos["attributes"] if attr["use"] != "prohibited"]) |
|
1386 elements = dict([(element["name"], element) for element in classinfos["elements"]]) |
|
1387 |
940 def setElementValue(self, path, value): |
1388 def setElementValue(self, path, value): |
941 if "enum" in members or "limit" in members: |
1389 if "content" in elements: |
942 if not path: |
|
943 self.setValue(value) |
|
944 elif "choice_content" in members: |
|
945 if path: |
1390 if path: |
946 self.content["value"].setElementValue(path, value) |
1391 self.content["value"].setElementValue(path, value) |
947 else: |
1392 else: |
948 self.addContent(value) |
1393 self.addcontentbytype(value) |
949 else: |
1394 else: |
950 parts = path.split(".", 1) |
1395 parts = path.split(".", 1) |
951 if parts[0] in members: |
1396 if parts[0] in attributes: |
952 values = members[parts[0]] |
1397 if len(parts) != 1: |
953 if values[1] == "attribute" and len(parts) == 1: |
1398 raise ValueError, "Wrong path!" |
954 attr = getattr(self, parts[0], None) |
1399 if attributes[parts[0]]["attr_type"]["basename"] == "boolean": |
955 if attr != None: |
1400 setattr(self, parts[0], value) |
956 if values[0].startswith("cls:"): |
1401 else: |
957 attr.setElementValue(None, value) |
1402 setattr(self, parts[0], attributes[parts[0]]["attr_type"]["extract"](value, False)) |
958 elif values[0][4:] == "boolean": |
1403 elif parts[0] in elements: |
959 setattr(self, parts[0], value) |
1404 if elements[parts[0]]["elmt_type"]["type"] == SIMPLETYPE: |
|
1405 if len(parts) != 1: |
|
1406 raise ValueError, "Wrong path!" |
|
1407 if elements[parts[0]]["elmt_type"]["basename"] == "boolean": |
|
1408 setattr(self, parts[0], value) |
|
1409 else: |
|
1410 setattr(self, parts[0], elements[parts[0]]["elmt_type"]["extract"](value, False)) |
|
1411 else: |
|
1412 instance = getattr(self, parts[0], None) |
|
1413 if instance != None: |
|
1414 if len(parts) == 1: |
|
1415 instance.setElementValue(None, value) |
960 else: |
1416 else: |
961 setattr(self, parts[0], GetComputedValue(values[0], value)) |
1417 instance.setElementValue(parts[1], value) |
962 elif values[1] == "element": |
|
963 attr = getattr(self, parts[0], None) |
|
964 if attr != None: |
|
965 if len(parts) == 1: |
|
966 attr.setElementValue(None, value) |
|
967 else: |
|
968 attr.setElementValue(parts[1], value) |
|
969 return setElementValue |
1418 return setElementValue |
970 |
1419 |
971 """ |
1420 """ |
972 Methods that generates the different methods for setting and getting the attributes |
1421 Methods that generates the different methods for setting and getting the attributes |
973 """ |
1422 """ |
974 def generateInitMethod(bases, members): |
1423 def generateInitMethod(factory, classinfos): |
975 def initMethod(self): |
1424 def initMethod(self): |
976 for base in bases: |
1425 if "base" in classinfos: |
977 base.__init__(self) |
1426 classinfos["base"].__init__(self) |
978 for attr, initial in members.items(): |
1427 for attribute in classinfos["attributes"]: |
979 setattr(self, attr, initial()) |
1428 if isinstance(attribute["attr_type"], (UnicodeType, StringType)): |
|
1429 namespace, name = DecomposeQualifiedName(attribute["attr_type"]) |
|
1430 attribute["attr_type"] = factory.GetQualifiedNameInfos(name, namespace) |
|
1431 if attribute["use"] == "required": |
|
1432 setattr(self, attribute["name"], attribute["attr_type"]["initial"]()) |
|
1433 elif attribute["use"] == "optional": |
|
1434 if "default" in attribute: |
|
1435 setattr(self, attribute["name"], attribute["attr_type"]["extract"](attribute["default"], False)) |
|
1436 else: |
|
1437 setattr(self, attribute["name"], None) |
|
1438 for element in classinfos["elements"]: |
|
1439 if isinstance(element["elmt_type"], (UnicodeType, StringType)): |
|
1440 namespace, name = DecomposeQualifiedName(element["elmt_type"]) |
|
1441 element["elmt_type"] = factory.GetQualifiedNameInfos(name, namespace) |
|
1442 if element["minOccurs"] == 0 and element["maxOccurs"] == 1: |
|
1443 if "default" in element: |
|
1444 setattr(self, element["name"], element["elmt_type"]["extract"](element["default"], False)) |
|
1445 else: |
|
1446 setattr(self, element["name"], None) |
|
1447 elif element["minOccurs"] == 1 and element["maxOccurs"] == 1: |
|
1448 setattr(self, element["name"], element["elmt_type"]["initial"]()) |
|
1449 else: |
|
1450 value = [] |
|
1451 for i in xrange(element["minOccurs"]): |
|
1452 value.append(element["elmt_type"]["initial"]()) |
|
1453 setattr(self, element["name"], value) |
980 return initMethod |
1454 return initMethod |
981 |
1455 |
982 def generateSetMethod(attr, attr_type): |
1456 def generateSetMethod(attr): |
983 def setMethod(self, value): |
1457 def setMethod(self, value): |
984 setattr(self, attr, value) |
1458 setattr(self, attr, value) |
985 return setMethod |
|
986 |
|
987 def generateAddChoiceMethod(choice_type, initial_values): |
|
988 def addChoiceMethod(self, name): |
|
989 if name in choice_type: |
|
990 self.content = {"name" : name, "value" : initial_values[name]()} |
|
991 return addChoiceMethod |
|
992 |
|
993 def generateSetChoiceMethod(choice_type): |
|
994 def setChoiceMethod(self, name, value): |
|
995 self.content = {"name" : name, "value" : value} |
|
996 return setChoiceMethod |
|
997 |
|
998 def generateGetChoicesMethod(choice_type): |
|
999 def getChoicesMethod(self): |
|
1000 return choice_type |
|
1001 return getChoicesMethod |
|
1002 |
|
1003 def generateSetEnumMethod(enum, attr_type): |
|
1004 def setEnumMethod(self, value): |
|
1005 if value in enum: |
|
1006 self.value = value |
|
1007 else: |
|
1008 raise ValueError, "%s is not a valid value. Must be in %s"%(value, str(enum)) |
|
1009 return setEnumMethod |
|
1010 |
|
1011 def generateSetLimitMethod(limit, attr_type): |
|
1012 def setMethod(self, value): |
|
1013 if "min" in limit and value < limit["min"]: |
|
1014 raise ValueError, "%s is not a valid value. Must be greater than %d"%(value, limit["min"]) |
|
1015 elif "max" in limit and value > limit["max"]: |
|
1016 raise ValueError, "%s is not a valid value. Must be smaller than %d"%(value, limit["max"]) |
|
1017 else: |
|
1018 self.value = value |
|
1019 return setMethod |
1459 return setMethod |
1020 |
1460 |
1021 def generateGetMethod(attr): |
1461 def generateGetMethod(attr): |
1022 def getMethod(self): |
1462 def getMethod(self): |
1023 return getattr(self, attr, None) |
1463 return getattr(self, attr, None) |
1024 return getMethod |
1464 return getMethod |
1025 |
1465 |
1026 def generateAddMethod(attr, initial): |
1466 def generateAddMethod(attr, factory, infos): |
1027 def addMethod(self): |
1467 def addMethod(self): |
1028 setattr(self, attr, initial()) |
1468 if infos["type"] == ATTRIBUTE: |
|
1469 if isinstance(infos["attr_type"], (UnicodeType, StringType)): |
|
1470 namespace, name = DecomposeQualifiedName(infos) |
|
1471 infos["attr_type"] = factory.GetQualifiedNameInfos(name, namespace) |
|
1472 initial = infos["attr_type"]["initial"] |
|
1473 extract = infos["attr_type"]["extract"] |
|
1474 elif infos["type"] == ELEMENT: |
|
1475 if isinstance(infos["elmt_type"], (UnicodeType, StringType)): |
|
1476 namespace, name = DecomposeQualifiedName(infos) |
|
1477 infos["elmt_type"] = factory.GetQualifiedNameInfos(name, namespace) |
|
1478 initial = infos["elmt_type"]["initial"] |
|
1479 extract = infos["elmt_type"]["extract"] |
|
1480 else: |
|
1481 raise ValueError, "Invalid class attribute!" |
|
1482 if "default" in infos: |
|
1483 setattr(self, attr, extract(infos["default"], False)) |
|
1484 else: |
|
1485 setattr(self, attr, initial()) |
1029 return addMethod |
1486 return addMethod |
1030 |
1487 |
1031 def generateDeleteMethod(attr): |
1488 def generateDeleteMethod(attr): |
1032 def deleteMethod(self): |
1489 def deleteMethod(self): |
1033 setattr(self, attr, None) |
1490 setattr(self, attr, None) |
1034 return deleteMethod |
1491 return deleteMethod |
1035 |
1492 |
1036 def generateAppendMethod(attr, attr_type): |
1493 def generateAppendMethod(attr, maxOccurs, factory, infos): |
1037 def appendMethod(self, value): |
1494 def appendMethod(self, value): |
1038 getattr(self, attr).append(value) |
1495 if isinstance(infos["elmt_type"], (UnicodeType, StringType)): |
|
1496 namespace, name = DecomposeQualifiedName(infos) |
|
1497 infos["elmt_type"] = factory.GetQualifiedNameInfos(name, namespace) |
|
1498 attr_list = getattr(self, attr) |
|
1499 if maxOccurs == "unbounded" or len(attr_list) < maxOccurs: |
|
1500 if infos["elmt_type"]["check"](value): |
|
1501 attr_list.append(value) |
|
1502 else: |
|
1503 raise ValueError, "\"%s\" value isn't valid!"%attr |
|
1504 else: |
|
1505 raise ValueError, "There can't be more than %d values in \"%s\"!"%(maxOccurs, attr) |
1039 return appendMethod |
1506 return appendMethod |
1040 |
1507 |
1041 def generateInsertMethod(attr, attr_type): |
1508 def generateInsertMethod(attr, maxOccurs, factory, infos): |
1042 def insertMethod(self, index, value): |
1509 def insertMethod(self, index, value): |
1043 getattr(self, attr).insert(index, value) |
1510 if isinstance(infos["elmt_type"], (UnicodeType, StringType)): |
|
1511 namespace, name = DecomposeQualifiedName(infos) |
|
1512 infos["elmt_type"] = factory.GetQualifiedNameInfos(name, namespace) |
|
1513 attr_list = getattr(self, attr) |
|
1514 if maxOccurs == "unbounded" or len(attr_list) < maxOccurs: |
|
1515 if infos["elmt_type"]["check"](value): |
|
1516 attr_list.insert(index, value) |
|
1517 else: |
|
1518 raise ValueError, "\"%s\" value isn't valid!"%attr |
|
1519 else: |
|
1520 raise ValueError, "There can't be more than %d values in \"%s\"!"%(maxOccurs, attr) |
1044 return insertMethod |
1521 return insertMethod |
1045 |
1522 |
1046 def generateAppendChoiceByTypeMethod(choice_type, initial_values): |
1523 def generateGetChoicesMethod(choice_types): |
|
1524 def getChoicesMethod(self): |
|
1525 return [choice["name"] for choice in choice_types] |
|
1526 return getChoicesMethod |
|
1527 |
|
1528 def generateAddChoiceByTypeMethod(choice_types): |
|
1529 choices = dict([(choice["name"], choice) for choice in choice_types]) |
1047 def addChoiceMethod(self, name): |
1530 def addChoiceMethod(self, name): |
1048 if name in choice_type: |
1531 if name in choices: |
1049 self.content.append({"name" : name, "value" : initial_values[name]()}) |
1532 if isinstance(choices["name"]["elmt_type"], (UnicodeType, StringType)): |
|
1533 namespace, name = DecomposeQualifiedName(infos) |
|
1534 choices["name"]["elmt_type"] = factory.GetQualifiedNameInfos(name, namespace) |
|
1535 self.content = {"name" : name, "value" : choices["name"]["elmt_type"]["initial"]()} |
1050 return addChoiceMethod |
1536 return addChoiceMethod |
1051 |
1537 |
1052 def generateAppendChoiceMethod(choice_types): |
1538 def generateRemoveMethod(attr, minOccurs): |
1053 def appendMethod(self, name, value): |
|
1054 self.content.append({"name":name,"value":value}) |
|
1055 return appendMethod |
|
1056 |
|
1057 def generateInsertChoiceMethod(choice_types): |
|
1058 def insertMethod(self, index, name, value): |
|
1059 self.content.insert(index, {"name":name,"value":value}) |
|
1060 return insertMethod |
|
1061 |
|
1062 def generateRemoveMethod(attr): |
|
1063 def removeMethod(self, index): |
1539 def removeMethod(self, index): |
1064 getattr(self, attr).pop(index) |
1540 attr_list = getattr(self, attr) |
|
1541 if len(attr_list) > minOccurs: |
|
1542 getattr(self, attr).pop(index) |
|
1543 else: |
|
1544 raise ValueError, "There can't be less than %d values in \"%s\"!"%(minOccurs, attr) |
1065 return removeMethod |
1545 return removeMethod |
1066 |
1546 |
1067 def generateCountMethod(attr): |
1547 def generateCountMethod(attr): |
1068 def countMethod(self): |
1548 def countMethod(self): |
1069 return len(getattr(self, attr)) |
1549 return len(getattr(self, attr)) |