lbessard@2: #!/usr/bin/env python lbessard@2: # -*- coding: utf-8 -*- lbessard@2: lbessard@2: #This file is part of PLCOpenEditor, a library implementing an IEC 61131-3 editor lbessard@2: #based on the plcopen standard. lbessard@2: # lbessard@58: #Copyright (C) 2007: Edouard TISSERANT and Laurent BESSARD lbessard@2: # lbessard@2: #See COPYING file for copyrights details. lbessard@2: # lbessard@2: #This library is free software; you can redistribute it and/or lbessard@2: #modify it under the terms of the GNU General Public lbessard@2: #License as published by the Free Software Foundation; either lbessard@2: #version 2.1 of the License, or (at your option) any later version. lbessard@2: # lbessard@2: #This library is distributed in the hope that it will be useful, lbessard@2: #but WITHOUT ANY WARRANTY; without even the implied warranty of lbessard@2: #MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU lbessard@58: #General Public License for more details. lbessard@2: # lbessard@2: #You should have received a copy of the GNU General Public lbessard@2: #License along with this library; if not, write to the Free Software lbessard@2: #Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA lbessard@2: lbessard@2: from xml.dom import minidom lbessard@2: import sys,re lbessard@2: from types import * lbessard@2: from datetime import * etisserant@75: from new import classobj lbessard@2: lbessard@2: """ lbessard@2: Time and date definitions lbessard@2: """ lbessard@2: TimeType = time(0,0,0).__class__ lbessard@2: DateType = date(1,1,1).__class__ lbessard@2: DateTimeType = datetime(1,1,1,0,0,0).__class__ lbessard@2: lbessard@2: """ lbessard@2: Regular expression models for extracting dates and times from a string lbessard@2: """ lbessard@24: time_model = re.compile('([0-9]{2}):([0-9]{2}):([0-9]{2}(?:.[0-9]*)?)') lbessard@2: date_model = re.compile('([0-9]{4})-([0-9]{2})-([0-9]{2})') lbessard@24: datetime_model = re.compile('([0-9]{4})-([0-9]{2})-([0-9]{2})[ T]([0-9]{2}):([0-9]{2}):([0-9]{2}(?:.[0-9]*)?)') lbessard@2: lbessard@2: """ lbessard@2: This function calculates the number of whitespace for indentation lbessard@2: """ lbessard@2: def getIndent(indent, balise): lbessard@2: first = indent * 2 lbessard@2: second = first + len(balise) + 1 lbessard@2: return "\t".expandtabs(first), "\t".expandtabs(second) lbessard@2: lbessard@2: """ lbessard@2: Function that extracts data from a node lbessard@2: """ lbessard@2: def GetAttributeValue(attr): lbessard@2: if len(attr.childNodes) == 1: lbessard@2: return attr.childNodes[0].data.encode() lbessard@2: else: lbessard@67: text = "" lbessard@67: for node in attr.childNodes: lbessard@67: if node.nodeName != "#text": lbessard@67: text += node.data.encode() lbessard@67: return text lbessard@2: lbessard@2: """ lbessard@2: Function that computes value from a python type (Only Boolean are critical because lbessard@2: there is no uppercase in plcopen) lbessard@2: """ lbessard@2: def ComputeValue(value): lbessard@2: if type(value) == BooleanType: lbessard@2: if value: lbessard@2: return "true" lbessard@2: else: lbessard@2: return "false" lbessard@2: else: lbessard@2: return str(value) lbessard@2: lbessard@2: """ lbessard@2: Function that extracts a value from a string following the xsd type given lbessard@2: """ lbessard@2: def GetComputedValue(attr_type, value): lbessard@2: type_compute = attr_type[4:].replace("[]", "") lbessard@2: if type_compute == "boolean": lbessard@2: if value == "true": lbessard@2: return True lbessard@2: elif value == "false": lbessard@2: return False lbessard@2: else: lbessard@2: raise ValueError, "\"%s\" is not a valid boolean!"%value lbessard@2: elif type_compute in ["decimal","unsignedLong","long","integer"]: lbessard@2: return int(value) lbessard@2: elif type_compute in ["string","anyURI","NMTOKEN","language"]: lbessard@2: return value lbessard@2: elif type_compute == "time": lbessard@2: result = time_model.match(value) lbessard@2: if result: lbessard@24: values = result.groups() lbessard@24: time_values = [int(v) for v in values[:2]] lbessard@24: seconds = float(values[2]) lbessard@24: time_values.extend([int(seconds), int((seconds % 1) * 1000000)]) lbessard@2: return time(*time_values) lbessard@2: else: lbessard@2: raise ValueError, "\"%s\" is not a valid time!"%value lbessard@2: elif type_compute == "date": lbessard@2: result = date_model.match(value) lbessard@2: if result: lbessard@2: date_values = [int(v) for v in result.groups()] lbessard@2: return date(*date_values) lbessard@2: else: lbessard@2: raise ValueError, "\"%s\" is not a valid date!"%value lbessard@2: elif type_compute == "dateTime": lbessard@2: result = datetime_model.match(value) lbessard@2: if result: lbessard@24: values = result.groups() lbessard@24: datetime_values = [int(v) for v in values[:5]] lbessard@24: seconds = float(values[5]) lbessard@24: datetime_values.extend([int(seconds), int((seconds % 1) * 1000000)]) lbessard@2: return datetime(*datetime_values) lbessard@2: else: lbessard@2: raise ValueError, "\"%s\" is not a valid datetime!"%value lbessard@2: else: lbessard@2: print "Can't affect: %s"%type_compute lbessard@2: return None lbessard@2: lbessard@2: """ lbessard@76: Class that generate class from an XML Tree lbessard@76: """ lbessard@76: class ClassFactory: lbessard@76: lbessard@76: def __init__(self, xsd_tree): lbessard@76: self.XML_Tree = xsd_tree lbessard@76: lbessard@76: # Dictionary for stocking Classes and Types definitions created from the XML tree lbessard@76: self.XMLClassDefinitions = {} lbessard@76: lbessard@76: # Dictionaries for stocking Classes and Types generated lbessard@76: self.ComputedClasses = {} lbessard@76: self.ComputedTypes = {} lbessard@76: self.AlreadyComputed = {} lbessard@76: lbessard@76: """ lbessard@76: This function recursively creates a definition of the classes and their attributes lbessard@76: for plcopen from the xsd file of plcopen opened in a DOM model lbessard@76: """ lbessard@76: def GenerateXSDClasses(self, tree, parent, sequence = False): lbessard@76: attributes = {} lbessard@76: inheritance = [] lbessard@76: if sequence: lbessard@76: order = [] lbessard@76: # The lists of attributes and inheritance of the node are generated from the childrens lbessard@76: for node in tree.childNodes: lbessard@76: # We make fun of #text elements and all other tags that don't are xsd tags lbessard@76: if node.nodeName != "#text" and node.nodeName.startswith("xsd:"): lbessard@76: recursion = False lbessard@76: name = node.nodeName[4:].encode() lbessard@76: lbessard@76: # This tags defines an attribute of the class lbessard@76: if name in ["element", "attribute"]: lbessard@76: nodename = GetAttributeValue(node._attrs["name"]) lbessard@76: if "type" in node._attrs: lbessard@76: nodetype = GetAttributeValue(node._attrs["type"]) lbessard@76: if nodetype.startswith("xsd"): lbessard@76: nodetype = nodetype.replace("xsd", "bse") lbessard@76: elif nodetype.startswith("ppx"): lbessard@76: nodetype = nodetype.replace("ppx", "cls") lbessard@76: else: lbessard@76: # The type of attribute is defines in the child tree so we generate a new class lbessard@76: # No name is defined so we create one from nodename and parent class name lbessard@76: # (because some different nodes can have the same name) lbessard@76: if parent: lbessard@76: classname = "%s_%s"%(parent, nodename) lbessard@76: else: lbessard@76: classname = nodename lbessard@76: self.GenerateXSDClasses(node, classname) lbessard@76: nodetype = "cls:%s"%classname lbessard@76: if name == "attribute": lbessard@76: if "use" in node._attrs: lbessard@76: use = GetAttributeValue(node._attrs["use"]) lbessard@76: else: lbessard@76: use = "optional" lbessard@76: if name == "element": lbessard@76: # If a tag can be written more than one time we define a list attribute lbessard@76: if "maxOccurs" in node._attrs and GetAttributeValue(node._attrs["maxOccurs"]) == "unbounded": lbessard@76: nodetype = "%s[]"%nodetype lbessard@76: if "minOccurs" in node._attrs and GetAttributeValue(node._attrs["minOccurs"]) == "0": lbessard@76: use = "optional" lbessard@76: else: lbessard@76: use = "required" lbessard@76: attributes[nodename] = (nodetype, name, use) lbessard@76: if sequence: lbessard@76: order.append(nodename) lbessard@76: lbessard@76: # This tag defines a new class lbessard@76: elif name == "complexType" or name == "simpleType": lbessard@76: if "name" in node._attrs: lbessard@76: classname = GetAttributeValue(node._attrs["name"]) lbessard@76: super, attrs = self.GenerateXSDClasses(node, classname) lbessard@76: else: lbessard@76: classname = parent lbessard@76: super, attrs = self.GenerateXSDClasses(node, classname.split("_")[-1]) lbessard@76: # When all attributes and inheritances have been extracted, the lbessard@76: # values are added in the list of classes to create lbessard@76: if self.XMLClassDefinitions.get(classname, None) == None: lbessard@76: self.XMLClassDefinitions[classname] = (super, attrs) lbessard@76: elif self.XMLClassDefinitions[classname] != (super, attrs): lbessard@76: print "A different class has already got %s for name"%classname lbessard@76: lbessard@76: # This tag defines an attribute that can have different types lbessard@76: elif name == "choice": lbessard@76: super, attrs = self.GenerateXSDClasses(node, parent) lbessard@76: lbessard@76: if "ref" in attrs.keys(): lbessard@76: choices = attrs lbessard@76: else: lbessard@76: choices = {} lbessard@76: for attr, (attr_type, xml_type, write_type) in attrs.items(): lbessard@76: choices[attr] = attr_type lbessard@76: if "maxOccurs" in node._attrs and GetAttributeValue(node._attrs["maxOccurs"]) == "unbounded": lbessard@76: attributes["multichoice_content"] = choices lbessard@76: if sequence: lbessard@76: order.append("multichoice_content") lbessard@76: else: lbessard@76: attributes["choice_content"] = choices lbessard@76: if sequence: lbessard@76: order.append("choice_content") lbessard@76: lbessard@76: # This tag defines the order in which class attributes must be written lbessard@76: # in plcopen xml file. We have to store this order like an attribute lbessard@76: elif name in "sequence": lbessard@76: super, attrs, order = self.GenerateXSDClasses(node, parent, True) lbessard@76: if "maxOccurs" in node._attrs and GetAttributeValue(node._attrs["maxOccurs"]) == "unbounded": lbessard@76: for attr, (attr_type, xml_type, write_type) in attrs.items(): lbessard@76: attrs[attr] = ("%s[]"%attr_type, xml_type, write_type) lbessard@76: if "minOccurs" in node._attrs and GetAttributeValue(node._attrs["minOccurs"]) == "0": lbessard@76: for attr, (attr_type, xml_type, write_type) in attrs.items(): lbessard@76: attrs[attr] = (attr_type, xml_type, "optional") lbessard@76: inheritance.extend(super) lbessard@76: attributes.update(attrs) lbessard@76: attributes["order"] = order lbessard@76: lbessard@76: # This tag defines of types lbessard@76: elif name == "group": lbessard@76: if "name" in node._attrs: lbessard@76: nodename = GetAttributeValue(node._attrs["name"]) lbessard@76: super, attrs = self.GenerateXSDClasses(node, None) lbessard@76: self.XMLClassDefinitions[nodename] = (super, {"group":attrs["choice_content"]}) lbessard@76: elif "ref" in node._attrs: lbessard@76: if "ref" not in attributes: lbessard@76: attributes["ref"] = [GetAttributeValue(node._attrs["ref"])] lbessard@76: else: lbessard@76: attributes["ref"].append(GetAttributeValue(node._attrs["ref"])) lbessard@76: lbessard@76: # This tag define a base class for the node lbessard@76: elif name == "extension": lbessard@76: super = GetAttributeValue(node._attrs["base"]) lbessard@76: if super.startswith("xsd"): lbessard@76: super = super.replace("xsd", "bse") lbessard@76: elif super.startswith("ppx"): lbessard@76: super = super.replace("ppx", "cls") lbessard@76: inheritance.append(super[4:]) lbessard@76: recursion = True lbessard@76: lbessard@76: # This tag defines a restriction on the type of attribute lbessard@76: elif name == "restriction": lbessard@76: basetype = GetAttributeValue(node._attrs["base"]) lbessard@76: if basetype.startswith("xsd"): lbessard@76: basetype = basetype.replace("xsd", "bse") lbessard@76: elif basetype.startswith("ppx"): lbessard@76: basetype = basetype.replace("ppx", "cls") lbessard@76: attributes["basetype"] = basetype lbessard@76: recursion = True lbessard@76: lbessard@76: # This tag defines an enumerated type lbessard@76: elif name == "enumeration": lbessard@76: if "enum" not in attributes: lbessard@76: attributes["enum"] = [GetAttributeValue(node._attrs["value"])] lbessard@76: else: lbessard@76: attributes["enum"].append(GetAttributeValue(node._attrs["value"])) lbessard@76: lbessard@76: # This tags defines a restriction on a numerical value lbessard@76: elif name in ["minInclusive","maxInclusive"]: lbessard@76: if "limit" not in attributes: lbessard@76: attributes["limit"] = {} lbessard@76: if name == "minInclusive": lbessard@76: attributes["limit"]["min"] = eval(GetAttributeValue(node._attrs["value"])) lbessard@76: elif name == "maxInclusive": lbessard@76: attributes["limit"]["max"] = eval(GetAttributeValue(node._attrs["value"])) lbessard@76: lbessard@76: # This tag are not important but their childrens are. The childrens are then parsed. lbessard@76: elif name in ["complexContent", "schema"]: lbessard@76: recursion = True lbessard@76: lbessard@76: # We make fun of xsd documentation lbessard@76: elif name in ["annotation"]: lbessard@76: pass lbessard@76: lbessard@76: else: lbessard@76: # Unable this line to print XSD element that is not yet supported lbessard@76: #print name lbessard@76: self.GenerateXSDClasses(node, parent) lbessard@76: lbessard@76: # Parse the childrens of node lbessard@76: if recursion: lbessard@76: super, attrs = self.GenerateXSDClasses(node, parent) lbessard@76: inheritance.extend(super) lbessard@76: attributes.update(attrs) lbessard@76: lbessard@76: # if sequence tag have been found, order is returned lbessard@76: if sequence: lbessard@76: return inheritance, attributes, order lbessard@76: else: lbessard@76: return inheritance, attributes lbessard@76: lbessard@76: """ lbessard@76: Funtion that returns the Python type and default value for a given type lbessard@76: """ lbessard@76: def GetTypeInitialValue(self, attr_type): lbessard@76: type_compute = attr_type[4:].replace("[]", "") lbessard@76: if attr_type.startswith("bse:"): lbessard@76: if type_compute == "boolean": lbessard@76: return BooleanType, "False" lbessard@76: elif type_compute in ["decimal","unsignedLong","long","integer"]: lbessard@76: return IntType, "0" lbessard@76: elif type_compute in ["string","anyURI","NMTOKEN"]: lbessard@76: return StringType, "\"\"" lbessard@76: elif type_compute == "time": lbessard@76: return TimeType, "time(0,0,0,0)" lbessard@76: elif type_compute == "date": lbessard@76: return DateType, "date(1,1,1)" lbessard@76: elif type_compute == "dateTime": lbessard@76: return DateTimeType, "datetime(1,1,1,0,0,0,0)" lbessard@76: elif type_compute == "language": lbessard@76: return StringType, "\"en-US\"" lbessard@76: else: lbessard@76: print "Can't affect: %s"%type_compute lbessard@76: elif attr_type.startswith("cls:"): lbessard@76: if self.XMLClassDefinitions.get(type_compute, None) != None: lbessard@76: return self.XMLClassDefinitions[type_compute],"%s()"%type_compute lbessard@76: lbessard@76: """ lbessard@76: Methods that generate the classes lbessard@76: """ lbessard@76: def CreateClasses(self): lbessard@76: self.GenerateXSDClasses(self.XML_Tree, None) lbessard@76: for classname in self.XMLClassDefinitions.keys(): lbessard@76: self.CreateClass(classname) lbessard@76: for classname in self.XMLClassDefinitions.keys(): lbessard@76: self.MarkUsedClasses(classname) lbessard@76: return self.ComputedClasses, self.ComputedTypes lbessard@76: lbessard@76: def CreateClass(self, classname): lbessard@76: # Checks that classe haven't been generated yet lbessard@76: if not self.AlreadyComputed.get(classname, False) and classname in self.XMLClassDefinitions: lbessard@76: self.AlreadyComputed[classname] = True lbessard@76: inheritance, attributes = self.XMLClassDefinitions[classname] lbessard@76: #print classname, inheritance, attributes lbessard@76: members = {} lbessard@76: bases = [] lbessard@76: lbessard@76: # If inheritance classes haven't been generated lbessard@76: for base in inheritance: lbessard@76: self.CreateClass(base) lbessard@76: bases.append(self.ComputedClasses[base]) lbessard@76: lbessard@76: # Checks that all attribute types are available lbessard@76: for attribute, type_attribute in attributes.items(): lbessard@76: if attribute == "group": lbessard@76: self.ComputedTypes[classname] = type_attribute lbessard@76: elif attribute in ["choice_content","multichoice_content"]: lbessard@76: element_types = {} lbessard@76: for attr, value in type_attribute.items(): lbessard@76: if attr == "ref": lbessard@76: for ref in value: lbessard@76: self.CreateClass(ref[4:]) lbessard@76: element_types.update(self.ComputedTypes[ref[4:]]) lbessard@76: else: lbessard@76: element_types[attr] = value lbessard@76: members[attribute] = element_types lbessard@76: else: lbessard@76: members[attribute] = type_attribute lbessard@76: if attribute == "enum": lbessard@76: self.ComputedTypes["%s_enum"%classname] = type_attribute lbessard@76: elif attribute not in ["limit", "order"]: lbessard@76: if type_attribute[0].startswith("cls:"): lbessard@76: type_compute = type_attribute[0][4:].replace("[]","") lbessard@76: self.CreateClass(type_compute) lbessard@76: if "group" not in attributes: lbessard@76: bases = tuple(bases) lbessard@76: classmembers = {"IsBaseClass" : True} lbessard@76: initialValues = {} lbessard@76: for attr, values in members.items(): lbessard@76: if attr in ["order", "basetype"]: lbessard@76: pass lbessard@76: lbessard@76: # Class is a enumerated type lbessard@76: elif attr == "enum": lbessard@76: value_type, initial = self.GetTypeInitialValue(members["basetype"]) lbessard@76: initialValues["value"] = "\"%s\""%values[0] lbessard@76: classmembers["value"] = values[0] lbessard@76: classmembers["setValue"] = generateSetEnumMethod(values, value_type) lbessard@76: classmembers["getValue"] = generateGetMethod("value") lbessard@76: lbessard@76: # Class is a limited type lbessard@76: elif attr == "limit": lbessard@76: value_type, initial = self.GetTypeInitialValue(members["basetype"]) lbessard@76: initial = 0 lbessard@76: if "min" in values: lbessard@76: initial = max(initial, values["min"]) lbessard@76: if "max" in values: lbessard@76: initial = min(initial, values["max"]) lbessard@76: initialValues["value"] = "%d"%initial lbessard@76: classmembers["value"] = initial lbessard@76: classmembers["setValue"] = generateSetLimitMethod(values, value_type) lbessard@76: classmembers["getValue"] = generateGetMethod("value") lbessard@76: lbessard@76: # Class has an attribute that can have different value types lbessard@76: elif attr == "choice_content": lbessard@76: classmembers["content"] = None lbessard@76: initialValues["content"] = "None" lbessard@76: classmembers["deleteContent"] = generateDeleteMethod("content") lbessard@76: classmembers["setContent"] = generateSetChoiceMethod(values) lbessard@76: classmembers["getContent"] = generateGetMethod("content") lbessard@76: elif attr == "multichoice_content": lbessard@76: classmembers["content"] = [] lbessard@76: initialValues["content"] = "[]" lbessard@76: classmembers["appendContent"] = generateAppendChoiceMethod(values) lbessard@76: classmembers["insertContent"] = generateInsertChoiceMethod(values) lbessard@76: classmembers["removeContent"] = generateRemoveMethod("content") lbessard@76: classmembers["countContent"] = generateCountMethod("content") lbessard@76: classmembers["setContent"] = generateSetMethod("content", ListType) lbessard@76: classmembers["getContent"] = generateGetMethod("content") lbessard@76: lbessard@76: # It's an attribute of the class lbessard@76: else: lbessard@76: attrname = attr[0].upper()+attr[1:] lbessard@76: attr_type, xml_type, write_type = values lbessard@76: value_type, initial = self.GetTypeInitialValue(attr_type) lbessard@76: # Value of the attribute is a list lbessard@76: if attr_type.endswith("[]"): lbessard@76: classmembers[attr] = [] lbessard@76: initialValues[attr] = "[]" lbessard@76: classmembers["append"+attrname] = generateAppendMethod(attr, value_type) lbessard@76: classmembers["insert"+attrname] = generateInsertMethod(attr, value_type) lbessard@76: classmembers["remove"+attrname] = generateRemoveMethod(attr) lbessard@76: classmembers["count"+attrname] = generateCountMethod(attr) lbessard@76: classmembers["set"+attrname] = generateSetMethod(attr, ListType) lbessard@76: else: lbessard@76: if write_type == "optional": lbessard@76: classmembers[attr] = None lbessard@76: initialValues[attr] = "None" lbessard@76: classmembers["add"+attrname] = generateAddMethod(attr, initial, self.ComputedClasses) lbessard@76: classmembers["delete"+attrname] = generateDeleteMethod(attr) lbessard@76: else: lbessard@76: classmembers[attr] = initial lbessard@76: initialValues[attr] = initial lbessard@76: classmembers["set"+attrname] = generateSetMethod(attr, value_type) lbessard@76: classmembers["get"+attrname] = generateGetMethod(attr) lbessard@76: classmembers["__init__"] = generateInitMethod(bases, initialValues, self.ComputedClasses) lbessard@76: classmembers["loadXMLTree"] = generateLoadXMLTree(bases, members, self.ComputedClasses) lbessard@76: classmembers["generateXMLText"] = generateGenerateXMLText(bases, members) lbessard@76: classmembers["getElementAttributes"] = generategetElementAttributes(bases, members) lbessard@76: classmembers["singleLineAttributes"] = True lbessard@76: lbessard@76: self.ComputedClasses[classname] = classobj(classname, bases, classmembers) lbessard@76: lbessard@76: def MarkUsedClasses(self, classname): lbessard@76: # Checks that classe haven't been generated yet lbessard@76: if classname in self.XMLClassDefinitions: lbessard@76: inheritance, attributes = self.XMLClassDefinitions[classname] lbessard@76: lbessard@76: # If inheritance classes haven't been generated lbessard@76: for base in inheritance: lbessard@76: if base in self.ComputedClasses: lbessard@76: self.ComputedClasses[base].IsBaseClass = False lbessard@76: lbessard@76: # Checks that all attribute types are available lbessard@76: for attribute, type_attribute in attributes.items(): lbessard@76: if attribute in ["choice_content","multichoice_content"]: lbessard@76: element_types = {} lbessard@76: for attr, value in type_attribute.items(): lbessard@76: if attr == "ref": lbessard@76: for ref in value: lbessard@76: element_types.update(self.ComputedTypes[ref[4:]]) lbessard@76: else: lbessard@76: element_types[attr] = value lbessard@76: for type_name in element_types.values(): lbessard@76: type_compute = type_name[4:].replace("[]","") lbessard@76: if type_compute in self.ComputedClasses: lbessard@76: self.ComputedClasses[type_compute].IsBaseClass = False lbessard@76: elif attribute != "group": lbessard@76: if attribute not in ["enum", "limit", "order"]: lbessard@76: if type_attribute[0].startswith("cls:"): lbessard@76: type_compute = type_attribute[0][4:].replace("[]","") lbessard@76: if type_compute in self.ComputedClasses: lbessard@76: self.ComputedClasses[type_compute].IsBaseClass = False lbessard@76: lbessard@76: """ lbessard@76: Methods that print the classes generated lbessard@76: """ lbessard@76: def PrintClasses(self): lbessard@76: for classname, xmlclass in self.ComputedClasses.items(): lbessard@76: print "%s : %s"%(classname, str(xmlclass)) lbessard@76: lbessard@76: def PrintClassNames(self): lbessard@76: classnames = self.XMLClassDefinitions.keys() lbessard@76: classnames.sort() lbessard@76: for classname in classnames: lbessard@76: print classname lbessard@76: lbessard@76: """ etisserant@75: Method that generate the method for loading an xml tree by following the etisserant@75: attributes list defined etisserant@75: """ lbessard@76: def generateLoadXMLTree(bases, members, classes): etisserant@75: def loadXMLTreeMethod(self, tree): etisserant@75: # If class is derived, values of inheritance classes are loaded etisserant@75: for base in bases: etisserant@75: base.loadXMLTree(self, tree) etisserant@75: # Class is a enumerated or limited value etisserant@75: if "enum" in members.keys() or "limit" in members.keys(): etisserant@75: attr_value = GetAttributeValue(tree) etisserant@75: attr_type = members["basetype"] etisserant@75: val = GetComputedValue(attr_type, attr_value) etisserant@75: self.setValue(val) etisserant@75: else: etisserant@75: etisserant@75: # Load the node attributes if they are defined in the list etisserant@75: for attrname, attr in tree._attrs.items(): etisserant@75: if attrname in members.keys(): etisserant@75: attr_type, xml_type, write_type = members[attrname] etisserant@75: attr_value = GetAttributeValue(attr) etisserant@75: if write_type != "optional" or attr_value != "": etisserant@75: # Extracts the value etisserant@75: if attr_type.startswith("bse:"): etisserant@75: val = GetComputedValue(attr_type, attr_value) etisserant@75: elif attr_type.startswith("cls:"): lbessard@76: val = classes[attr_type[4:]]() etisserant@75: val.loadXMLTree(attr) etisserant@75: setattr(self, attrname, val) etisserant@75: etisserant@75: # Load the node childs if they are defined in the list etisserant@75: for node in tree.childNodes: etisserant@75: name = node.nodeName etisserant@75: # We make fun of #text elements etisserant@75: if name != "#text": etisserant@75: etisserant@75: # Class has an attribute that can have different value types etisserant@75: if "choice_content" in members.keys() and name in members["choice_content"].keys(): etisserant@75: attr_type = members["choice_content"][name] etisserant@75: # Extracts the value etisserant@75: if attr_type.startswith("bse:"): etisserant@75: attr_value = GetAttributeValue(node) etisserant@75: if write_type != "optional" or attr_value != "": etisserant@75: val = GetComputedValue(attr_type.replace("[]",""), attr_value) etisserant@75: else: etisserant@75: val = None etisserant@75: elif attr_type.startswith("cls:"): lbessard@76: val = classes[attr_type[4:].replace("[]","")]() etisserant@75: val.loadXMLTree(node) etisserant@75: # Stock value in content attribute etisserant@75: if val: etisserant@75: if attr_type.endswith("[]"): etisserant@75: if self.content: etisserant@75: self.content["value"].append(val) etisserant@75: else: etisserant@75: self.content = {"name":name,"value":[val]} etisserant@75: else: etisserant@75: self.content = {"name":name,"value":val} etisserant@75: etisserant@75: # Class has a list of attributes that can have different value types etisserant@75: elif "multichoice_content" in members.keys() and name in members["multichoice_content"].keys(): etisserant@75: attr_type = members["multichoice_content"][name] etisserant@75: # Extracts the value etisserant@75: if attr_type.startswith("bse:"): etisserant@75: attr_value = GetAttributeValue(node) etisserant@75: if write_type != "optional" or attr_value != "": etisserant@75: val = GetComputedValue(attr_type, attr_value) etisserant@75: else: etisserant@75: val = None etisserant@75: elif attr_type.startswith("cls:"): lbessard@76: val = classes[attr_type[4:]]() etisserant@75: val.loadXMLTree(node) etisserant@75: # Add to content attribute list etisserant@75: if val: etisserant@75: self.content.append({"name":name,"value":val}) etisserant@75: etisserant@75: # The node child is defined in the list etisserant@75: elif name in members.keys(): etisserant@75: attr_type, xml_type, write_type = members[name] etisserant@75: # Extracts the value etisserant@75: if attr_type.startswith("bse:"): etisserant@75: attr_value = GetAttributeValue(node) etisserant@75: if write_type != "optional" or attr_value != "": etisserant@75: val = GetComputedValue(attr_type.replace("[]",""), attr_value) etisserant@75: else: etisserant@75: val = None etisserant@75: elif attr_type.startswith("cls:"): lbessard@76: val = classes[attr_type[4:].replace("[]","")]() etisserant@75: val.loadXMLTree(node) etisserant@75: # Stock value in attribute etisserant@75: if val: etisserant@75: if attr_type.endswith("[]"): etisserant@75: getattr(self, name).append(val) etisserant@75: else: etisserant@75: setattr(self, name, val) etisserant@75: return loadXMLTreeMethod etisserant@75: etisserant@75: """ etisserant@75: Method that generates the method for generating an xml text by following the etisserant@75: attributes list defined etisserant@75: """ etisserant@75: def generateGenerateXMLText(bases, members): etisserant@75: def generateXMLTextMethod(self, name, indent, extras = {}, derived = False): etisserant@75: ind1, ind2 = getIndent(indent, name) etisserant@75: if not derived: etisserant@75: text = ind1 + "<%s"%name etisserant@75: else: etisserant@75: text = "" etisserant@75: if len(bases) > 0: etisserant@75: base_extras = {} etisserant@75: if "order" in members.keys(): etisserant@75: order = members["order"] etisserant@75: else: etisserant@75: order = [] etisserant@75: if "choice_content" in members.keys() and "choice_content" not in order: etisserant@75: order.append("choice_content") etisserant@75: if "multichoice_content" in members.keys() and "multichoice_content" not in order: etisserant@75: order.append("multichoice_content") etisserant@75: size = 0 etisserant@75: first = True etisserant@75: for attr, value in extras.items(): etisserant@75: if not first and not self.singleLineAttributes: etisserant@75: text += "\n%s"%(ind2) etisserant@75: text += " %s=\"%s\""%(attr, ComputeValue(value)) etisserant@75: first = False etisserant@75: for attr, values in members.items(): etisserant@75: if attr in ["order","choice_content","multichoice_content"]: lbessard@2: pass etisserant@75: elif attr in ["enum","limit"]: etisserant@75: if not derived: etisserant@75: text += ">%s\n"%(ComputeValue(self.value),name) etisserant@75: else: etisserant@75: text += ComputeValue(self.value) etisserant@75: return text etisserant@75: elif values[1] == "attribute": etisserant@75: value = getattr(self, attr, None) etisserant@75: if value == "": etisserant@75: value = None etisserant@75: if values[2] != "optional" or value != None: etisserant@75: if not first and not self.singleLineAttributes: etisserant@75: text += "\n%s"%(ind2) etisserant@75: if values[0].startswith("cls"): etisserant@75: if len(bases) > 0: etisserant@75: base_extras[attr] = value.getValue() etisserant@75: else: etisserant@75: text += " %s=\"%s\""%(attr, ComputeValue(value.getValue())) etisserant@75: else: etisserant@75: if len(bases) > 0: etisserant@75: base_extras[attr] = value etisserant@75: else: etisserant@75: text += " %s=\"%s\""%(attr, ComputeValue(value)) etisserant@75: first = False etisserant@75: if len(bases) > 0: etisserant@75: first, new_text = bases[0].generateXMLText(self, name, indent, base_extras, True) etisserant@75: text += new_text etisserant@75: else: etisserant@75: first = True etisserant@75: ind3, ind4 = getIndent(indent + 1, name) etisserant@75: for attr in order: etisserant@75: value = getattr(self, attr, None) etisserant@75: if attr == "choice_content": etisserant@75: if self.content: etisserant@75: if first: etisserant@75: text += ">\n" etisserant@75: first = False etisserant@75: value_type = members[attr][self.content["name"]] etisserant@75: if value_type.startswith("bse:"): etisserant@75: if value_type.endswith("[]"): etisserant@75: for content in self.content["value"]: etisserant@75: text += ind1 + "<%s>%s\n"%(self.content["name"], ComputeValue(content), self.content["name"]) etisserant@75: else: etisserant@75: text += ind1 + "<%s>%s\n"%(self.content["name"], ComputeValue(self.content["value"]), self.content["name"]) etisserant@75: elif value_type.endswith("[]"): etisserant@75: for content in self.content["value"]: etisserant@75: text += content.generateXMLText(self.content["name"], indent + 1) etisserant@75: else: etisserant@75: text += self.content["value"].generateXMLText(self.content["name"], indent + 1) lbessard@2: elif attr == "multichoice_content": etisserant@75: if len(self.content) > 0: etisserant@75: for element in self.content: lbessard@2: if first: lbessard@2: text += ">\n" lbessard@2: first = False etisserant@75: value_type = members[attr][element["name"]] lbessard@2: if value_type.startswith("bse:"): etisserant@75: text += ind1 + "<%s>%s\n"%(element["name"], ComputeValue(element["value"]), element["name"]) lbessard@2: else: etisserant@75: text += element["value"].generateXMLText(element["name"], indent + 1) etisserant@75: elif members[attr][2] != "optional" or value != None: etisserant@75: if members[attr][0].endswith("[]"): etisserant@75: if first and len(value) > 0: etisserant@75: text += ">\n" etisserant@75: first = False etisserant@75: for element in value: etisserant@75: if members[attr][0].startswith("bse:"): etisserant@75: text += ind3 + "<%s>%s\n"%(attr, ComputeValue(element), attr) etisserant@75: else: etisserant@75: text += element.generateXMLText(attr, indent + 1) etisserant@75: else: etisserant@75: if first: etisserant@75: text += ">\n" etisserant@75: first = False etisserant@75: if members[attr][0].startswith("bse:"): etisserant@75: text += ind3 + "<%s>%s\n"%(attr, ComputeValue(value), attr) lbessard@2: else: etisserant@75: text += getattr(self, attr).generateXMLText(attr, indent + 1) etisserant@75: if not derived: etisserant@75: if first: etisserant@75: text += "/>\n" etisserant@75: else: etisserant@75: text += ind1 + "\n"%(name) etisserant@75: return text etisserant@75: else: etisserant@75: return first, text etisserant@75: return generateXMLTextMethod etisserant@75: etisserant@75: etisserant@75: def generategetElementAttributes(bases, members): etisserant@75: def getElementAttributes(self): etisserant@75: attr_list = [] etisserant@75: for attr, values in members.items(): etisserant@75: if attr in ["order","choice_content","multichoice_content"]: etisserant@75: pass etisserant@75: elif values[1] == "attribute": etisserant@75: if values[2] == "required": etisserant@75: require = True lbessard@2: else: etisserant@75: require = False etisserant@75: attr_hash ={"name": attr,"type": values[0] ,"value": getattr(self, attr, "") ,"require": require} etisserant@75: attr_list.append(attr_hash) etisserant@75: return attr_list etisserant@75: return getElementAttributes etisserant@75: etisserant@75: """ etisserant@75: Methods that generates the different methods for setting and getting the attributes etisserant@75: """ lbessard@76: def generateInitMethod(bases, members, classes): etisserant@75: def initMethod(self): etisserant@75: for base in bases: etisserant@75: base.__init__(self) etisserant@75: for attr, initial in members.items(): lbessard@76: setattr(self, attr, eval(initial, globals().update(classes))) etisserant@75: return initMethod etisserant@75: etisserant@75: def generateSetMethod(attr, attr_type): etisserant@75: def setMethod(self, value): etisserant@75: setattr(self, attr, value) etisserant@75: return setMethod etisserant@75: etisserant@75: def generateSetChoiceMethod(choice_type): etisserant@75: def setChoiceMethod(self, name, value): etisserant@75: self.content = {"name":name,"value":value} etisserant@75: return setChoiceMethod etisserant@75: etisserant@75: def generateSetEnumMethod(enum, attr_type): etisserant@75: def setEnumMethod(self, value): etisserant@75: if value in enum: etisserant@75: self.value = value etisserant@75: else: etisserant@75: raise ValueError, "%s is not a valid value. Must be in %s"%(value, str(enum)) etisserant@75: return setEnumMethod etisserant@75: etisserant@75: def generateSetLimitMethod(limit, attr_type): etisserant@75: def setMethod(self, value): etisserant@75: if "min" in limit and value < limit["min"]: etisserant@75: raise ValueError, "%s is not a valid value. Must be greater than %d"%(value, limit["min"]) etisserant@75: elif "max" in limit and value > limit["max"]: etisserant@75: raise ValueError, "%s is not a valid value. Must be smaller than %d"%(value, limit["max"]) etisserant@75: else: etisserant@75: self.value = value etisserant@75: return setMethod etisserant@75: etisserant@75: def generateGetMethod(attr): etisserant@75: def getMethod(self): etisserant@75: return getattr(self, attr, None) etisserant@75: return getMethod etisserant@75: lbessard@76: def generateAddMethod(attr, initial, classes): etisserant@75: def addMethod(self): lbessard@76: setattr(self, attr, eval(initial, globals().update(classes))) etisserant@75: return addMethod etisserant@75: etisserant@75: def generateDeleteMethod(attr): etisserant@75: def deleteMethod(self): etisserant@75: setattr(self, attr, None) etisserant@75: return deleteMethod etisserant@75: etisserant@75: def generateAppendMethod(attr, attr_type): etisserant@75: def appendMethod(self, value): etisserant@75: getattr(self, attr).append(value) etisserant@75: return appendMethod etisserant@75: etisserant@75: def generateInsertMethod(attr, attr_type): etisserant@75: def insertMethod(self, index, value): etisserant@75: getattr(self, attr).insert(index, value) etisserant@75: return insertMethod etisserant@75: etisserant@75: def generateAppendChoiceMethod(choice_types): etisserant@75: def appendMethod(self, name, value): etisserant@75: self.content.append({"name":name,"value":value}) etisserant@75: return appendMethod etisserant@75: etisserant@75: def generateInsertChoiceMethod(choice_types): etisserant@75: def insertMethod(self, index, name, value): etisserant@75: self.content.insert(index, {"name":name,"value":value}) etisserant@75: return insertMethod etisserant@75: etisserant@75: def generateRemoveMethod(attr): etisserant@75: def removeMethod(self, index): etisserant@75: getattr(self, attr).pop(index) etisserant@75: return removeMethod etisserant@75: etisserant@75: def generateCountMethod(attr): etisserant@75: def countMethod(self): etisserant@75: return len(getattr(self, attr)) etisserant@75: return countMethod etisserant@75: etisserant@75: """ lbessard@76: This function generate the classes from a class factory lbessard@76: """ lbessard@76: def GenerateClasses(factory, declare = False): lbessard@76: ComputedClasses, ComputedTypes = factory.CreateClasses() lbessard@76: if declare: lbessard@76: for ClassName, Class in pluginClasses.items(): lbessard@76: sys._getframe(1).f_locals[ClassName] = Class lbessard@76: for TypeName, Type in pluginTypes.items(): lbessard@76: sys._getframe(1).f_locals[TypeName] = Type lbessard@76: return ComputedClasses, ComputedTypes lbessard@76: lbessard@76: """ lbessard@76: This function opens the xsd file and generate the classes from the xml tree lbessard@76: """ lbessard@76: def GenerateClassesFromXSD(filename, declare = False): lbessard@76: xsdfile = open(filename, 'r') lbessard@76: factory = ClassFactory(minidom.parse(xsdfile)) lbessard@76: xsdfile.close() lbessard@76: return GenerateClasses(factory, declare) lbessard@76: lbessard@76: """ lbessard@76: This function generate the classes from the xsd given as a string lbessard@76: """ lbessard@76: def GenerateClassesFromXSDstring(xsdstring, declare = False): lbessard@76: factory = ClassFactory(minidom.parseString(xsdstring)) lbessard@76: return GenerateClasses(factory, declare) lbessard@76: lbessard@76: