Changed the way class are generated, using classobj from "new" module, instead of type inheritence.
#!/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) 2007: 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
#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 *
from new import classobj
"""
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}(?:.[0-9]*)?)')
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}(?:.[0-9]*)?)')
"""
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 generate the classes from the xsd given as a string
"""
def GenerateClassesFromXSDstring(xsdstring):
Generate_xsd_classes(minidom.parseString(xsdstring), None)
"""
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:
text = ""
for node in attr.childNodes:
if node.nodeName != "#text":
text += node.data.encode()
return text
"""
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,0)"
elif type_compute == "date":
return DateType, "date(1,1,1)"
elif type_compute == "dateTime":
return DateTimeType, "datetime(1,1,1,0,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:
values = result.groups()
time_values = [int(v) for v in values[:2]]
seconds = float(values[2])
time_values.extend([int(seconds), int((seconds % 1) * 1000000)])
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:
values = result.groups()
datetime_values = [int(v) for v in values[:5]]
seconds = float(values[5])
datetime_values.extend([int(seconds), int((seconds % 1) * 1000000)])
return datetime(*datetime_values)
else:
raise ValueError, "\"%s\" is not a valid datetime!"%value
else:
print "Can't affect: %s"%type_compute
return None
"""
Method that generate the method for loading an xml tree by following the
attributes list defined
"""
def generateLoadXMLTree(bases, members, 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 members.keys() or "limit" in members.keys():
attr_value = GetAttributeValue(tree)
attr_type = members["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 members.keys():
attr_type, xml_type, write_type = members[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 members.keys() and name in members["choice_content"].keys():
attr_type = members["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 members.keys() and name in members["multichoice_content"].keys():
attr_type = members["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 members.keys():
attr_type, xml_type, write_type = members[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(bases, members):
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 members.keys():
order = members["order"]
else:
order = []
if "choice_content" in members.keys() and "choice_content" not in order:
order.append("choice_content")
if "multichoice_content" in members.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 members.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 value == "":
value = 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 = members[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 = members[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 members[attr][2] != "optional" or value != None:
if members[attr][0].endswith("[]"):
if first and len(value) > 0:
text += ">\n"
first = False
for element in value:
if members[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 members[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
def generategetElementAttributes(bases, members):
def getElementAttributes(self):
attr_list = []
for attr, values in members.items():
if attr in ["order","choice_content","multichoice_content"]:
pass
elif values[1] == "attribute":
if values[2] == "required":
require = True
else:
require = False
attr_hash ={"name": attr,"type": values[0] ,"value": getattr(self, attr, "") ,"require": require}
attr_list.append(attr_hash)
return attr_list
return getElementAttributes
"""
Methods that generates the different methods for setting and getting the attributes
"""
def generateInitMethod(bases, members, user_classes):
def initMethod(self):
for base in bases:
base.__init__(self)
for attr, initial in members.items():
setattr(self, attr, eval(initial, globals().update(user_classes)))
return initMethod
def generateSetMethod(attr, attr_type):
def setMethod(self, value):
setattr(self, attr, value)
return setMethod
def generateSetChoiceMethod(choice_type):
def setChoiceMethod(self, name, value):
self.content = {"name":name,"value":value}
return setChoiceMethod
def generateSetEnumMethod(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(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(attr):
def getMethod(self):
return getattr(self, attr, None)
return getMethod
def generateAddMethod(attr, initial, user_classes):
def addMethod(self):
setattr(self, attr, eval(initial, globals().update(user_classes)))
return addMethod
def generateDeleteMethod(attr):
def deleteMethod(self):
setattr(self, attr, None)
return deleteMethod
def generateAppendMethod(attr, attr_type):
def appendMethod(self, value):
getattr(self, attr).append(value)
return appendMethod
def generateInsertMethod(attr, attr_type):
def insertMethod(self, index, value):
getattr(self, attr).insert(index, value)
return insertMethod
def generateAppendChoiceMethod(choice_types):
def appendMethod(self, name, value):
self.content.append({"name":name,"value":value})
return appendMethod
def generateInsertChoiceMethod(choice_types):
def insertMethod(self, index, name, value):
self.content.insert(index, {"name":name,"value":value})
return insertMethod
def generateRemoveMethod(attr):
def removeMethod(self, index):
getattr(self, attr).pop(index)
return removeMethod
def generateCountMethod(attr):
def countMethod(self):
return len(getattr(self, attr))
return countMethod
"""
This is the Metaclass for PLCOpen element classes. It generates automatically
the basic useful methods for manipulate the differents attributes of the classes
"""
def MetaClass(name, bases, members, user_classes):
classmembers = {}
initialValues = {}
for attr, values in members.items():
if attr in ["order", "basetype"]:
pass
# Class is a enumerated type
elif attr == "enum":
value_type, initial = GetTypeInitialValue(members["basetype"])
initialValues["value"] = "\"%s\""%values[0]
classmembers["value"]= values[0]
classmembers["setValue"]= generateSetEnumMethod(values, value_type)
classmembers["getValue"]= generateGetMethod("value")
# Class is a limited type
elif attr == "limit":
value_type, initial = GetTypeInitialValue(members["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
classmembers["value"]= initial
classmembers["setValue"]= generateSetLimitMethod(values, value_type)
classmembers["getValue"]= generateGetMethod("value")
# Class has an attribute that can have different value types
elif attr == "choice_content":
classmembers["content"]= None
initialValues["content"] = "None"
classmembers["deleteContent"]= generateDeleteMethod("content")
classmembers["setContent"]= generateSetChoiceMethod(values)
classmembers["getContent"]= generateGetMethod("content")
elif attr == "multichoice_content":
classmembers["content"]= []
initialValues["content"] = "[]"
classmembers["appendContent"]= generateAppendChoiceMethod(values)
classmembers["insertContent"]= generateInsertChoiceMethod(values)
classmembers["removeContent"]= generateRemoveMethod("content")
classmembers["countContent"]= generateCountMethod("content")
classmembers["setContent"]= generateSetMethod("content", ListType)
classmembers["getContent"]= generateGetMethod("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("[]"):
classmembers[attr]= []
initialValues[attr] = "[]"
classmembers["append"+attrname] = generateAppendMethod(attr, value_type)
classmembers["insert"+attrname] = generateInsertMethod(attr, value_type)
classmembers["remove"+attrname] = generateRemoveMethod(attr)
classmembers["count"+attrname] = generateCountMethod(attr)
classmembers["set"+attrname] = generateSetMethod(attr, ListType)
else:
if write_type == "optional":
classmembers[attr] = None
initialValues[attr] = "None"
classmembers["add"+attrname] = generateAddMethod(attr, initial, user_classes)
classmembers["delete"+attrname] = generateDeleteMethod(attr)
else:
classmembers[attr] = initial
initialValues[attr] = initial
classmembers["set"+attrname] = generateSetMethod(attr, value_type)
classmembers["get"+attrname] = generateGetMethod(attr)
classmembers["__init__"]= generateInitMethod(bases, initialValues, user_classes)
classmembers["loadXMLTree"]= generateLoadXMLTree(bases, members, user_classes)
classmembers["generateXMLText"]= generateGenerateXMLText(bases, members)
classmembers["getElementAttributes"]= generategetElementAttributes(bases, members)
classmembers["singleLineAttributes"]= True
return classobj(name, bases, classmembers)
"""
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
members = {}
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 value:
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
members[attribute] = element_types
else:
members[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(classname, tuple(bases), members, 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
def DeclareXSDClass(XSDstring):
pluginClasses = {}
pluginTypes = {}
GenerateClassesFromXSDstring(XSDstring)
CreateClasses(pluginClasses, pluginTypes)
for ClassName, Class in pluginClasses.items():
sys._getframe(1).f_locals[ClassName] = Class