--- a/xmlclass/xmlclass.py Mon Aug 21 20:17:19 2017 +0000
+++ b/xmlclass/xmlclass.py Mon Aug 21 23:22:58 2017 +0300
@@ -22,7 +22,8 @@
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-import os, sys
+import os
+import sys
import re
import datetime
from types import *
@@ -32,6 +33,7 @@
from new import classobj
from collections import OrderedDict
+
def CreateNode(name):
node = minidom.Node()
node.nodeName = name
@@ -39,9 +41,11 @@
node.childNodes = []
return node
+
def NodeRenameAttr(node, old_name, new_name):
node._attrs[new_name] = node._attrs.pop(old_name)
+
def NodeSetAttr(node, name, value):
attr = minidom.Attr(name)
text = minidom.Text()
@@ -49,6 +53,7 @@
attr.childNodes[0] = text
node._attrs[name] = attr
+
"""
Regular expression models for checking all kind of string values defined in XML
standard
@@ -72,14 +77,15 @@
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.__offset = timedelta(minutes=0)
self.__name = "UTC"
else:
- sign = {"-" : -1, "+" : 1}[offset[0]]
+ 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 = ""
@@ -93,10 +99,13 @@
def dst(self, dt):
return ZERO
-[SYNTAXELEMENT, SYNTAXATTRIBUTE, SIMPLETYPE, COMPLEXTYPE, COMPILEDCOMPLEXTYPE,
- ATTRIBUTESGROUP, ELEMENTSGROUP, ATTRIBUTE, ELEMENT, CHOICE, ANY, TAG, CONSTRAINT,
+
+[
+ SYNTAXELEMENT, SYNTAXATTRIBUTE, SIMPLETYPE, COMPLEXTYPE, COMPILEDCOMPLEXTYPE,
+ ATTRIBUTESGROUP, ELEMENTSGROUP, ATTRIBUTE, ELEMENT, CHOICE, ANY, TAG, CONSTRAINT,
] = range(13)
+
def NotSupportedYet(type):
"""
Function that generates a function that point out to user that datatype
@@ -105,14 +114,14 @@
@return: function generated
"""
def GetUnknownValue(attr):
- raise ValueError("\"%s\" type isn't supported by \"xmlclass\" yet!" % \
- type)
+ 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):
+ """
+ This function calculates the number of whitespace for indentation
+ """
first = indent * 2
second = first + len(balise) + 1
return u'\t'.expandtabs(first), u'\t'.expandtabs(second)
@@ -140,7 +149,7 @@
def GetNormalizedString(attr, extract=True):
"""
- Function that normalizes a string according to XML 1.0. Replace
+ 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
@@ -155,14 +164,14 @@
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
+ 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
+ return " ".join([part for part in
GetNormalizedString(attr, extract).split(" ")
if part])
@@ -182,11 +191,11 @@
raise ValueError("\"%s\" isn't a valid hexadecimal integer!" % value)
try:
return int(value, 16)
- except:
+ except Exception:
raise ValueError("\"%s\" isn't a valid hexadecimal integer!" % value)
-def GenerateIntegerExtraction(minInclusive=None, maxInclusive=None,
+def GenerateIntegerExtraction(minInclusive=None, maxInclusive=None,
minExclusive=None, maxExclusive=None):
"""
Function that generates an extraction function for integer defining min and
@@ -212,19 +221,19 @@
try:
# TODO: permit to write value like 1E2
value = int(value)
- except:
+ except Exception:
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!" % \
+ 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!" % \
+ 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!" % \
+ 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!" % \
+ raise ValueError("\"%d\" isn't lesser than %d!" %
(value, maxExclusive))
return value
return GetInteger
@@ -236,7 +245,7 @@
@param type: name of the type of float
@return: function generated
"""
- def GetFloat(attr, extract = True):
+ 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
@@ -251,7 +260,7 @@
return value
try:
return float(value)
- except:
+ except Exception:
raise ValueError("\"%s\" isn't a valid %s!" % (value, type))
return GetFloat
@@ -401,7 +410,7 @@
raise ValueError("Member limit can't be defined to \"unbounded\"!")
try:
limit = int(value)
- except:
+ except Exception:
raise ValueError("\"%s\" isn't a valid value for this member limit!" % value)
if limit < 0:
raise ValueError("Member limit can't be negative!")
@@ -435,8 +444,8 @@
if value in list:
return value
else:
- raise ValueError("\"%s\" isn't a valid value for %s!" % \
- (value, type))
+ raise ValueError(
+ "\"%s\" isn't a valid value for %s!" % (value, type))
return GetEnumerated
@@ -497,8 +506,8 @@
if item in list:
values.append(item)
else:
- raise ValueError("\"%s\" isn't a valid value for %s!" % \
- (value, type))
+ raise ValueError(
+ "\"%s\" isn't a valid value for %s!" % (value, type))
return values
return GetLists
@@ -517,7 +526,7 @@
check that all extracted items 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
+ @return: data as a list of string if matching
"""
if extract:
value = GetAttributeValue(attr)
@@ -529,24 +538,24 @@
if result is not None:
values.append(item)
else:
- raise ValueError("\"%s\" isn't a valid value for %s!" % \
- (value, type))
+ raise ValueError("\"%s\" isn't a valid value for %s!" % (value, type))
return values
return GetModelNameList
+
def GenerateAnyInfos(infos):
-
+
def GetTextElement(tree):
if infos["namespace"][0] == "##any":
return tree.xpath("p")[0]
return tree.xpath("ns:p", namespaces={"ns": infos["namespace"][0]})[0]
-
+
def ExtractAny(tree):
return GetTextElement(tree).text
-
+
def GenerateAny(tree, value):
GetTextElement(tree).text = etree.CDATA(value)
-
+
def InitialAny():
if infos["namespace"][0] == "##any":
element_name = "p"
@@ -555,15 +564,16 @@
p = etree.Element(element_name)
p.text = etree.CDATA("")
return p
-
+
return {
- "type": COMPLEXTYPE,
+ "type": COMPLEXTYPE,
"extract": ExtractAny,
"generate": GenerateAny,
"initial": InitialAny,
"check": lambda x: isinstance(x, (StringType, UnicodeType, etree.ElementBase))
}
+
def GenerateTagInfos(infos):
def ExtractTag(tree):
if len(tree._attrs) > 0:
@@ -574,28 +584,30 @@
return True
else:
return None
-
+
def GenerateTag(value, name=None, indent=0):
if name is not None and not (infos["minOccurs"] == 0 and value is None):
ind1, ind2 = getIndent(indent, name)
return ind1 + "<%s/>\n" % name
else:
return ""
-
+
return {
- "type": TAG,
+ "type": TAG,
"extract": ExtractTag,
"generate": GenerateTag,
"initial": lambda: None,
- "check": lambda x: x == None or infos["minOccurs"] == 0 and value == True
+ "check": lambda x: x is None or infos["minOccurs"] == 0 and value
}
+
def FindTypeInfos(factory, infos):
if isinstance(infos, (UnicodeType, StringType)):
namespace, name = DecomposeQualifiedName(infos)
return factory.GetQualifiedNameInfos(name, namespace)
return infos
-
+
+
def GetElementInitialValue(factory, infos):
infos["elmt_type"] = FindTypeInfos(factory, infos["elmt_type"])
if infos["minOccurs"] == 1:
@@ -616,6 +628,7 @@
else:
return []
+
def GetContentInfos(name, choices):
for choice_infos in choices:
if choices_infos["type"] == "sequence":
@@ -629,6 +642,7 @@
return choices_infos
return None
+
def ComputeContentChoices(factory, name, infos):
choices = []
for choice in infos["choices"]:
@@ -649,6 +663,7 @@
choices.append((choice["name"], choice))
return choices
+
def GenerateContentInfos(factory, name, choices):
choices_dict = {}
for choice_name, infos in choices:
@@ -656,18 +671,18 @@
for element in infos["elements"]:
if element["type"] == CHOICE:
element["elmt_type"] = GenerateContentInfos(factory, name, ComputeContentChoices(factory, name, element))
- elif choices_dict.has_key(element["name"]):
+ elif element["name"] in choices_dict:
raise ValueError("'%s' element defined two times in choice" % choice_name)
else:
choices_dict[element["name"]] = infos
else:
- if choices_dict.has_key(choice_name):
+ if choice_name in choices_dict:
raise ValueError("'%s' element defined two times in choice" % choice_name)
choices_dict[choice_name] = infos
prefix = ("%s:" % factory.TargetNamespace
if factory.TargetNamespace is not None else "")
choices_xpath = "|".join(map(lambda x: prefix + x, choices_dict.keys()))
-
+
def GetContentInitial():
content_name, infos = choices[0]
if content_name == "sequence":
@@ -678,28 +693,29 @@
else:
content_value = GetElementInitialValue(factory, infos)
return content_value
-
+
return {
"type": COMPLEXTYPE,
"choices_xpath": etree.XPath(choices_xpath, namespaces=factory.NSMAP),
"initial": GetContentInitial,
}
-#-------------------------------------------------------------------------------
+# -------------------------------------------------------------------------------
# Structure extraction functions
-#-------------------------------------------------------------------------------
+# -------------------------------------------------------------------------------
def DecomposeQualifiedName(name):
result = QName_model.match(name)
if not result:
- raise ValueError("\"%s\" isn't a valid QName value!" % name)
+ 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,
+
+
+def GenerateElement(element_name, attributes, elements_model,
accept_text=False):
def ExtractElement(factory, node):
attrs = factory.ExtractNodeAttrs(element_name, node, attributes)
@@ -709,7 +725,7 @@
for child in node.childNodes:
if child.nodeName not in ["#comment", "#text"]:
namespace, childname = DecomposeQualifiedName(child.nodeName)
- children_structure += "%s "%childname
+ 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)
@@ -726,7 +742,7 @@
infos = factory.GetQualifiedNameInfos(childname, namespace)
if infos["type"] != SYNTAXELEMENT:
raise ValueError("\"%s\" can't be a member child!" % name)
- if infos["extract"].has_key(element_name):
+ if element_name in infos["extract"]:
children.append(infos["extract"][element_name](factory, child))
else:
children.append(infos["extract"]["default"](factory, child))
@@ -734,10 +750,10 @@
return ExtractElement
-"""
-Class that generate class from an XML Tree
-"""
class ClassFactory:
+ """
+ Class that generate class from an XML Tree
+ """
def __init__(self, document, filepath=None, debug=False):
self.Document = document
@@ -746,20 +762,20 @@
else:
self.BaseFolder = self.FileName = None
self.Debug = debug
-
+
# Dictionary for stocking Classes and Types definitions created from
# the XML tree
self.XMLClassDefinitions = {}
-
+
self.DefinedNamespaces = {}
self.NSMAP = {}
self.Namespaces = {}
self.SchemaNamespace = None
self.TargetNamespace = None
self.etreeNamespaceFormat = "%s"
-
+
self.CurrentCompilations = []
-
+
# Dictionaries for stocking Classes and Types generated
self.ComputeAfter = []
if self.FileName is not None:
@@ -773,36 +789,36 @@
def GetQualifiedNameInfos(self, name, namespace=None, canbenone=False):
if namespace is None:
- if self.Namespaces[self.SchemaNamespace].has_key(name):
+ if name in self.Namespaces[self.SchemaNamespace]:
return self.Namespaces[self.SchemaNamespace][name]
for space, elements in self.Namespaces.iteritems():
- if space != self.SchemaNamespace and elements.has_key(name):
+ 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 group.has_key("elements"):
+ if "elements" in group:
elements = group["elements"]
- elif group.has_key("choices"):
+ 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 self.Namespaces.has_key(namespace):
- if self.Namespaces[namespace].has_key(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 group.has_key("elements"):
+ if "elements" in group:
elements = group["elements"]
- elif group.has_key("choices"):
+ elif "choices" in group:
elements = group["choices"]
for element in elements:
if element["name"] == parts[1]:
@@ -815,36 +831,36 @@
def SplitQualifiedName(self, name, namespace=None, canbenone=False):
if namespace is None:
- if self.Namespaces[self.SchemaNamespace].has_key(name):
+ if name in self.Namespaces[self.SchemaNamespace]:
return name, None
for space, elements in self.Namespaces.items():
- if space != self.SchemaNamespace and elements.has_key(name):
+ 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 group.has_key("elements"):
+ if "elements" in group:
elements = group["elements"]
- elif group.has_key("choices"):
+ 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 self.Namespaces.has_key(namespace):
- if self.Namespaces[namespace].has_key(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 group.has_key("elements"):
+ if "elements" in group:
elements = group["elements"]
- elif group.has_key("choices"):
+ elif "choices" in group:
elements = group["choices"]
for element in elements:
if element["name"] == parts[1]:
@@ -858,7 +874,7 @@
def ExtractNodeAttrs(self, element_name, node, valid_attrs):
attrs = {}
for qualified_name, attr in node._attrs.items():
- namespace, name = DecomposeQualifiedName(qualified_name)
+ namespace, name = DecomposeQualifiedName(qualified_name)
if name in valid_attrs:
infos = self.GetQualifiedNameInfos(name, namespace)
if infos["type"] != SYNTAXATTRIBUTE:
@@ -878,9 +894,9 @@
raise ValueError("Invalid attribute \"%s\" for member \"%s\"!" % (qualified_name, node.nodeName))
for attr in valid_attrs:
if attr not in attrs and \
- self.Namespaces[self.SchemaNamespace].has_key(attr) and \
- self.Namespaces[self.SchemaNamespace][attr].has_key("default"):
- if self.Namespaces[self.SchemaNamespace][attr]["default"].has_key(element_name):
+ 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"]
@@ -892,7 +908,7 @@
result = []
for child_infos in elements:
if child_infos is not None:
- if child_infos[1].has_key("name") and schema:
+ 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)
@@ -901,7 +917,7 @@
element = infos["reduce"](self, child_infos[1], child_infos[2])
if element is not None:
result.append(element)
- if child_infos[1].has_key("name") and schema:
+ if "name" in child_infos[1] and schema:
self.CurrentCompilations.pop(-1)
annotations = []
children = []
@@ -913,22 +929,22 @@
return annotations, children
def AddComplexType(self, typename, infos):
- if not self.XMLClassDefinitions.has_key(typename):
+ 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 AddEquivalentClass(self, name, base):
if name != base:
equivalences = self.EquivalentClassesParent.setdefault(self.etreeNamespaceFormat % base, {})
equivalences[self.etreeNamespaceFormat % name] = True
-
+
def AddDistinctionBetweenParentsInLookupClass(
self, lookup_classes, parent, typeinfos):
- parent = (self.etreeNamespaceFormat % parent
+ parent = (self.etreeNamespaceFormat % parent
if parent is not None else None)
parent_class = lookup_classes.get(parent)
if parent_class is not None:
@@ -939,7 +955,7 @@
lookup_classes[parent] = [typeinfos, parent_class]
else:
lookup_classes[parent] = typeinfos
-
+
def AddToLookupClass(self, name, parent, typeinfos):
lookup_name = self.etreeNamespaceFormat % name
if isinstance(typeinfos, (StringType, UnicodeType)):
@@ -958,7 +974,7 @@
self.AddDistinctionBetweenParentsInLookupClass(
lookup_classes, parent, typeinfos)
self.ComputedClassesLookUp[lookup_name] = lookup_classes
-
+
def ExtractTypeInfos(self, name, parent, typeinfos):
if isinstance(typeinfos, (StringType, UnicodeType)):
namespace, type_name = DecomposeQualifiedName(typeinfos)
@@ -986,12 +1002,12 @@
return self.CreateClass(name, parent, typeinfos)
elif typeinfos["type"] == SIMPLETYPE:
return typeinfos
-
+
def GetEquivalentParents(self, parent):
return reduce(lambda x, y: x + y,
- [[p] + self.GetEquivalentParents(p)
- for p in self.EquivalentClassesParent.get(parent, {}).keys()], [])
-
+ [[p] + self.GetEquivalentParents(p)
+ for p in self.EquivalentClassesParent.get(parent, {}).keys()], [])
+
"""
Methods that generates the classes
"""
@@ -1015,9 +1031,9 @@
self.Namespaces[self.TargetNamespace][result["name"]] = result
elif infos["type"] == ELEMENTSGROUP:
elements = []
- if infos.has_key("elements"):
+ if "elements" in infos:
elements = infos["elements"]
- elif infos.has_key("choices"):
+ elif "choices" in infos:
elements = infos["choices"]
for element in elements:
if not isinstance(element["elmt_type"], (UnicodeType, StringType)) and \
@@ -1028,7 +1044,7 @@
if result is not None and \
not isinstance(result, (UnicodeType, StringType)):
self.Namespaces[self.TargetNamespace][result["name"]] = result
-
+
for name, parents in self.ComputedClassesLookUp.iteritems():
if isinstance(parents, DictType):
computed_classes = parents.items()
@@ -1042,19 +1058,19 @@
parents = dict(computed_classes)
self.ComputedClassesLookUp[name] = parents
parents[equivalent_parent] = computed_class
-
+
return self.ComputedClasses
- def CreateClass(self, name, parent, classinfos, baseclass = False):
+ 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):
return self.ComputedClassesInfos.get(classname, None)
-
+
# If base classes haven't been generated
bases = []
base_infos = classinfos.get("base", None)
@@ -1088,29 +1104,29 @@
bases.append(DefaultElementClass)
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 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["add%s"%attrname] = generateAddMethod(attrname, self, attribute)
- classmembers["delete%s"%attrname] = generateDeleteMethod(attrname)
- classmembers["set%s"%attrname] = generateSetMethod(attrname)
- classmembers["get%s"%attrname] = generateGetMethod(attrname)
+ classmembers["add%s" % attrname] = generateAddMethod(attrname, self, attribute)
+ classmembers["delete%s" % attrname] = generateDeleteMethod(attrname)
+ 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 = ComputeContentChoices(self, name, element)
- classmembers["get%schoices"%elmtname] = generateGetChoicesMethod(element["choices"])
+ classmembers["get%schoices" % elmtname] = generateGetChoicesMethod(element["choices"])
if element["maxOccurs"] == "unbounded" or element["maxOccurs"] > 1:
classmembers["append%sbytype" % elmtname] = generateAppendChoiceByTypeMethod(element["maxOccurs"], self, element["choices"])
classmembers["insert%sbytype" % elmtname] = generateInsertChoiceByTypeMethod(element["maxOccurs"], self, element["choices"])
@@ -1141,30 +1157,31 @@
classmembers["delete%s" % elmtname] = generateDeleteMethod(elmtname)
classmembers["set%s" % elmtname] = generateSetMethod(elmtname)
classmembers["get%s" % elmtname] = generateGetMethod(elmtname)
-
+
classmembers["_init_"] = generateInitMethod(self, classinfos)
classmembers["StructurePattern"] = GetStructurePattern(classinfos)
classmembers["getElementAttributes"] = generateGetElementAttributes(self, classinfos)
classmembers["getElementInfos"] = generateGetElementInfos(self, classinfos)
classmembers["setElementValue"] = generateSetElementValue(self, classinfos)
-
+
class_definition = classobj(str(name), bases, classmembers)
setattr(class_definition, "__getattr__", generateGetattrMethod(self, class_definition, classinfos))
setattr(class_definition, "__setattr__", generateSetattrMethod(self, class_definition, classinfos))
- class_infos = {"type": COMPILEDCOMPLEXTYPE,
- "name": classname,
- "initial": generateClassCreateFunction(class_definition),
+ class_infos = {
+ "type": COMPILEDCOMPLEXTYPE,
+ "name": classname,
+ "initial": generateClassCreateFunction(class_definition),
}
-
+
if self.FileName is not None:
self.ComputedClasses[self.FileName][classname] = class_definition
else:
self.ComputedClasses[classname] = class_definition
self.ComputedClassesInfos[classname] = class_infos
-
+
self.AddToLookupClass(name, parent, class_definition)
self.AddToLookupClass(classname, None, class_definition)
-
+
return class_infos
"""
@@ -1183,18 +1200,19 @@
else:
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 generating the xml tree structure model by
-following the attributes list defined
-"""
+
def ComputeMultiplicity(name, infos):
+ """
+ Method that generate the method for generating the xml tree structure model by
+ following the attributes list defined
+ """
if infos["minOccurs"] == 0:
if infos["maxOccurs"] == "unbounded":
return "(?:%s)*" % name
@@ -1213,13 +1231,15 @@
if infos["maxOccurs"] == "unbounded":
return "(?:%s){%d,}" % (name, infos["minOccurs"], name)
else:
- return "(?:%s){%d,%d}" % (name, infos["minOccurs"],
- infos["maxOccurs"])
+ return "(?:%s){%d,%d}" % (name,
+ infos["minOccurs"],
+ infos["maxOccurs"])
+
def GetStructurePattern(classinfos):
base_structure_pattern = (
classinfos["base"].StructurePattern.pattern[:-1]
- if classinfos.has_key("base") else "")
+ if "base" in classinfos else "")
elements = []
for element in classinfos["elements"]:
if element["type"] == ANY:
@@ -1244,33 +1264,35 @@
else:
raise ValueError("XSD structure not yet supported!")
-"""
-Method that generate the method for creating a class instance
-"""
+
def generateClassCreateFunction(class_definition):
+ """
+ Method that generate the method for creating a class instance
+ """
def classCreatefunction():
return class_definition()
return classCreatefunction
+
def generateGetattrMethod(factory, class_definition, classinfos):
attributes = dict([(attr["name"], attr) for attr in classinfos["attributes"] if attr["use"] != "prohibited"])
optional_attributes = dict([(attr["name"], True) for attr in classinfos["attributes"] if attr["use"] == "optional"])
elements = dict([(element["name"], element) for element in classinfos["elements"]])
-
+
def getattrMethod(self, name):
- if attributes.has_key(name):
+ if name in attributes:
attribute_infos = attributes[name]
attribute_infos["attr_type"] = FindTypeInfos(factory, attribute_infos["attr_type"])
value = self.get(name)
if value is not None:
return attribute_infos["attr_type"]["extract"](value, extract=False)
- elif attribute_infos.has_key("fixed"):
+ elif "fixed" in attribute_infos:
return attribute_infos["attr_type"]["extract"](attribute_infos["fixed"], extract=False)
- elif attribute_infos.has_key("default"):
+ elif "default" in attribute_infos:
return attribute_infos["attr_type"]["extract"](attribute_infos["default"], extract=False)
return None
-
- elif elements.has_key(name):
+
+ elif name in elements:
element_infos = elements[name]
element_infos["elmt_type"] = FindTypeInfos(factory, element_infos["elmt_type"])
if element_infos["type"] == CHOICE:
@@ -1279,7 +1301,7 @@
return content
elif len(content) > 0:
return content[0]
- return None
+ return None
elif element_infos["type"] == ANY:
return element_infos["elmt_type"]["extract"](self)
elif name == "content" and element_infos["elmt_type"]["type"] == SIMPLETYPE:
@@ -1290,29 +1312,30 @@
values = self.findall(element_name)
if element_infos["elmt_type"]["type"] == SIMPLETYPE:
return map(lambda value:
- element_infos["elmt_type"]["extract"](value.text, extract=False),
- values)
+ element_infos["elmt_type"]["extract"](value.text, extract=False),
+ values)
return values
else:
value = self.find(element_name)
if element_infos["elmt_type"]["type"] == SIMPLETYPE:
return element_infos["elmt_type"]["extract"](value.text, extract=False)
return value
-
- elif classinfos.has_key("base"):
+
+ elif "base" in classinfos:
return classinfos["base"].__getattr__(self, name)
-
+
return DefaultElementClass.__getattribute__(self, name)
-
+
return getattrMethod
+
def generateSetattrMethod(factory, class_definition, classinfos):
attributes = dict([(attr["name"], attr) for attr in classinfos["attributes"] if attr["use"] != "prohibited"])
optional_attributes = dict([(attr["name"], True) for attr in classinfos["attributes"] if attr["use"] == "optional"])
elements = OrderedDict([(element["name"], element) for element in classinfos["elements"]])
-
+
def setattrMethod(self, name, value):
- if attributes.has_key(name):
+ if name in attributes:
attribute_infos = attributes[name]
attribute_infos["attr_type"] = FindTypeInfos(factory, attribute_infos["attr_type"])
if optional_attributes.get(name, False):
@@ -1320,65 +1343,66 @@
if value is None or value == default:
self.attrib.pop(name, None)
return
- elif attribute_infos.has_key("fixed"):
+ elif "fixed" in attribute_infos:
return
return self.set(name, attribute_infos["attr_type"]["generate"](value))
-
- elif elements.has_key(name):
+
+ elif name in elements:
element_infos = elements[name]
element_infos["elmt_type"] = FindTypeInfos(factory, element_infos["elmt_type"])
if element_infos["type"] == ANY:
element_infos["elmt_type"]["generate"](self, value)
-
+
elif name == "content" and element_infos["elmt_type"]["type"] == SIMPLETYPE:
self.text = element_infos["elmt_type"]["generate"](value)
-
+
else:
prefix = ("%s:" % factory.TargetNamespace
if factory.TargetNamespace is not None else "")
element_xpath = (prefix + name
if name != "content"
else elements["content"]["elmt_type"]["choices_xpath"].path)
-
+
for element in self.xpath(element_xpath, namespaces=factory.NSMAP):
self.remove(element)
-
+
if value is not None:
element_idx = elements.keys().index(name)
if element_idx > 0:
previous_elements_xpath = "|".join(map(
lambda x: prefix + x
- if x != "content"
- else elements["content"]["elmt_type"]["choices_xpath"].path,
+ if x != "content"
+ else elements["content"]["elmt_type"]["choices_xpath"].path,
elements.keys()[:element_idx]))
-
+
insertion_point = len(self.xpath(previous_elements_xpath, namespaces=factory.NSMAP))
else:
insertion_point = 0
-
+
if not isinstance(value, ListType):
value = [value]
-
+
for element in reversed(value):
if element_infos["elmt_type"]["type"] == SIMPLETYPE:
tmp_element = etree.Element(factory.etreeNamespaceFormat % name)
tmp_element.text = element_infos["elmt_type"]["generate"](element)
element = tmp_element
self.insert(insertion_point, element)
-
- elif classinfos.has_key("base"):
+
+ elif "base" in classinfos:
return classinfos["base"].__setattr__(self, name, value)
-
+
else:
raise AttributeError("'%s' can't have an attribute '%s'." % (self.__class__.__name__, name))
-
+
return setattrMethod
+
def gettypeinfos(name, facets):
- if facets.has_key("enumeration") and facets["enumeration"][0] is not None:
+ if "enumeration" in facets and facets["enumeration"][0] is not None:
return facets["enumeration"][0]
- elif facets.has_key("maxInclusive"):
- limits = {"max" : None, "min" : None}
+ 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:
@@ -1391,24 +1415,28 @@
return limits
return name
+
def generateGetElementAttributes(factory, classinfos):
def getElementAttributes(self):
attr_list = []
- if classinfos.has_key("base"):
+ if "base" in classinfos:
attr_list.extend(classinfos["base"].getElementAttributes(self))
for attr in classinfos["attributes"]:
if attr["use"] != "prohibited":
- attr_params = {"name" : attr["name"], "use" : attr["use"],
- "type" : gettypeinfos(attr["attr_type"]["basename"], attr["attr_type"]["facets"]),
- "value" : getattr(self, attr["name"], "")}
+ attr_params = {
+ "name": attr["name"],
+ "use": attr["use"],
+ "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, derived=False):
attr_type = "element"
value = None
@@ -1416,17 +1444,17 @@
children = []
if path is not None:
parts = path.split(".", 1)
- if attributes.has_key(parts[0]):
+ if parts[0] in attributes:
if len(parts) != 1:
raise ValueError("Wrong path!")
- attr_type = gettypeinfos(attributes[parts[0]]["attr_type"]["basename"],
+ attr_type = gettypeinfos(attributes[parts[0]]["attr_type"]["basename"],
attributes[parts[0]]["attr_type"]["facets"])
value = getattr(self, parts[0], "")
- elif elements.has_key(parts[0]):
+ elif parts[0] in elements:
if elements[parts[0]]["elmt_type"]["type"] == SIMPLETYPE:
if len(parts) != 1:
raise ValueError("Wrong path!")
- attr_type = gettypeinfos(elements[parts[0]]["elmt_type"]["basename"],
+ attr_type = gettypeinfos(elements[parts[0]]["elmt_type"]["basename"],
elements[parts[0]]["elmt_type"]["facets"])
value = getattr(self, parts[0], "")
elif parts[0] == "content":
@@ -1439,17 +1467,17 @@
return attr.getElementInfos(parts[0])
else:
return attr.getElementInfos(parts[0], parts[1])
- elif elements.has_key("content"):
+ elif "content" in elements:
if len(parts) > 0:
return self.content.getElementInfos(name, path)
- elif classinfos.has_key("base"):
+ elif "base" in classinfos:
classinfos["base"].getElementInfos(name, path)
else:
raise ValueError("Wrong path!")
else:
if not derived:
children.extend(self.getElementAttributes())
- if classinfos.has_key("base"):
+ if "base" in classinfos:
children.extend(classinfos["base"].getElementInfos(self, name, derived=True)["children"])
for element_name, element in elements.items():
if element["minOccurs"] == 0:
@@ -1463,8 +1491,10 @@
if self.content is not None:
children.extend(self.content.getElementInfos(value)["children"])
elif element["elmt_type"]["type"] == SIMPLETYPE:
- children.append({"name": element_name, "require": element["minOccurs"] != 0,
- "type": gettypeinfos(element["elmt_type"]["basename"],
+ 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:
@@ -1475,28 +1505,29 @@
return {"name": name, "type": attr_type, "value": value, "use": use, "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 path is not None:
parts = path.split(".", 1)
- if attributes.has_key(parts[0]):
+ 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)
elif attributes[parts[0]]["use"] == "optional" and value == "":
- if attributes[parts[0]].has_key("default"):
- setattr(self, parts[0],
- attributes[parts[0]]["attr_type"]["extract"](
- attributes[parts[0]]["default"], False))
+ if "default" in attributes[parts[0]]:
+ setattr(self, parts[0],
+ attributes[parts[0]]["attr_type"]["extract"](
+ attributes[parts[0]]["default"], False))
else:
setattr(self, parts[0], None)
else:
setattr(self, parts[0], attributes[parts[0]]["attr_type"]["extract"](value, False))
- elif elements.has_key(parts[0]):
+ elif parts[0] in elements:
if elements[parts[0]]["elmt_type"]["type"] == SIMPLETYPE:
if len(parts) != 1:
raise ValueError("Wrong path!")
@@ -1511,17 +1542,17 @@
if instance is None and elements[parts[0]]["minOccurs"] == 0:
instance = elements[parts[0]]["elmt_type"]["initial"]()
setattr(self, parts[0], instance)
- if instance != None:
+ if instance is not None:
if len(parts) > 1:
instance.setElementValue(parts[1], value)
else:
instance.setElementValue(None, value)
- elif elements.has_key("content"):
+ elif "content" in elements:
if len(parts) > 0:
self.content.setElementValue(path, value)
- elif classinfos.has_key("base"):
+ elif "base" in classinfos:
classinfos["base"].setElementValue(self, path, value)
- elif elements.has_key("content"):
+ elif "content" in elements:
if value == "":
if elements["content"]["minOccurs"] == 0:
self.setcontent([])
@@ -1531,12 +1562,14 @@
self.setcontentbytype(value)
return setElementValue
-"""
-Methods that generates the different methods for setting and getting the attributes
-"""
+
def generateInitMethod(factory, classinfos):
+ """
+ Methods that generates the different methods for setting and getting the attributes
+ """
+
def initMethod(self):
- if classinfos.has_key("base"):
+ if "base" in classinfos:
classinfos["base"]._init_(self)
for attribute in classinfos["attributes"]:
attribute["attr_type"] = FindTypeInfos(factory, attribute["attr_type"])
@@ -1553,21 +1586,24 @@
map(self.append, initial)
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:
infos["attr_type"] = FindTypeInfos(factory, infos["attr_type"])
- if not infos.has_key("default"):
+ if "default" not in infos:
setattr(self, attr, infos["attr_type"]["initial"]())
elif infos["type"] == ELEMENT:
infos["elmt_type"] = FindTypeInfos(factory, infos["elmt_type"])
@@ -1579,11 +1615,13 @@
raise ValueError("Invalid class attribute!")
return addMethod
+
def generateDeleteMethod(attr):
def deleteMethod(self):
setattr(self, attr, None)
return deleteMethod
+
def generateAppendMethod(attr, maxOccurs, factory, infos):
def appendMethod(self, value):
infos["elmt_type"] = FindTypeInfos(factory, infos["elmt_type"])
@@ -1597,6 +1635,7 @@
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):
infos["elmt_type"] = FindTypeInfos(factory, infos["elmt_type"])
@@ -1612,15 +1651,18 @@
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 generateSetChoiceByTypeMethod(factory, choice_types):
choices = dict([(choice["name"], choice) for choice in choice_types])
+
def setChoiceMethod(self, content_type):
- if not choices.has_key(content_type):
+ if content_type not in choices:
raise ValueError("Unknown \"%s\" choice type for \"content\"!" % content_type)
choices[content_type]["elmt_type"] = FindTypeInfos(factory, choices[content_type]["elmt_type"])
new_content = choices[content_type]["elmt_type"]["initial"]()
@@ -1629,10 +1671,12 @@
return new_content
return setChoiceMethod
+
def generateAppendChoiceByTypeMethod(maxOccurs, factory, choice_types):
choices = dict([(choice["name"], choice) for choice in choice_types])
+
def appendChoiceMethod(self, content_type):
- if not choices.has_key(content_type):
+ if content_type not in choices:
raise ValueError("Unknown \"%s\" choice type for \"content\"!" % content_type)
choices[content_type]["elmt_type"] = FindTypeInfos(factory, choices[content_type]["elmt_type"])
if maxOccurs == "unbounded" or len(self.content) < maxOccurs:
@@ -1644,10 +1688,12 @@
raise ValueError("There can't be more than %d values in \"content\"!" % maxOccurs)
return appendChoiceMethod
+
def generateInsertChoiceByTypeMethod(maxOccurs, factory, choice_types):
choices = dict([(choice["name"], choice) for choice in choice_types])
+
def insertChoiceMethod(self, index, content_type):
- if not choices.has_key(content_type):
+ if content_type not in choices:
raise ValueError("Unknown \"%s\" choice type for \"content\"!" % content_type)
choices[type]["elmt_type"] = FindTypeInfos(factory, choices[content_type]["elmt_type"])
if maxOccurs == "unbounded" or len(self.content) < maxOccurs:
@@ -1659,6 +1705,7 @@
raise ValueError("There can't be more than %d values in \"content\"!" % maxOccurs)
return insertChoiceMethod
+
def generateRemoveMethod(attr, minOccurs):
def removeMethod(self, index):
attr_list = getattr(self, attr)
@@ -1668,52 +1715,56 @@
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 a xml parser from a class factory
"""
NAMESPACE_PATTERN = re.compile("xmlns(?:\:[^\=]*)?=\"[^\"]*\" ")
+
class DefaultElementClass(etree.ElementBase):
-
+
StructurePattern = re.compile("$")
-
+
def _init_(self):
pass
-
+
def getLocalTag(self):
return etree.QName(self.tag).localname
-
+
def tostring(self):
return NAMESPACE_PATTERN.sub("", etree.tostring(self, pretty_print=True, encoding='utf-8')).decode('utf-8')
+
class XMLElementClassLookUp(etree.PythonElementClassLookup):
-
+
def __init__(self, classes, *args, **kwargs):
etree.PythonElementClassLookup.__init__(self, *args, **kwargs)
self.LookUpClasses = classes
-
+
def GetElementClass(self, element_tag, parent_tag=None, default=DefaultElementClass):
element_class = self.LookUpClasses.get(element_tag, (default, None))
if not isinstance(element_class, DictType):
if isinstance(element_class[0], (StringType, UnicodeType)):
return self.GetElementClass(element_class[0], default=default)
return element_class[0]
-
+
element_with_parent_class = element_class.get(parent_tag, default)
if isinstance(element_with_parent_class, (StringType, UnicodeType)):
return self.GetElementClass(element_with_parent_class, default=default)
return element_with_parent_class
-
+
def lookup(self, document, element):
parent = element.getparent()
- element_class = self.GetElementClass(element.tag,
- parent.tag if parent is not None else None)
+ element_class = self.GetElementClass(
+ element.tag, parent.tag if parent is not None else None)
if isinstance(element_class, ListType):
children = "".join([
"%s " % etree.QName(child.tag).localname
@@ -1726,6 +1777,7 @@
return element_class[0]
return element_class
+
class XMLClassParser(etree.XMLParser):
def __init__(self, namespaces, default_namespace_format, base_class, xsd_schema, *args, **kwargs):
@@ -1741,24 +1793,24 @@
self.RootNSMAP = namespaces
self.BaseClass = base_class
self.XSDSchema = xsd_schema
-
+
def set_element_class_lookup(self, class_lookup):
etree.XMLParser.set_element_class_lookup(self, class_lookup)
self.ClassLookup = class_lookup
-
+
def LoadXMLString(self, xml_string):
tree = etree.fromstring(xml_string, self)
if not self.XSDSchema.validate(tree):
error = self.XSDSchema.error_log.last_error
return tree, (error.line, error.message)
- return tree, None
-
+ return tree, None
+
def Dumps(self, xml_obj):
return etree.tostring(xml_obj, encoding='utf-8')
-
+
def Loads(self, xml_string):
return etree.fromstring(xml_string, self)
-
+
def CreateRoot(self):
if self.BaseClass is not None:
root = self.makeelement(
@@ -1767,42 +1819,42 @@
root._init_()
return root
return None
-
+
def GetElementClass(self, element_tag, parent_tag=None):
return self.ClassLookup.GetElementClass(
- self.DefaultNamespaceFormat % element_tag,
- self.DefaultNamespaceFormat % parent_tag
- if parent_tag is not None else parent_tag,
+ self.DefaultNamespaceFormat % element_tag,
+ self.DefaultNamespaceFormat % parent_tag
+ if parent_tag is not None else parent_tag,
None)
-
+
def CreateElement(self, element_tag, parent_tag=None, class_idx=None):
element_class = self.GetElementClass(element_tag, parent_tag)
if isinstance(element_class, ListType):
if class_idx is not None and class_idx < len(element_class):
new_element = element_class[class_idx]()
else:
- raise ValueError, "No corresponding class found!"
+ raise ValueError("No corresponding class found!")
else:
new_element = element_class()
DefaultElementClass.__setattr__(new_element, "tag", self.DefaultNamespaceFormat % element_tag)
new_element._init_()
return new_element
-
+
+
def GenerateParser(factory, xsdstring):
ComputedClasses = factory.CreateClasses()
-
+
if factory.FileName is not None:
ComputedClasses = ComputedClasses[factory.FileName]
BaseClass = [(name, XSDclass) for name, XSDclass in ComputedClasses.items() if XSDclass.IsBaseClass]
-
+
parser = XMLClassParser(
factory.NSMAP,
factory.etreeNamespaceFormat,
BaseClass[0] if len(BaseClass) == 1 else None,
etree.XMLSchema(etree.fromstring(xsdstring)),
- strip_cdata = False, remove_blank_text=True)
+ strip_cdata=False, remove_blank_text=True)
class_lookup = XMLElementClassLookUp(factory.ComputedClassesLookUp)
parser.set_element_class_lookup(class_lookup)
-
+
return parser
-