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