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@151: import sys, re, datetime lbessard@2: from types import * etisserant@75: from new import classobj lbessard@2: lbessard@151: LANGUAGES = ["en-US", "fr-FR", "en", "fr"] lbessard@151: lbessard@151: """ lbessard@151: Regular expression models for check all kind of string lbessard@151: """ lbessard@151: Name_model = re.compile('([a-zA-Z_\:][\w\.\-\:]*)$') lbessard@151: Names_model = re.compile('([a-zA-Z_\:][\w\.\-\:]*(?: [a-zA-Z_\:][\w\.\-\:]*)*)$') lbessard@151: NMToken_model = re.compile('([\w\.\-\:]*)$') lbessard@151: NMTokens_model = re.compile('([\w\.\-\:]*(?: [\w\.\-\:]*)*)$') lbessard@151: QName_model = re.compile('((?:[a-zA-Z_][\w]*:)?[a-zA-Z_][\w]*)$') lbessard@151: QNames_model = re.compile('((?:[a-zA-Z_][\w]*:)?[a-zA-Z_][\w]*(?: (?:[a-zA-Z_][\w]*:)?[a-zA-Z_][\w]*)*)$') lbessard@151: NCName_model = re.compile('([a-zA-Z_][\w]*)$') lbessard@151: URI_model = re.compile('((?:http://|/)?(?:[\w.]*/?)*)$') lbessard@151: lbessard@151: ONLY_ANNOTATION = re.compile("((?:annotation )?)") lbessard@151: lbessard@2: """ lbessard@2: Regular expression models for extracting dates and times from a string lbessard@2: """ lbessard@151: time_model = re.compile('([0-9]{2}):([0-9]{2}):([0-9]{2}(?:\.[0-9]*)?)(?:Z)?$') lbessard@151: date_model = re.compile('([0-9]{4})-([0-9]{2})-([0-9]{2})((?:[\-\+][0-9]{2}:[0-9]{2})|Z)?$') lbessard@151: 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]*)?)((?:[\-\+][0-9]{2}:[0-9]{2})|Z)?$') lbessard@151: lbessard@151: class xml_timezone(datetime.tzinfo): lbessard@116: lbessard@116: def SetOffset(self, offset): lbessard@116: if offset == "Z": lbessard@116: self.__offset = timedelta(minutes = 0) lbessard@116: self.__name = "UTC" lbessard@116: else: lbessard@116: sign = {"-" : -1, "+" : 1}[offset[0]] lbessard@116: hours, minutes = [int(val) for val in offset[1:].split(":")] lbessard@116: self.__offset = timedelta(minutes = sign * (hours * 60 + minutes)) lbessard@116: self.__name = "" lbessard@116: lbessard@116: def utcoffset(self, dt): lbessard@116: return self.__offset lbessard@116: lbessard@116: def tzname(self, dt): lbessard@116: return self.__name lbessard@116: lbessard@116: def dst(self, dt): lbessard@116: return ZERO lbessard@2: lbessard@151: [SYNTAXELEMENT, SYNTAXATTRIBUTE, SIMPLETYPE, COMPLEXTYPE, COMPILEDCOMPLEXTYPE, lbessard@151: ATTRIBUTESGROUP, ELEMENTSGROUP, ATTRIBUTE, ELEMENT, CHOICE, ANY, TAG lbessard@151: ] = range(12) lbessard@151: lbessard@151: def NotSupportedYet(type): lbessard@151: """ lbessard@151: Function that generates a function that point out to user that datatype asked lbessard@151: are not yet supported by xmlclass lbessard@151: @param type: data type lbessard@151: @return: function generated lbessard@151: """ lbessard@151: def GetUnknownValue(attr): lbessard@151: raise ValueError, "\"%s\" type isn't supported by \"xmlclass\" yet!"%type lbessard@151: return GetUnknownValue lbessard@90: 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@151: lbessard@151: def GetAttributeValue(attr, extract = True): lbessard@151: """ lbessard@151: Function that extracts data from a tree node lbessard@151: @param attr: tree node containing data to extract lbessard@151: @param extract: attr is a tree node or not lbessard@151: @return: data extracted as string lbessard@151: """ lbessard@151: if not extract: lbessard@151: return attr lbessard@2: if len(attr.childNodes) == 1: lbessard@2: return attr.childNodes[0].data.encode() lbessard@2: else: lbessard@151: # content is a CDATA 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@151: lbessard@151: def GetNormalizedString(attr, extract = True): lbessard@151: """ lbessard@151: Function that normalizes a string according to XML 1.0. Replace tabulations, lbessard@151: line feed and carriage return by white space lbessard@151: @param attr: tree node containing data to extract or data to normalize lbessard@151: @param extract: attr is a tree node or not lbessard@151: @return: data normalized as string lbessard@151: """ lbessard@151: if extract: lbessard@151: return GetAttributeValue(attr).replace("\n", " ").replace("\t", " ") lbessard@2: else: lbessard@151: return attr.replace("\n", " ").replace("\t", " ") lbessard@151: lbessard@151: lbessard@151: def GetToken(attr, extract = True): lbessard@151: """ lbessard@151: Function that tokenizes a string according to XML 1.0. Remove any leading and lbessard@151: trailing white space and replace internal sequence of two or more spaces by lbessard@151: only one white space lbessard@151: @param attr: tree node containing data to extract or data to tokenize lbessard@151: @param extract: attr is a tree node or not lbessard@151: @return: data tokenized as string lbessard@151: """ lbessard@151: return " ".join([part for part in GetNormalizedString(attr, extract).split(" ") if part]) lbessard@151: lbessard@151: lbessard@151: def GetHexInteger(attr, extract = True): lbessard@151: """ lbessard@151: Function that extracts an hexadecimal integer from a tree node or a string lbessard@151: @param attr: tree node containing data to extract or data as a string lbessard@151: @param extract: attr is a tree node or not lbessard@151: @return: data as an integer lbessard@151: """ lbessard@151: if extract: lbessard@151: value = GetAttributeValue(attr) lbessard@151: else: lbessard@151: value = attr lbessard@151: try: lbessard@151: return int(value, 16) lbessard@151: except: lbessard@151: raise ValueError, "\"%s\" isn't a valid hexadecimal integer!"%value lbessard@151: lbessard@151: lbessard@151: def GenerateIntegerExtraction(minInclusive = None, maxInclusive = None, minExclusive = None, maxExclusive = None): lbessard@151: """ lbessard@151: Function that generates an extraction function for integer defining min and max lbessard@151: of integer value lbessard@151: @param minInclusive: inclusive minimum lbessard@151: @param maxInclusive: inclusive maximum lbessard@151: @param minExclusive: exclusive minimum lbessard@151: @param maxExclusive: exclusive maximum lbessard@151: @return: function generated lbessard@151: """ lbessard@151: def GetInteger(attr, extract = True): lbessard@151: """ lbessard@151: Function that extracts an integer from a tree node or a string lbessard@151: @param attr: tree node containing data to extract or data as a string lbessard@151: @param extract: attr is a tree node or not lbessard@151: @return: data as an integer lbessard@151: """ lbessard@151: lbessard@151: if extract: lbessard@151: value = GetAttributeValue(attr) lbessard@151: else: lbessard@151: value = attr lbessard@151: try: lbessard@151: # TODO: permit to write value like 1E2 lbessard@151: value = int(value) lbessard@151: except: lbessard@151: raise ValueError, "\"%s\" isn't a valid integer!"%value lbessard@151: if minInclusive is not None and value < minInclusive: lbessard@151: raise ValueError, "%d isn't greater or equal to %d!"%(value, minInclusive) lbessard@151: if maxInclusive is not None and value > maxInclusive: lbessard@151: raise ValueError, "%d isn't lesser or equal to %d!"%(value, maxInclusive) lbessard@151: if minExclusive is not None and value <= minExclusive: lbessard@151: raise ValueError, "%d isn't greater than %d!"%(value, minExclusive) lbessard@151: if maxExclusive is not None and value >= maxExclusive: lbessard@151: raise ValueError, "%d isn't lesser than %d!"%(value, maxExclusive) lbessard@2: return value lbessard@151: return GetInteger lbessard@151: lbessard@151: lbessard@151: def GenerateFloatExtraction(type, extra_values = []): lbessard@151: """ lbessard@151: Function that generates an extraction function for float lbessard@151: @param type: name of the type of float lbessard@151: @return: function generated lbessard@151: """ lbessard@151: def GetFloat(attr, extract = True): lbessard@151: """ lbessard@151: Function that extracts a float from a tree node or a string lbessard@151: @param attr: tree node containing data to extract or data as a string lbessard@151: @param extract: attr is a tree node or not lbessard@151: @return: data as a float lbessard@151: """ lbessard@151: if extract: lbessard@151: value = GetAttributeValue(attr) lbessard@151: else: lbessard@151: value = attr lbessard@151: try: lbessard@151: if value in extra_values: lbessard@151: return value lbessard@151: return float(value) lbessard@151: except: lbessard@151: raise ValueError, "\"%s\" isn't a valid %s!"%(value, type) lbessard@151: return GetFloat lbessard@151: lbessard@151: lbessard@151: def GetBoolean(attr, extract = True): lbessard@151: """ lbessard@151: Function that extracts a boolean from a tree node or a string lbessard@151: @param attr: tree node containing data to extract or data as a string lbessard@151: @param extract: attr is a tree node or not lbessard@151: @return: data as a boolean lbessard@151: """ lbessard@151: if extract: lbessard@151: value = GetAttributeValue(attr) lbessard@2: else: lbessard@151: value = attr lbessard@151: if value == "true" or value == "1": lbessard@151: return True lbessard@151: elif value == "false" or value == "0": lbessard@151: return False lbessard@151: else: lbessard@151: raise ValueError, "\"%s\" isn't a valid boolean!"%value lbessard@151: lbessard@151: lbessard@151: def GetTime(attr, extract = True): lbessard@151: """ lbessard@151: Function that extracts a time from a tree node or a string lbessard@151: @param attr: tree node containing data to extract or data as a string lbessard@151: @param extract: attr is a tree node or not lbessard@151: @return: data as a time lbessard@151: """ lbessard@151: if extract: lbessard@151: result = time_model.match(GetAttributeValue(attr)) lbessard@151: else: lbessard@151: result = time_model.match(attr) lbessard@151: if result: lbessard@151: values = result.groups() lbessard@151: time_values = [int(v) for v in values[:2]] lbessard@151: seconds = float(values[2]) lbessard@151: time_values.extend([int(seconds), int((seconds % 1) * 1000000)]) lbessard@151: return datetime.time(*time_values) lbessard@151: else: lbessard@151: raise ValueError, "\"%s\" is not a valid time!"%value lbessard@151: lbessard@151: lbessard@151: def GetDate(attr, extract = True): lbessard@151: """ lbessard@151: Function that extracts a date from a tree node or a string lbessard@151: @param attr: tree node containing data to extract or data as a string lbessard@151: @param extract: attr is a tree node or not lbessard@151: @return: data as a date lbessard@151: """ lbessard@151: if extract: lbessard@151: result = date_model.match(GetAttributeValue(attr)) lbessard@151: else: lbessard@151: result = date_model.match(attr) lbessard@151: if result: lbessard@151: values = result.groups() lbessard@151: date_values = [int(v) for v in values[:3]] lbessard@151: if values[3] is not None: lbessard@151: tz = xml_timezone() lbessard@151: tz.SetOffset(values[3]) lbessard@151: date_values.append(tz) lbessard@151: return datetime.date(*date_values) lbessard@151: else: lbessard@151: raise ValueError, "\"%s\" is not a valid date!"%value lbessard@151: lbessard@151: lbessard@151: def GetDateTime(attr, extract = True): lbessard@151: """ lbessard@151: Function that extracts date and time from a tree node or a string lbessard@151: @param attr: tree node containing data to extract or data as a string lbessard@151: @param extract: attr is a tree node or not lbessard@151: @return: data as date and time lbessard@151: """ lbessard@151: if extract: lbessard@151: result = datetime_model.match(GetAttributeValue(attr)) lbessard@151: else: lbessard@151: result = datetime_model.match(attr) lbessard@151: if result: lbessard@151: values = result.groups() lbessard@151: datetime_values = [int(v) for v in values[:5]] lbessard@151: seconds = float(values[5]) lbessard@151: datetime_values.extend([int(seconds), int((seconds % 1) * 1000000)]) lbessard@151: if values[6] is not None: lbessard@151: tz = xml_timezone() lbessard@151: tz.SetOffset(values[6]) lbessard@151: datetime_values.append(tz) lbessard@151: return datetime.datetime(*datetime_values) lbessard@151: else: lbessard@151: raise ValueError, "\"%s\" is not a valid datetime!"%value lbessard@151: lbessard@151: lbessard@151: def GenerateModelNameExtraction(type, model): lbessard@151: """ lbessard@151: Function that generates an extraction function for string matching a model lbessard@151: @param type: name of the data type lbessard@151: @param model: model that data must match lbessard@151: @return: function generated lbessard@151: """ lbessard@151: def GetModelName(attr, extract = True): lbessard@151: """ lbessard@151: Function that extracts a string from a tree node or not and check that lbessard@151: string extracted or given match the model lbessard@151: @param attr: tree node containing data to extract or data as a string lbessard@151: @param extract: attr is a tree node or not lbessard@151: @return: data as a string if matching lbessard@151: """ lbessard@151: if extract: lbessard@151: value = GetAttributeValue(attr) lbessard@151: else: lbessard@151: value = attr lbessard@151: result = model.match(value) lbessard@151: if not result: lbessard@151: raise ValueError, "\"%s\" is not a valid %s!"%(value, type) lbessard@151: return value lbessard@151: return GetModelName lbessard@151: lbessard@151: lbessard@151: def GenerateLimitExtraction(min = None, max = None, unbounded = True): lbessard@151: """ lbessard@151: Function that generates an extraction function for integer defining min and max lbessard@151: of integer value lbessard@151: @param min: minimum limit value lbessard@151: @param max: maximum limit value lbessard@151: @param unbounded: value can be "unbounded" or not lbessard@151: @return: function generated lbessard@151: """ lbessard@151: def GetLimit(attr, extract = True): lbessard@151: """ lbessard@151: Function that extracts a string from a tree node or not and check that lbessard@151: string extracted or given is in a list of values lbessard@151: @param attr: tree node containing data to extract or data as a string lbessard@151: @param extract: attr is a tree node or not lbessard@151: @return: data as a string lbessard@151: """ lbessard@151: if extract: lbessard@151: value = GetAttributeValue(attr) lbessard@151: else: lbessard@151: value = attr lbessard@151: if value == "unbounded": lbessard@151: if unbounded: lbessard@151: return value lbessard@151: else: lbessard@151: raise "\"%s\" isn't a valid value for this member limit!"%value lbessard@151: try: lbessard@151: limit = int(value) lbessard@151: except: lbessard@151: raise "\"%s\" isn't a valid value for this member limit!"%value lbessard@151: if limit < 0: lbessard@151: raise "\"%s\" isn't a valid value for this member limit!"%value lbessard@151: elif min is not None and limit < min: lbessard@151: raise "\"%s\" isn't a valid value for this member limit!"%value lbessard@151: elif max is not None and limit > max: lbessard@151: raise "\"%s\" isn't a valid value for this member limit!"%value lbessard@151: return limit lbessard@151: return GetLimit lbessard@151: lbessard@151: lbessard@151: def GenerateEnumeratedExtraction(type, list): lbessard@151: """ lbessard@151: Function that generates an extraction function for enumerated values lbessard@151: @param type: name of the data type lbessard@151: @param list: list of possible values lbessard@151: @return: function generated lbessard@151: """ lbessard@151: def GetEnumerated(attr, extract = True): lbessard@151: """ lbessard@151: Function that extracts a string from a tree node or not and check that lbessard@151: string extracted or given is in a list of values lbessard@151: @param attr: tree node containing data to extract or data as a string lbessard@151: @param extract: attr is a tree node or not lbessard@151: @return: data as a string lbessard@151: """ lbessard@151: if extract: lbessard@151: value = GetAttributeValue(attr) lbessard@151: else: lbessard@151: value = attr lbessard@151: if value in list: lbessard@151: return value lbessard@151: else: lbessard@151: raise ValueError, "\"%s\" isn't a valid value for %s!"%(value, type) lbessard@151: return GetEnumerated lbessard@151: lbessard@151: lbessard@151: def GetNamespaces(attr, extract = True): lbessard@151: """ lbessard@151: Function that extracts a list of namespaces from a tree node or a string lbessard@151: @param attr: tree node containing data to extract or data as a string lbessard@151: @param extract: attr is a tree node or not lbessard@151: @return: list of namespaces lbessard@151: """ lbessard@151: if extract: lbessard@151: value = GetAttributeValue(attr) lbessard@151: else: lbessard@151: value = attr lbessard@151: if value == "": lbessard@151: return [] lbessard@151: elif value == "##any" or value == "##other": lbessard@151: namespaces = [value] lbessard@151: else: lbessard@151: namespaces = [] lbessard@151: for item in value.split(" "): lbessard@151: if item == "##targetNamespace" or item == "##local": lbessard@151: namespaces.append(item) lbessard@151: else: lbessard@151: result = URI_model.match(item) lbessard@151: if result is not None: lbessard@151: namespaces.append(item) lbessard@151: else: lbessard@151: raise ValueError, "\"%s\" isn't a valid value for namespace!"%value lbessard@151: return namespaces lbessard@151: lbessard@151: lbessard@151: def GenerateGetList(type, list): lbessard@151: """ lbessard@151: Function that generates an extraction function for a list of values lbessard@151: @param type: name of the data type lbessard@151: @param list: list of possible values lbessard@151: @return: function generated lbessard@151: """ lbessard@151: def GetLists(attr, extract = True): lbessard@151: """ lbessard@151: Function that extracts a list of values from a tree node or a string lbessard@151: @param attr: tree node containing data to extract or data as a string lbessard@151: @param extract: attr is a tree node or not lbessard@151: @return: list of values lbessard@151: """ lbessard@151: if extract: lbessard@151: value = GetAttributeValue(attr) lbessard@151: else: lbessard@151: value = attr lbessard@151: if value == "": lbessard@151: return [] lbessard@151: elif value == "#all": lbessard@151: return [value] lbessard@151: else: lbessard@151: values = [] lbessard@151: for item in value.split(" "): lbessard@151: if item in list: lbessard@151: values.append(item) lbessard@151: else: lbessard@151: raise ValueError, "\"%s\" isn't a valid value for %s!"%(value, type) lbessard@151: return values lbessard@151: return GetLists lbessard@151: lbessard@151: lbessard@151: def GenerateModelNameListExtraction(type, model): lbessard@151: """ lbessard@151: Function that generates an extraction function for list of string matching a model lbessard@151: @param type: name of the data type lbessard@151: @param model: model that list elements must match lbessard@151: @return: function generated lbessard@151: """ lbessard@151: def GetModelNameList(attr, extract = True): lbessard@151: """ lbessard@151: Function that extracts a list of string from a tree node or not and check lbessard@151: that all the items extracted match the model lbessard@151: @param attr: tree node containing data to extract or data as a string lbessard@151: @param extract: attr is a tree node or not lbessard@151: @return: data as a list of string if matching lbessard@151: """ lbessard@151: if extract: lbessard@151: value = GetAttributeValue(attr) lbessard@151: else: lbessard@151: value = attr lbessard@151: values = [] lbessard@151: for item in value.split(" "): lbessard@151: result = model.match(item) lbessard@151: if result is not None: lbessard@151: values.append(item) lbessard@151: else: lbessard@151: raise ValueError, "\"%s\" isn't a valid value for %s!"%(value, type) lbessard@151: return values lbessard@151: return GetModelNameList lbessard@151: lbessard@151: def GenerateAnyInfos(): lbessard@151: def ExtractAny(tree): lbessard@151: return tree.data.encode() lbessard@151: lbessard@151: def GenerateAny(value, name = None, indent = 0): lbessard@151: return "\n"%str(value) lbessard@151: lbessard@151: return { lbessard@151: "type" : COMPLEXTYPE, lbessard@151: "extract" : ExtractAny, lbessard@151: "generate" : GenerateAny, lbessard@151: "initial" : lambda: "", lbessard@151: "check" : lambda x: isinstance(x, (StringType, UnicodeType)) lbessard@151: } lbessard@151: lbessard@151: def GenerateTagInfos(name): lbessard@151: def ExtractTag(tree): lbessard@151: if len(tree._attrs) > 0: lbessard@151: raise ValueError, "\"%s\" musn't have attributes!"%name lbessard@151: if len(tree.childNodes) > 0: lbessard@151: raise ValueError, "\"%s\" musn't have children!"%name lbessard@2: return None lbessard@151: lbessard@151: def GenerateTag(value, name = None, indent = 0): lbessard@151: if name is not None: lbessard@151: ind1, ind2 = getIndent(indent, name) lbessard@151: return ind1 + "<%s/>\n"%name lbessard@151: else: lbessard@151: return "" lbessard@151: lbessard@151: return { lbessard@151: "type" : TAG, lbessard@151: "extract" : ExtractTag, lbessard@151: "generate" : GenerateTag, lbessard@151: "initial" : lambda: None, lbessard@151: "check" : lambda x: x == None lbessard@151: } lbessard@151: lbessard@151: def GenerateContentInfos(factory, choices): lbessard@151: def GetContentInitial(): lbessard@151: content_name, infos = choices[0] lbessard@151: if isinstance(infos["elmt_type"], (UnicodeType, StringType)): lbessard@151: namespace, name = DecomposeQualifiedName(infos["elmt_type"]) lbessard@151: infos["elmt_type"] = factory.GetQualifiedNameInfos(name, namespace) lbessard@151: if infos["maxOccurs"] == "unbounded" or infos["maxOccurs"] > 1: lbessard@151: return {"name" : content_name, "value" : map(infos["elmt_type"]["initial"], range(infos["minOccurs"]))} lbessard@151: else: lbessard@151: return {"name" : content_name, "value" : infos["elmt_type"]["initial"]()} lbessard@151: lbessard@151: def CheckContent(value): lbessard@151: for content_name, infos in choices: lbessard@151: if content_name == value["name"]: lbessard@151: if isinstance(infos["elmt_type"], (UnicodeType, StringType)): lbessard@151: namespace, name = DecomposeQualifiedName(infos["elmt_type"]) lbessard@151: infos["elmt_type"] = factory.GetQualifiedNameInfos(name, namespace) lbessard@151: if infos["maxOccurs"] == "unbounded" or infos["maxOccurs"] > 1: lbessard@151: if isinstance(value["value"], ListType) and infos["minOccurs"] <= len(value["value"]) <= infos["maxOccurs"]: lbessard@151: return reduce(lambda x, y: x and y, map(infos["elmt_type"]["check"], value["value"]), True) lbessard@151: else: lbessard@151: return infos["elmt_type"]["check"](value["value"]) lbessard@151: return False lbessard@151: lbessard@151: def ExtractContent(tree, content): lbessard@151: for content_name, infos in choices: lbessard@151: if content_name == tree.nodeName: lbessard@151: if isinstance(infos["elmt_type"], (UnicodeType, StringType)): lbessard@151: namespace, name = DecomposeQualifiedName(infos["elmt_type"]) lbessard@151: infos["elmt_type"] = factory.GetQualifiedNameInfos(name, namespace) lbessard@151: if infos["maxOccurs"] == "unbounded" or infos["maxOccurs"] > 1: lbessard@151: if isinstance(content, ListType) and len(content) > 0 and content[-1]["name"] == content_name: lbessard@151: content_item = content.pop(-1) lbessard@151: content_item["value"].append(infos["elmt_type"]["extract"](tree)) lbessard@151: return content_item lbessard@151: elif not isinstance(content, ListType) and content is not None and content["name"] == content_name: lbessard@151: return {"name" : content_name, "value" : content["value"] + [infos["elmt_type"]["extract"](tree)]} lbessard@151: else: lbessard@151: return {"name" : content_name, "value" : [infos["elmt_type"]["extract"](tree)]} lbessard@151: else: lbessard@151: return {"name" : content_name, "value" : infos["elmt_type"]["extract"](tree)} lbessard@151: raise ValueError, "Invalid element \"%s\" for content!"%tree.nodeName lbessard@151: lbessard@151: def GenerateContent(value, name = None, indent = 0): lbessard@151: for content_name, infos in choices: lbessard@151: if content_name == value["name"]: lbessard@151: if isinstance(infos["elmt_type"], (UnicodeType, StringType)): lbessard@151: namespace, name = DecomposeQualifiedName(infos["elmt_type"]) lbessard@151: infos["elmt_type"] = factory.GetQualifiedNameInfos(name, namespace) lbessard@151: if infos["maxOccurs"] == "unbounded" or infos["maxOccurs"] > 1: lbessard@151: text = "" lbessard@151: for item in value["value"]: lbessard@151: text += infos["elmt_type"]["generate"](item, content_name, indent) lbessard@151: return text lbessard@151: else: lbessard@151: return infos["elmt_type"]["generate"](value["value"], content_name, indent) lbessard@151: return "" lbessard@151: lbessard@151: return { lbessard@151: "initial" : GetContentInitial, lbessard@151: "check" : CheckContent, lbessard@151: "extract" : ExtractContent, lbessard@151: "generate" : GenerateContent lbessard@151: } lbessard@151: lbessard@151: #------------------------------------------------------------------------------- lbessard@151: # Structure extraction functions lbessard@151: #------------------------------------------------------------------------------- lbessard@151: lbessard@151: lbessard@151: def DecomposeQualifiedName(name): lbessard@151: result = QName_model.match(name) lbessard@151: if not result: lbessard@151: raise ValueError, "\"%s\" isn't a valid QName value!"%name lbessard@151: parts = result.groups()[0].split(':') lbessard@151: if len(parts) == 1: lbessard@151: return None, parts[0] lbessard@151: return parts lbessard@151: lbessard@151: def GenerateElement(element_name, attributes, elements_model, accept_text = False): lbessard@151: def ExtractElement(factory, node): lbessard@151: attrs = factory.ExtractNodeAttrs(element_name, node, attributes) lbessard@151: children_structure = "" lbessard@151: children_infos = [] lbessard@151: children = [] lbessard@151: for child in node.childNodes: lbessard@151: if child.nodeName not in ["#comment", "#text"]: lbessard@151: namespace, childname = DecomposeQualifiedName(child.nodeName) lbessard@151: children_structure += "%s "%childname lbessard@151: result = elements_model.match(children_structure) lbessard@151: if not result: lbessard@151: raise ValueError, "Invalid structure for \"%s\" children!. First element invalid."%node.nodeName lbessard@151: valid = result.groups()[0] lbessard@151: if len(valid) < len(children_structure): lbessard@151: raise ValueError, "Invalid structure for \"%s\" children!. Element number %d invalid."%(node.nodeName, len(valid.split(" ")) - 1) lbessard@151: for child in node.childNodes: lbessard@151: if child.nodeName != "#comment" and (accept_text or child.nodeName != "#text"): lbessard@151: if child.nodeName == "#text": lbessard@151: children.append(GetAttributeValue(node)) lbessard@151: else: lbessard@151: namespace, childname = DecomposeQualifiedName(child.nodeName) lbessard@151: infos = factory.GetQualifiedNameInfos(childname, namespace) lbessard@151: if infos["type"] != SYNTAXELEMENT: lbessard@151: raise ValueError, "\"%s\" can't be a member child!"%name lbessard@151: if element_name in infos["extract"]: lbessard@151: children.append(infos["extract"][element_name](factory, child)) lbessard@151: else: lbessard@151: children.append(infos["extract"]["default"](factory, child)) lbessard@151: return node.nodeName, attrs, children lbessard@151: return ExtractElement lbessard@151: lbessard@151: lbessard@151: """ lbessard@151: Class that generate class from an XML Tree lbessard@76: """ lbessard@76: class ClassFactory: lbessard@76: lbessard@151: def __init__(self, document, debug = False): lbessard@151: self.Document = document lbessard@151: self.Debug = debug lbessard@76: lbessard@76: # Dictionary for stocking Classes and Types definitions created from the XML tree lbessard@76: self.XMLClassDefinitions = {} lbessard@76: lbessard@151: self.DefinedNamespaces = {} lbessard@151: self.Namespaces = {} lbessard@151: self.SchemaNamespace = None lbessard@151: self.TargetNamespace = None lbessard@151: lbessard@151: self.CurrentCompilations = [] lbessard@151: lbessard@76: # Dictionaries for stocking Classes and Types generated lbessard@151: self.ComputeAfter = [] lbessard@76: self.ComputedClasses = {} lbessard@76: self.AlreadyComputed = {} lbessard@76: lbessard@151: def GetQualifiedNameInfos(self, name, namespace = None, canbenone = False): lbessard@151: if namespace is None: lbessard@151: if name in self.Namespaces[self.SchemaNamespace]: lbessard@151: return self.Namespaces[self.SchemaNamespace][name] lbessard@151: for space, elements in self.Namespaces.items(): lbessard@151: if space != self.SchemaNamespace and name in elements: lbessard@151: return elements[name] lbessard@151: parts = name.split("_", 1) lbessard@151: if len(parts) > 1: lbessard@151: group = self.GetQualifiedNameInfos(parts[0], namespace) lbessard@151: if group is not None and group["type"] == ELEMENTSGROUP: lbessard@151: elements = [] lbessard@151: if "elements" in group: lbessard@151: elements = group["elements"] lbessard@151: elif "choices" in group: lbessard@151: elements = group["choices"] lbessard@151: for element in elements: lbessard@151: if element["name"] == parts[1]: lbessard@151: return element lbessard@151: if not canbenone: lbessard@151: raise ValueError, "Unknown element \"%s\" for any defined namespaces!"%name lbessard@151: elif namespace in self.Namespaces: lbessard@151: if name in self.Namespaces[namespace]: lbessard@151: return self.Namespaces[namespace][name] lbessard@151: parts = name.split("_", 1) lbessard@151: if len(parts) > 1: lbessard@151: group = self.GetQualifiedNameInfos(parts[0], namespace) lbessard@151: if group is not None and group["type"] == ELEMENTSGROUP: lbessard@151: elements = [] lbessard@151: if "elements" in group: lbessard@151: elements = group["elements"] lbessard@151: elif "choices" in group: lbessard@151: elements = group["choices"] lbessard@151: for element in elements: lbessard@151: if element["name"] == parts[1]: lbessard@151: return element lbessard@151: if not canbenone: lbessard@151: raise ValueError, "Unknown element \"%s\" for namespace \"%s\"!"%(name, namespace) lbessard@151: elif not canbenone: lbessard@151: raise ValueError, "Unknown namespace \"%s\"!"%namespace lbessard@151: return None lbessard@151: lbessard@151: def SplitQualifiedName(self, name, namespace = None, canbenone = False): lbessard@151: if namespace is None: lbessard@151: if name in self.Namespaces[self.SchemaNamespace]: lbessard@151: return name, None lbessard@151: for space, elements in self.Namespaces.items(): lbessard@151: if space != self.SchemaNamespace and name in elements: lbessard@151: return name, None lbessard@151: parts = name.split("_", 1) lbessard@151: if len(parts) > 1: lbessard@151: group = self.GetQualifiedNameInfos(parts[0], namespace) lbessard@151: if group is not None and group["type"] == ELEMENTSGROUP: lbessard@151: elements = [] lbessard@151: if "elements" in group: lbessard@151: elements = group["elements"] lbessard@151: elif "choices" in group: lbessard@151: elements = group["choices"] lbessard@151: for element in elements: lbessard@151: if element["name"] == parts[1]: lbessard@151: return part[1], part[0] lbessard@151: if not canbenone: lbessard@151: raise ValueError, "Unknown element \"%s\" for any defined namespaces!"%name lbessard@151: elif namespace in self.Namespaces: lbessard@151: if name in self.Namespaces[namespace]: lbessard@151: return name, None lbessard@151: parts = name.split("_", 1) lbessard@151: if len(parts) > 1: lbessard@151: group = self.GetQualifiedNameInfos(parts[0], namespace) lbessard@151: if group is not None and group["type"] == ELEMENTSGROUP: lbessard@151: elements = [] lbessard@151: if "elements" in group: lbessard@151: elements = group["elements"] lbessard@151: elif "choices" in group: lbessard@151: elements = group["choices"] lbessard@151: for element in elements: lbessard@151: if element["name"] == parts[1]: lbessard@151: return parts[1], parts[0] lbessard@151: if not canbenone: lbessard@151: raise ValueError, "Unknown element \"%s\" for namespace \"%s\"!"%(name, namespace) lbessard@151: elif not canbenone: lbessard@151: raise ValueError, "Unknown namespace \"%s\"!"%namespace lbessard@151: return None, None lbessard@151: lbessard@151: def ExtractNodeAttrs(self, element_name, node, valid_attrs): lbessard@151: attrs = {} lbessard@151: for qualified_name, attr in node._attrs.items(): lbessard@151: namespace, name = DecomposeQualifiedName(qualified_name) lbessard@151: if name in valid_attrs: lbessard@151: infos = self.GetQualifiedNameInfos(name, namespace) lbessard@151: if infos["type"] != SYNTAXATTRIBUTE: lbessard@151: raise ValueError, "\"%s\" can't be a member attribute!"%name lbessard@151: elif name in attrs: lbessard@151: raise ValueError, "\"%s\" attribute has been twice!"%name lbessard@151: elif element_name in infos["extract"]: lbessard@151: attrs[name] = infos["extract"][element_name](attr) lbessard@151: else: lbessard@151: attrs[name] = infos["extract"]["default"](attr) lbessard@151: elif namespace == "xmlns": lbessard@151: infos = self.GetQualifiedNameInfos("anyURI", self.SchemaNamespace) lbessard@151: self.DefinedNamespaces[infos["extract"](attr)] = name lbessard@151: else: lbessard@151: raise ValueError, "Invalid attribute \"%s\" for member \"%s\"!"%(qualified_name, node.nodeName) lbessard@151: for attr in valid_attrs: lbessard@151: if attr not in attrs and attr in self.Namespaces[self.SchemaNamespace] and "default" in self.Namespaces[self.SchemaNamespace][attr]: lbessard@151: if element_name in self.Namespaces[self.SchemaNamespace][attr]["default"]: lbessard@151: default = self.Namespaces[self.SchemaNamespace][attr]["default"][element_name] lbessard@151: else: lbessard@151: default = self.Namespaces[self.SchemaNamespace][attr]["default"]["default"] lbessard@151: if default is not None: lbessard@151: attrs[attr] = default lbessard@151: return attrs lbessard@151: lbessard@151: def ReduceElements(self, elements, schema=False): lbessard@151: result = [] lbessard@151: for child_infos in elements: lbessard@151: if "name" in child_infos[1] and schema: lbessard@151: self.CurrentCompilations.append(child_infos[1]["name"]) lbessard@151: namespace, name = DecomposeQualifiedName(child_infos[0]) lbessard@151: infos = self.GetQualifiedNameInfos(name, namespace) lbessard@151: if infos["type"] != SYNTAXELEMENT: lbessard@151: raise ValueError, "\"%s\" can't be a member child!"%name lbessard@151: result.append(infos["reduce"](self, child_infos[1], child_infos[2])) lbessard@151: if "name" in child_infos[1] and schema: lbessard@151: self.CurrentCompilations.pop(-1) lbessard@151: annotations = [] lbessard@151: children = [] lbessard@151: for element in result: lbessard@151: if element["type"] == "annotation": lbessard@151: annotations.append(element) lbessard@151: else: lbessard@151: children.append(element) lbessard@151: return annotations, children lbessard@151: lbessard@151: def AddComplexType(self, typename, infos): lbessard@151: if typename not in self.XMLClassDefinitions: lbessard@151: self.XMLClassDefinitions[typename] = infos lbessard@151: else: lbessard@151: raise ValueError, "\"%s\" class already defined. Choose another name!"%typename lbessard@151: lbessard@151: def ParseSchema(self): lbessard@151: pass lbessard@151: lbessard@151: def ExtractTypeInfos(self, name, parent, typeinfos): lbessard@151: if isinstance(typeinfos, (StringType, UnicodeType)): lbessard@151: namespace, name = DecomposeQualifiedName(typeinfos) lbessard@151: infos = self.GetQualifiedNameInfos(name, namespace) lbessard@151: if infos["type"] == COMPLEXTYPE: lbessard@151: name, parent = self.SplitQualifiedName(name, namespace) lbessard@151: result = self.CreateClass(name, parent, infos) lbessard@151: if result is not None and not isinstance(result, (UnicodeType, StringType)): lbessard@151: self.Namespaces[self.TargetNamespace][result["name"]] = result lbessard@151: return result lbessard@151: elif infos["type"] == ELEMENT and infos["elmt_type"]["type"] == COMPLEXTYPE: lbessard@151: name, parent = self.SplitQualifiedName(name, namespace) lbessard@151: result = self.CreateClass(name, parent, infos["elmt_type"]) lbessard@151: if result is not None and not isinstance(result, (UnicodeType, StringType)): lbessard@151: self.Namespaces[self.TargetNamespace][result["name"]] = result lbessard@151: return result lbessard@151: else: lbessard@151: return infos lbessard@151: elif typeinfos["type"] == COMPLEXTYPE: lbessard@151: return self.CreateClass(name, parent, typeinfos) lbessard@151: elif typeinfos["type"] == SIMPLETYPE: lbessard@151: return typeinfos lbessard@151: lbessard@151: """ lbessard@151: Methods that generates the classes lbessard@151: """ lbessard@151: def CreateClasses(self): lbessard@151: self.ParseSchema() lbessard@151: for name, infos in self.Namespaces[self.TargetNamespace].items(): lbessard@151: if infos["type"] == ELEMENT: lbessard@151: if not isinstance(infos["elmt_type"], (UnicodeType, StringType)) and infos["elmt_type"]["type"] == COMPLEXTYPE: lbessard@151: self.ComputeAfter.append((name, None, infos["elmt_type"], True)) lbessard@151: while len(self.ComputeAfter) > 0: lbessard@151: result = self.CreateClass(*self.ComputeAfter.pop(0)) lbessard@151: if result is not None and not isinstance(result, (UnicodeType, StringType)): lbessard@151: self.Namespaces[self.TargetNamespace][result["name"]] = result lbessard@151: elif infos["type"] == COMPLEXTYPE: lbessard@151: self.ComputeAfter.append((name, None, infos)) lbessard@151: while len(self.ComputeAfter) > 0: lbessard@151: result = self.CreateClass(*self.ComputeAfter.pop(0)) lbessard@151: if result is not None and not isinstance(result, (UnicodeType, StringType)): lbessard@151: self.Namespaces[self.TargetNamespace][result["name"]] = result lbessard@151: elif infos["type"] == ELEMENTSGROUP: lbessard@151: elements = [] lbessard@151: if "elements" in infos: lbessard@151: elements = infos["elements"] lbessard@151: elif "choices" in infos: lbessard@151: elements = infos["choices"] lbessard@151: for element in elements: lbessard@151: if not isinstance(element["elmt_type"], (UnicodeType, StringType)) and element["elmt_type"]["type"] == COMPLEXTYPE: lbessard@151: self.ComputeAfter.append((element["name"], infos["name"], element["elmt_type"])) lbessard@151: while len(self.ComputeAfter) > 0: lbessard@151: result = self.CreateClass(*self.ComputeAfter.pop(0)) lbessard@151: if result is not None and not isinstance(result, (UnicodeType, StringType)): lbessard@151: self.Namespaces[self.TargetNamespace][result["name"]] = result lbessard@151: return self.ComputedClasses lbessard@151: lbessard@151: def CreateClass(self, name, parent, classinfos, baseclass = False): lbessard@151: if parent is not None: lbessard@151: classname = "%s_%s"%(parent, name) lbessard@151: else: lbessard@151: classname = name lbessard@151: lbessard@151: # Checks that classe haven't been generated yet lbessard@151: if self.AlreadyComputed.get(classname, False): lbessard@151: if baseclass: lbessard@151: self.AlreadyComputed[classname].IsBaseClass = baseclass lbessard@151: return None lbessard@151: lbessard@151: # If base classes haven't been generated lbessard@151: bases = [] lbessard@151: if "base" in classinfos: lbessard@151: result = self.ExtractTypeInfos("base", name, classinfos["base"]) lbessard@151: if result is None: lbessard@151: namespace, base_name = DecomposeQualifiedName(classinfos["base"]) lbessard@151: if self.AlreadyComputed.get(base_name, False): lbessard@151: self.ComputeAfter.append((name, parent, classinfos)) lbessard@151: if self.TargetNamespace is not None: lbessard@151: return "%s:%s"%(self.TargetNamespace, classname) lbessard@76: else: lbessard@151: return classname lbessard@151: elif result is not None: lbessard@151: classinfos["base"] = self.ComputedClasses[result["name"]] lbessard@151: bases.append(self.ComputedClasses[result["name"]]) lbessard@151: bases.append(object) lbessard@151: bases = tuple(bases) lbessard@151: classmembers = {"__doc__" : classinfos.get("doc", ""), "IsBaseClass" : baseclass} lbessard@151: lbessard@151: self.AlreadyComputed[classname] = True lbessard@151: lbessard@151: for attribute in classinfos["attributes"]: lbessard@151: infos = self.ExtractTypeInfos(attribute["name"], name, attribute["attr_type"]) lbessard@151: if infos is not None: lbessard@151: if infos["type"] != SIMPLETYPE: lbessard@151: raise ValueError, "\"%s\" type is not a simple type!"%attribute["attr_type"] lbessard@151: attrname = attribute["name"] lbessard@151: if attribute["use"] == "optional": lbessard@151: classmembers[attrname] = None lbessard@151: classmembers["add%s"%attrname] = generateAddMethod(attrname, self, attribute) lbessard@151: classmembers["delete%s"%attrname] = generateDeleteMethod(attrname) lbessard@151: else: lbessard@151: classmembers[attrname] = infos["initial"]() lbessard@151: classmembers["set%s"%attrname] = generateSetMethod(attrname) lbessard@151: classmembers["get%s"%attrname] = generateGetMethod(attrname) lbessard@151: else: lbessard@151: raise ValueError, "\"%s\" type unrecognized!"%attribute["attr_type"] lbessard@151: attribute["attr_type"] = infos lbessard@151: lbessard@151: for element in classinfos["elements"]: lbessard@151: if element["type"] == CHOICE: lbessard@151: elmtname = element["name"] lbessard@151: choices = [] lbessard@151: for choice in element["choices"]: lbessard@151: if choice["elmt_type"] == "tag": lbessard@151: choice["elmt_type"] = GenerateTagInfos(choice["name"]) lbessard@76: else: lbessard@151: infos = self.ExtractTypeInfos(choice["name"], name, choice["elmt_type"]) lbessard@151: if infos is not None: lbessard@151: choice["elmt_type"] = infos lbessard@151: choices.append((choice["name"], choice)) lbessard@151: classmembers["get%schoices"%elmtname] = generateGetChoicesMethod(element["choices"]) lbessard@151: classmembers["add%sbytype"%elmtname] = generateAddChoiceByTypeMethod(element["choices"]) lbessard@151: infos = GenerateContentInfos(self, choices) lbessard@151: elif element["type"] == ANY: lbessard@151: elmtname = element["name"] = "text" lbessard@151: element["minOccurs"] = element["maxOccurs"] = 1 lbessard@151: infos = GenerateAnyInfos() lbessard@151: else: lbessard@151: elmtname = element["name"] lbessard@151: infos = self.ExtractTypeInfos(element["name"], name, element["elmt_type"]) lbessard@151: if infos is not None: lbessard@151: element["elmt_type"] = infos lbessard@151: if element["maxOccurs"] == "unbounded" or element["maxOccurs"] > 1: lbessard@151: classmembers[elmtname] = [] lbessard@151: classmembers["append%s"%elmtname] = generateAppendMethod(elmtname, element["maxOccurs"], self, element) lbessard@151: classmembers["insert%s"%elmtname] = generateInsertMethod(elmtname, element["maxOccurs"], self, element) lbessard@151: classmembers["remove%s"%elmtname] = generateRemoveMethod(elmtname, element["minOccurs"]) lbessard@151: classmembers["count%s"%elmtname] = generateCountMethod(elmtname) lbessard@151: else: lbessard@151: if element["minOccurs"] == 0: lbessard@151: classmembers[elmtname] = None lbessard@151: classmembers["add%s"%elmtname] = generateAddMethod(elmtname, self, element) lbessard@151: classmembers["delete%s"%elmtname] = generateDeleteMethod(elmtname) lbessard@151: elif not isinstance(element["elmt_type"], (UnicodeType, StringType)): lbessard@151: classmembers[elmtname] = element["elmt_type"]["initial"]() lbessard@151: else: lbessard@151: classmembers[elmtname] = None lbessard@151: classmembers["set%s"%elmtname] = generateSetMethod(elmtname) lbessard@151: classmembers["get%s"%elmtname] = generateGetMethod(elmtname) lbessard@76: lbessard@151: classmembers["__init__"] = generateInitMethod(self, classinfos) lbessard@151: classmembers["__setattr__"] = generateSetattrMethod(self, classinfos) lbessard@151: classmembers["getStructure"] = generateStructureMethod(classinfos) lbessard@151: classmembers["loadXMLTree"] = generateLoadXMLTree(self, classinfos) lbessard@151: classmembers["generateXMLText"] = generateGenerateXMLText(self, classinfos) lbessard@151: classmembers["getElementAttributes"] = generateGetElementAttributes(self, classinfos) lbessard@151: classmembers["getElementInfos"] = generateGetElementInfos(self, classinfos) lbessard@151: classmembers["setElementValue"] = generateSetElementValue(self, classinfos) lbessard@151: classmembers["singleLineAttributes"] = True lbessard@151: lbessard@151: class_definition = classobj(str(classname), bases, classmembers) lbessard@151: lbessard@151: self.ComputedClasses[classname] = class_definition lbessard@151: lbessard@151: return {"type" : COMPILEDCOMPLEXTYPE, lbessard@151: "name" : classname, lbessard@151: "check" : generateClassCheckFunction(class_definition), lbessard@151: "initial" : generateClassCreateFunction(class_definition), lbessard@151: "extract" : generateClassExtractFunction(class_definition), lbessard@151: "generate" : class_definition.generateXMLText} lbessard@76: lbessard@76: """ lbessard@76: Methods that print the classes generated lbessard@76: """ lbessard@76: def PrintClasses(self): lbessard@151: items = self.ComputedClasses.items() lbessard@151: items.sort() lbessard@151: for classname, xmlclass in 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: """ lbessard@151: Method that generate the method for checking a class instance lbessard@151: """ lbessard@151: def generateClassCheckFunction(class_definition): lbessard@151: def classCheckfunction(instance): lbessard@151: return isinstance(instance, class_definition) lbessard@151: return classCheckfunction lbessard@151: lbessard@151: """ lbessard@151: Method that generate the method for creating a class instance lbessard@151: """ lbessard@151: def generateClassCreateFunction(class_definition): lbessard@151: def classCreatefunction(): lbessard@151: return class_definition() lbessard@151: return classCreatefunction lbessard@151: lbessard@151: """ lbessard@151: Method that generate the method for extracting a class instance lbessard@151: """ lbessard@151: def generateClassExtractFunction(class_definition): lbessard@151: def classExtractfunction(node): lbessard@151: instance = class_definition() lbessard@151: instance.loadXMLTree(node) lbessard@151: return instance lbessard@151: return classExtractfunction lbessard@151: lbessard@151: """ etisserant@75: Method that generate the method for loading an xml tree by following the etisserant@75: attributes list defined etisserant@75: """ lbessard@151: def generateSetattrMethod(factory, classinfos): lbessard@151: attributes = dict([(attr["name"], attr) for attr in classinfos["attributes"] if attr["use"] != "prohibited"]) lbessard@151: optional_attributes = [attr["name"] for attr in classinfos["attributes"] if attr["use"] == "optional"] lbessard@151: elements = dict([(element["name"], element) for element in classinfos["elements"]]) lbessard@151: lbessard@151: def setattrMethod(self, name, value): lbessard@151: if name in attributes: lbessard@151: if isinstance(attributes[name]["attr_type"], (UnicodeType, StringType)): lbessard@151: namespace, name = DecomposeQualifiedName(infos) lbessard@151: attributes[name]["attr_type"] = factory.GetQualifiedNameInfos(name, namespace) lbessard@151: if value is None: lbessard@151: if name in optional_attributes: lbessard@151: return object.__setattr__(self, name, None) lbessard@151: else: lbessard@151: raise ValueError, "Attribute '%s' isn't optional."%name lbessard@151: elif "fixed" in attributes[name] and value != attributes[name]["fixed"]: lbessard@151: raise ValueError, "Value of attribute '%s' can only be '%s'."%(name, str(attributes[name]["fixed"])) lbessard@151: elif attributes[name]["attr_type"]["check"](value): lbessard@151: return object.__setattr__(self, name, value) lbessard@151: else: lbessard@151: raise ValueError, "Invalid value for attribute '%s'."%(name) lbessard@151: elif name in elements: lbessard@151: if isinstance(elements[name]["elmt_type"], (UnicodeType, StringType)): lbessard@151: namespace, name = DecomposeQualifiedName(infos) lbessard@151: elements[name]["elmt_type"] = factory.GetQualifiedNameInfos(name, namespace) lbessard@151: if value is None: lbessard@151: if elements[name]["minOccurs"] == 0 and elements[name]["maxOccurs"] == 1: lbessard@151: return object.__setattr__(self, name, None) lbessard@151: else: lbessard@151: raise ValueError, "Attribute '%s' isn't optional."%name lbessard@151: elif elements[name]["maxOccurs"] == "unbounded" or elements[name]["maxOccurs"] > 1: lbessard@151: if isinstance(value, ListType) and elements[name]["minOccurs"] <= len(value) <= elements[name]["maxOccurs"]: lbessard@151: if reduce(lambda x, y: x and y, map(elements[name]["elmt_type"]["check"], value), True): lbessard@151: return object.__setattr__(self, name, value) lbessard@151: raise ValueError, "Attribute '%s' must be a list of valid elements."%name lbessard@151: elif "fixed" in elements[name] and value != elements[name]["fixed"]: lbessard@151: raise ValueError, "Value of attribute '%s' can only be '%s'."%(name, str(elements[name]["fixed"])) lbessard@151: elif elements[name]["elmt_type"]["check"](value): lbessard@151: return object.__setattr__(self, name, value) lbessard@151: else: lbessard@151: raise ValueError, "Invalid value for attribute '%s'."%(name) lbessard@151: elif "base" in classinfos: lbessard@151: return classinfos["base"].__setattr__(self, name, value) lbessard@151: else: lbessard@151: raise AttributeError, "'%s' can't have an attribute '%s'."%(classinfos["name"], name) lbessard@151: lbessard@151: return setattrMethod lbessard@151: lbessard@151: """ lbessard@151: Method that generate the method for generating the xml tree structure model by lbessard@151: following the attributes list defined lbessard@151: """ lbessard@151: def ComputeMultiplicity(name, infos): lbessard@151: if infos["minOccurs"] == 0: lbessard@151: if infos["maxOccurs"] == "unbounded": lbessard@151: return "(?:%s)*"%name lbessard@151: elif infos["maxOccurs"] == 1: lbessard@151: return "(?:%s)?"%name lbessard@151: else: lbessard@151: return "(?:%s){0, %d}"%(name, infos["maxOccurs"]) lbessard@151: elif infos["minOccurs"] == 1: lbessard@151: if infos["maxOccurs"] == "unbounded": lbessard@151: return "(?:%s)+"%name lbessard@151: elif infos["maxOccurs"] == 1: lbessard@151: return name lbessard@151: else: lbessard@151: return "(?:%s){1, %d}"%(name, infos["maxOccurs"]) lbessard@151: else: lbessard@151: if infos["maxOccurs"] == "unbounded": lbessard@151: return "(?:%s){%d}(?:%s )*"%(name, infos["minOccurs"], name) lbessard@151: else: lbessard@151: return "(?:%s){%d, %d}"%(name, infos["minOccurs"], infos["maxOccurs"]) lbessard@151: lbessard@151: def generateStructureMethod(classinfos): lbessard@151: elements = [] lbessard@151: for element in classinfos["elements"]: lbessard@151: if element["type"] == ANY: lbessard@151: elements.append(ComputeMultiplicity("(?:#cdata-section )?", element)) lbessard@151: elif element["type"] == CHOICE: lbessard@151: elements.append(ComputeMultiplicity( lbessard@151: "|".join([ComputeMultiplicity("%s "%infos["name"], infos) for infos in element["choices"]]), lbessard@151: element)) lbessard@151: else: lbessard@151: elements.append(ComputeMultiplicity("%s "%element["name"], element)) lbessard@151: if classinfos.get("order") or len(elements) == 0: lbessard@151: structure = "".join(elements) lbessard@151: else: lbessard@151: raise ValueError, "XSD structure not yet supported!" lbessard@151: lbessard@151: def getStructureMethod(self): lbessard@151: if "base" in classinfos: lbessard@151: return classinfos["base"].getStructure(self) + structure lbessard@151: return structure lbessard@151: return getStructureMethod lbessard@151: lbessard@151: """ lbessard@151: Method that generate the method for loading an xml tree by following the lbessard@151: attributes list defined lbessard@151: """ lbessard@151: def generateLoadXMLTree(factory, classinfos): lbessard@151: attributes = dict([(attr["name"], attr) for attr in classinfos["attributes"] if attr["use"] != "prohibited"]) lbessard@151: elements = dict([(element["name"], element) for element in classinfos["elements"]]) lbessard@151: lbessard@151: def loadXMLTreeMethod(self, tree, extras = [], derived = False): lbessard@151: if not derived: lbessard@151: children_structure = "" etisserant@75: for node in tree.childNodes: lbessard@151: if node.nodeName not in ["#comment", "#text"]: lbessard@151: children_structure += "%s "%node.nodeName lbessard@151: structure_model = re.compile("(%s)$"%self.getStructure()) lbessard@151: result = structure_model.match(children_structure) lbessard@151: if not result: lbessard@151: raise ValueError, "Invalid structure for \"%s\" children!."%tree.nodeName lbessard@151: required_attributes = [attr["name"] for attr in classinfos["attributes"] if attr["use"] == "required"] lbessard@151: if "base" in classinfos: lbessard@151: extras.extend([attr["name"] for attr in classinfos["attributes"] if attr["use"] != "prohibited"]) lbessard@151: classinfos["base"].loadXMLTree(self, tree, extras, True) lbessard@151: for attrname, attr in tree._attrs.items(): lbessard@151: if attrname in attributes: lbessard@151: if isinstance(attributes[attrname]["attr_type"], (UnicodeType, StringType)): lbessard@151: namespace, name = DecomposeQualifiedName(infos) lbessard@151: attributes[attrname]["attr_type"] = factory.GetQualifiedNameInfos(name, namespace) lbessard@151: setattr(self, attrname, attributes[attrname]["attr_type"]["extract"](attr)) lbessard@151: elif "base" not in classinfos and attrname not in extras: lbessard@151: raise ValueError, "Invalid attribute \"%s\" for \"%s\" element!"%(attrname, tree.nodeName) lbessard@151: if attrname in required_attributes: lbessard@151: required_attributes.remove(attrname) lbessard@151: if len(required_attributes) > 0: lbessard@151: raise ValueError, "Required attributes %s missing for \"%s\" element!"%(", ".join(["\"%s\""%name for name in required_attributes]), tree.nodeName) lbessard@151: first = {} lbessard@151: for node in tree.childNodes: lbessard@151: name = node.nodeName lbessard@151: if name in ["#text", "#comment"]: lbessard@151: continue lbessard@151: if name in elements: lbessard@151: if isinstance(elements[name]["elmt_type"], (UnicodeType, StringType)): lbessard@151: namespace, name = DecomposeQualifiedName(infos) lbessard@151: elements[name]["elmt_type"] = factory.GetQualifiedNameInfos(name, namespace) lbessard@151: if elements[name]["maxOccurs"] == "unbounded" or elements[name]["maxOccurs"] > 1: lbessard@151: if first.get(name, True): lbessard@151: setattr(self, name, [elements[name]["elmt_type"]["extract"](node)]) lbessard@151: first[name] = False lbessard@151: else: lbessard@151: getattr(self, name).append(elements[name]["elmt_type"]["extract"](node)) lbessard@151: else: lbessard@151: setattr(self, name, elements[name]["elmt_type"]["extract"](node)) lbessard@151: elif name == "#cdata-section" and "text" in elements: lbessard@151: if elements["text"]["maxOccurs"] == "unbounded" or elements["text"]["maxOccurs"] > 1: lbessard@151: if first.get("text", True): lbessard@151: setattr(self, "text", [elements["text"]["elmt_type"]["extract"](node)]) lbessard@151: first["text"] = False lbessard@151: else: lbessard@151: getattr(self, "text").append(elements["text"]["elmt_type"]["extract"](node)) lbessard@151: else: lbessard@151: setattr(self, "text", elements["text"]["elmt_type"]["extract"](node)) lbessard@151: elif "content" in elements: lbessard@151: content = getattr(self, "content") lbessard@151: if elements["content"]["maxOccurs"] == "unbounded" or elements["content"]["maxOccurs"] > 1: lbessard@151: if first.get("content", True): lbessard@151: setattr(self, "content", [elements["content"]["elmt_type"]["extract"](node, None)]) lbessard@151: first["content"] = False lbessard@151: else: lbessard@151: content.append(elements["content"]["elmt_type"]["extract"](node, content)) lbessard@151: else: lbessard@151: setattr(self, "content", elements["content"]["elmt_type"]["extract"](node, content)) etisserant@75: return loadXMLTreeMethod lbessard@151: 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: """ lbessard@151: def generateGenerateXMLText(factory, classinfos): lbessard@151: def generateXMLTextMethod(self, name, indent = 0, 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 = "" lbessard@151: etisserant@75: first = True lbessard@151: if "base" not in classinfos: lbessard@151: for attr, value in extras.items(): lbessard@151: if not first and not self.singleLineAttributes: lbessard@151: text += "\n%s"%(ind2) lbessard@151: text += " %s=\"%s\""%(attr, value) lbessard@151: first = False lbessard@151: extras.clear() lbessard@151: for attr in classinfos["attributes"]: lbessard@151: if attr["use"] != "prohibited": lbessard@151: if isinstance(attr["attr_type"], (UnicodeType, StringType)): lbessard@151: namespace, name = DecomposeQualifiedName(infos) lbessard@151: attr["attr_type"] = factory.GetQualifiedNameInfos(name, namespace) lbessard@151: value = getattr(self, attr["name"], None) lbessard@86: if value != None: lbessard@151: computed_value = attr["attr_type"]["generate"](value) lbessard@86: else: lbessard@86: computed_value = None lbessard@151: if attr["use"] != "optional" or (value != None and computed_value != attr.get("default", attr["attr_type"]["generate"](attr["attr_type"]["initial"]()))): lbessard@151: if "base" in classinfos: lbessard@151: extras[attr["name"]] = computed_value etisserant@75: else: lbessard@83: if not first and not self.singleLineAttributes: lbessard@83: text += "\n%s"%(ind2) lbessard@151: text += " %s=\"%s\""%(attr["name"], computed_value) etisserant@75: first = False lbessard@151: if "base" in classinfos: lbessard@151: first, new_text = classinfos["base"].generateXMLText(self, name, indent, extras, True) etisserant@75: text += new_text etisserant@75: else: etisserant@75: first = True lbessard@151: for element in classinfos["elements"]: lbessard@151: if isinstance(element["elmt_type"], (UnicodeType, StringType)): lbessard@151: namespace, name = DecomposeQualifiedName(infos) lbessard@151: element["elmt_type"] = factory.GetQualifiedNameInfos(name, namespace) lbessard@151: value = getattr(self, element["name"], None) lbessard@151: if element["minOccurs"] == 0 and element["maxOccurs"] == 1: lbessard@151: if value is not None: etisserant@75: if first: etisserant@75: text += ">\n" etisserant@75: first = False lbessard@151: text += element["elmt_type"]["generate"](value, element["name"], indent + 1) lbessard@151: elif element["minOccurs"] == 1 and element["maxOccurs"] == 1: lbessard@151: if first: lbessard@151: text += ">\n" lbessard@151: first = False lbessard@151: text += element["elmt_type"]["generate"](value, element["name"], indent + 1) lbessard@151: else: lbessard@151: if first and len(value) > 0: lbessard@151: text += ">\n" lbessard@151: first = False lbessard@151: for item in value: lbessard@151: text += element["elmt_type"]["generate"](item, element["name"], 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: lbessard@151: def gettypeinfos(name, facets): lbessard@151: if "enumeration" in facets and facets["enumeration"][0] is not None: lbessard@151: return facets["enumeration"][0] lbessard@151: elif "maxInclusive" in facets: lbessard@151: limits = {"max" : None, "min" : None} lbessard@151: if facets["maxInclusive"][0] is not None: lbessard@151: limits["max"] = facets["maxInclusive"][0] lbessard@151: elif facets["maxExclusive"][0] is not None: lbessard@151: limits["max"] = facets["maxExclusive"][0] - 1 lbessard@151: if facets["minInclusive"][0] is not None: lbessard@151: limits["min"] = facets["minInclusive"][0] lbessard@151: elif facets["minExclusive"][0] is not None: lbessard@151: limits["min"] = facets["minExclusive"][0] + 1 lbessard@151: if limits["max"] is not None or limits["min"] is not None: lbessard@151: return limits lbessard@151: return name lbessard@151: lbessard@151: def generateGetElementAttributes(factory, classinfos): etisserant@75: def getElementAttributes(self): etisserant@75: attr_list = [] lbessard@151: for attr in classinfos["attributes"]: lbessard@151: if attr["use"] != "prohibited": lbessard@151: attr_params = {"name" : attr["name"], "require" : attr["use"] == "required", lbessard@151: "type" : gettypeinfos(attr["attr_type"]["basename"], attr["attr_type"]["facets"]), lbessard@151: "value" : getattr(self, attr["name"], "")} lbessard@83: attr_list.append(attr_params) etisserant@75: return attr_list etisserant@75: return getElementAttributes lbessard@85: lbessard@151: def generateGetElementInfos(factory, classinfos): lbessard@151: attributes = dict([(attr["name"], attr) for attr in classinfos["attributes"] if attr["use"] != "prohibited"]) lbessard@151: elements = dict([(element["name"], element) for element in classinfos["elements"]]) lbessard@151: lbessard@85: def getElementInfos(self, name, path = None): lbessard@85: attr_type = "element" lbessard@85: value = None lbessard@85: children = [] lbessard@151: if path is not None: lbessard@151: parts = path.split(".", 1) lbessard@151: if parts[0] in attributes: lbessard@151: if len(parts) != 0: lbessard@151: raise ValueError, "Wrong path!" lbessard@151: attr_type = gettypeinfos(attributes[parts[0]]["attr_type"]["basename"], lbessard@151: attributes[parts[0]]["attr_type"]["facets"]) lbessard@151: value = getattr(self, parts[0], "") lbessard@151: elif parts[0] in elements: lbessard@151: if element["elmt_type"]["type"] == SIMPLETYPE: lbessard@151: if len(parts) != 0: lbessard@151: raise ValueError, "Wrong path!" lbessard@151: attr_type = gettypeinfos(elements[parts[0]]["elmt_type"]["basename"], lbessard@151: elements[parts[0]]["elmt_type"]["facets"]) lbessard@151: value = getattr(self, parts[0], "") lbessard@151: elif parts[0] == "content": lbessard@151: return self.content["value"].getElementInfos(self.content["name"], path) lbessard@151: elif len(parts) == 1: lbessard@151: return attr.getElementInfos(parts[0]) lbessard@151: else: lbessard@151: return attr.getElementInfos(parts[0], parts[1]) lbessard@151: else: lbessard@151: raise ValueError, "Wrong path!" lbessard@151: else: lbessard@151: children.extend(self.getElementAttributes()) lbessard@151: for element_name, element in elements.items(): lbessard@151: if element_name == "content": lbessard@151: attr_type = [(choice["name"], None) for choice in element["choices"]] lbessard@151: value = self.content["name"] lbessard@151: children.extend(self.content["value"].getElementInfos(self.content["name"])["children"]) lbessard@151: elif element["elmt_type"]["type"] == SIMPLETYPE: lbessard@151: children.append({"name" : element_name, "require" : element["minOccurs"] != 0, lbessard@151: "type" : gettypeinfos(element["elmt_type"]["basename"], lbessard@151: element["elmt_type"]["facets"]), lbessard@151: "value" : getattr(self, element_name, None)}) lbessard@151: else: lbessard@151: instance = getattr(self, element_name, None) lbessard@151: if instance is None: lbessard@151: instance = elmt_type["elmt_type"]["initial"]() lbessard@151: children.append(instance.getElementInfos(element_name)) lbessard@85: return {"name" : name, "type" : attr_type, "value" : value, "children" : children} lbessard@85: return getElementInfos lbessard@85: lbessard@151: def generateSetElementValue(factory, classinfos): lbessard@151: attributes = dict([(attr["name"], attr) for attr in classinfos["attributes"] if attr["use"] != "prohibited"]) lbessard@151: elements = dict([(element["name"], element) for element in classinfos["elements"]]) lbessard@151: lbessard@85: def setElementValue(self, path, value): lbessard@151: if "content" in elements: lbessard@85: if path: lbessard@85: self.content["value"].setElementValue(path, value) lbessard@85: else: lbessard@151: self.addcontentbytype(value) lbessard@85: else: lbessard@85: parts = path.split(".", 1) lbessard@151: if parts[0] in attributes: lbessard@151: if len(parts) != 1: lbessard@151: raise ValueError, "Wrong path!" lbessard@151: if attributes[parts[0]]["attr_type"]["basename"] == "boolean": lbessard@151: setattr(self, parts[0], value) lbessard@151: else: lbessard@151: setattr(self, parts[0], attributes[parts[0]]["attr_type"]["extract"](value, False)) lbessard@151: elif parts[0] in elements: lbessard@151: if elements[parts[0]]["elmt_type"]["type"] == SIMPLETYPE: lbessard@151: if len(parts) != 1: lbessard@151: raise ValueError, "Wrong path!" lbessard@151: if elements[parts[0]]["elmt_type"]["basename"] == "boolean": lbessard@151: setattr(self, parts[0], value) lbessard@151: else: lbessard@151: setattr(self, parts[0], elements[parts[0]]["elmt_type"]["extract"](value, False)) lbessard@151: else: lbessard@151: instance = getattr(self, parts[0], None) lbessard@151: if instance != None: lbessard@151: if len(parts) == 1: lbessard@151: instance.setElementValue(None, value) lbessard@85: else: lbessard@151: instance.setElementValue(parts[1], value) lbessard@85: return setElementValue lbessard@85: etisserant@75: """ etisserant@75: Methods that generates the different methods for setting and getting the attributes etisserant@75: """ lbessard@151: def generateInitMethod(factory, classinfos): etisserant@75: def initMethod(self): lbessard@151: if "base" in classinfos: lbessard@151: classinfos["base"].__init__(self) lbessard@151: for attribute in classinfos["attributes"]: lbessard@151: if isinstance(attribute["attr_type"], (UnicodeType, StringType)): lbessard@151: namespace, name = DecomposeQualifiedName(attribute["attr_type"]) lbessard@151: attribute["attr_type"] = factory.GetQualifiedNameInfos(name, namespace) lbessard@151: if attribute["use"] == "required": lbessard@151: setattr(self, attribute["name"], attribute["attr_type"]["initial"]()) lbessard@151: elif attribute["use"] == "optional": lbessard@151: if "default" in attribute: lbessard@151: setattr(self, attribute["name"], attribute["attr_type"]["extract"](attribute["default"], False)) lbessard@151: else: lbessard@151: setattr(self, attribute["name"], None) lbessard@151: for element in classinfos["elements"]: lbessard@151: if isinstance(element["elmt_type"], (UnicodeType, StringType)): lbessard@151: namespace, name = DecomposeQualifiedName(element["elmt_type"]) lbessard@151: element["elmt_type"] = factory.GetQualifiedNameInfos(name, namespace) lbessard@151: if element["minOccurs"] == 0 and element["maxOccurs"] == 1: lbessard@151: if "default" in element: lbessard@151: setattr(self, element["name"], element["elmt_type"]["extract"](element["default"], False)) lbessard@151: else: lbessard@151: setattr(self, element["name"], None) lbessard@151: elif element["minOccurs"] == 1 and element["maxOccurs"] == 1: lbessard@151: setattr(self, element["name"], element["elmt_type"]["initial"]()) lbessard@151: else: lbessard@151: value = [] lbessard@151: for i in xrange(element["minOccurs"]): lbessard@151: value.append(element["elmt_type"]["initial"]()) lbessard@151: setattr(self, element["name"], value) etisserant@75: return initMethod etisserant@75: lbessard@151: def generateSetMethod(attr): etisserant@75: def setMethod(self, value): etisserant@75: setattr(self, attr, 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@151: def generateAddMethod(attr, factory, infos): etisserant@75: def addMethod(self): lbessard@151: if infos["type"] == ATTRIBUTE: lbessard@151: if isinstance(infos["attr_type"], (UnicodeType, StringType)): lbessard@151: namespace, name = DecomposeQualifiedName(infos) lbessard@151: infos["attr_type"] = factory.GetQualifiedNameInfos(name, namespace) lbessard@151: initial = infos["attr_type"]["initial"] lbessard@151: extract = infos["attr_type"]["extract"] lbessard@151: elif infos["type"] == ELEMENT: lbessard@151: if isinstance(infos["elmt_type"], (UnicodeType, StringType)): lbessard@151: namespace, name = DecomposeQualifiedName(infos) lbessard@151: infos["elmt_type"] = factory.GetQualifiedNameInfos(name, namespace) lbessard@151: initial = infos["elmt_type"]["initial"] lbessard@151: extract = infos["elmt_type"]["extract"] lbessard@151: else: lbessard@151: raise ValueError, "Invalid class attribute!" lbessard@151: if "default" in infos: lbessard@151: setattr(self, attr, extract(infos["default"], False)) lbessard@151: else: lbessard@151: setattr(self, attr, initial()) 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: lbessard@151: def generateAppendMethod(attr, maxOccurs, factory, infos): etisserant@75: def appendMethod(self, value): lbessard@151: if isinstance(infos["elmt_type"], (UnicodeType, StringType)): lbessard@151: namespace, name = DecomposeQualifiedName(infos) lbessard@151: infos["elmt_type"] = factory.GetQualifiedNameInfos(name, namespace) lbessard@151: attr_list = getattr(self, attr) lbessard@151: if maxOccurs == "unbounded" or len(attr_list) < maxOccurs: lbessard@151: if infos["elmt_type"]["check"](value): lbessard@151: attr_list.append(value) lbessard@151: else: lbessard@151: raise ValueError, "\"%s\" value isn't valid!"%attr lbessard@151: else: lbessard@151: raise ValueError, "There can't be more than %d values in \"%s\"!"%(maxOccurs, attr) etisserant@75: return appendMethod etisserant@75: lbessard@151: def generateInsertMethod(attr, maxOccurs, factory, infos): etisserant@75: def insertMethod(self, index, value): lbessard@151: if isinstance(infos["elmt_type"], (UnicodeType, StringType)): lbessard@151: namespace, name = DecomposeQualifiedName(infos) lbessard@151: infos["elmt_type"] = factory.GetQualifiedNameInfos(name, namespace) lbessard@151: attr_list = getattr(self, attr) lbessard@151: if maxOccurs == "unbounded" or len(attr_list) < maxOccurs: lbessard@151: if infos["elmt_type"]["check"](value): lbessard@151: attr_list.insert(index, value) lbessard@151: else: lbessard@151: raise ValueError, "\"%s\" value isn't valid!"%attr lbessard@151: else: lbessard@151: raise ValueError, "There can't be more than %d values in \"%s\"!"%(maxOccurs, attr) etisserant@75: return insertMethod etisserant@75: lbessard@151: def generateGetChoicesMethod(choice_types): lbessard@151: def getChoicesMethod(self): lbessard@151: return [choice["name"] for choice in choice_types] lbessard@151: return getChoicesMethod lbessard@151: lbessard@151: def generateAddChoiceByTypeMethod(choice_types): lbessard@151: choices = dict([(choice["name"], choice) for choice in choice_types]) lbessard@83: def addChoiceMethod(self, name): lbessard@151: if name in choices: lbessard@151: if isinstance(choices["name"]["elmt_type"], (UnicodeType, StringType)): lbessard@151: namespace, name = DecomposeQualifiedName(infos) lbessard@151: choices["name"]["elmt_type"] = factory.GetQualifiedNameInfos(name, namespace) lbessard@151: self.content = {"name" : name, "value" : choices["name"]["elmt_type"]["initial"]()} lbessard@83: return addChoiceMethod lbessard@83: lbessard@151: def generateRemoveMethod(attr, minOccurs): etisserant@75: def removeMethod(self, index): lbessard@151: attr_list = getattr(self, attr) lbessard@151: if len(attr_list) > minOccurs: lbessard@151: getattr(self, attr).pop(index) lbessard@151: else: lbessard@151: raise ValueError, "There can't be less than %d values in \"%s\"!"%(minOccurs, attr) 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@151: ComputedClasses = factory.CreateClasses() lbessard@151: #factory.PrintClasses() 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@83: globals().update(ComputedClasses) lbessard@151: return ComputedClasses lbessard@151: