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