--- a/xmlclass/xmlclass.py Fri Nov 18 17:40:40 2011 +0100
+++ b/xmlclass/xmlclass.py Wed Nov 23 00:19:27 2011 +0100
@@ -22,7 +22,7 @@
#License along with this library; if not, write to the Free Software
#Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-import sys
+import os, sys
import re
import datetime
from types import *
@@ -92,8 +92,8 @@
return ZERO
[SYNTAXELEMENT, SYNTAXATTRIBUTE, SIMPLETYPE, COMPLEXTYPE, COMPILEDCOMPLEXTYPE,
- ATTRIBUTESGROUP, ELEMENTSGROUP, ATTRIBUTE, ELEMENT, CHOICE, ANY, TAG
-] = range(12)
+ ATTRIBUTESGROUP, ELEMENTSGROUP, ATTRIBUTE, ELEMENT, CHOICE, ANY, TAG, CONSTRAINT,
+] = range(13)
def NotSupportedYet(type):
"""
@@ -126,13 +126,13 @@
if not extract:
return attr
if len(attr.childNodes) == 1:
- return unescape(attr.childNodes[0].data.encode())
+ return unescape(attr.childNodes[0].data.encode("utf-8"))
else:
# content is a CDATA
text = ""
for node in attr.childNodes:
if node.nodeName != "#text":
- text += node.data.encode()
+ text += node.data.encode("utf-8")
return text
@@ -532,23 +532,29 @@
return values
return GetModelNameList
-def GenerateAnyInfos():
+def GenerateAnyInfos(infos):
def ExtractAny(tree):
- return tree.data.encode("utf-8")
+ if tree.nodeName == "#cdata-section":
+ return tree.data.encode("utf-8")
+ else:
+ return tree
def GenerateAny(value, name=None, indent=0):
- try:
- value = value.decode("utf-8")
- except:
- pass
- return u'<![CDATA[%s]]>\n' % value
+ if isinstance(value, (StringType, UnicodeType)):
+ try:
+ value = value.decode("utf-8")
+ except:
+ pass
+ return u'<![CDATA[%s]]>\n' % value
+ else:
+ return value.toprettyxml(indent=" "*indent, encoding="utf-8")
return {
"type": COMPLEXTYPE,
"extract": ExtractAny,
"generate": GenerateAny,
"initial": lambda: "",
- "check": lambda x: isinstance(x, (StringType, UnicodeType))
+ "check": lambda x: isinstance(x, (StringType, UnicodeType, minidom.Node))
}
def GenerateTagInfos(name):
@@ -573,80 +579,239 @@
"initial": lambda: None,
"check": lambda x: x == None
}
+
+def FindTypeInfos(factory, infos):
+ if isinstance(infos, (UnicodeType, StringType)):
+ namespace, name = DecomposeQualifiedName(infos)
+ return factory.GetQualifiedNameInfos(name, namespace)
+ return infos
-def GenerateContentInfos(factory, choices):
+def GetElementInitialValue(factory, infos):
+ infos["elmt_type"] = FindTypeInfos(factory, infos["elmt_type"])
+ if infos["minOccurs"] == 0 and infos["maxOccurs"] == 1:
+ if infos.has_key("default"):
+ return infos["elmt_type"]["extract"](infos["default"], False)
+ else:
+ return None
+ elif infos["minOccurs"] == 1 and infos["maxOccurs"] == 1:
+ return infos["elmt_type"]["initial"]()
+ else:
+ return [infos["elmt_type"]["initial"]() for i in xrange(infos["minOccurs"])]
+
+def HandleError(message, raise_exception):
+ if raise_exception:
+ raise ValueError(message)
+ return False
+
+def CheckElementValue(factory, name, infos, value, raise_exception=True):
+ infos["elmt_type"] = FindTypeInfos(factory, infos["elmt_type"])
+ if value is None and raise_exception:
+ if not (infos["minOccurs"] == 0 and infos["maxOccurs"] == 1):
+ return HandleError("Attribute '%s' isn't optional." % name, raise_exception)
+ elif infos["maxOccurs"] == "unbounded" or infos["maxOccurs"] > 1:
+ if not isinstance(value, ListType):
+ return HandleError("Attribute '%s' must be a list." % name, raise_exception)
+ if len(value) < infos["minOccurs"] or infos["maxOccurs"] != "unbounded" and len(value) > infos["maxOccurs"]:
+ return HandleError("List out of bounds for attribute '%s'." % name, raise_exception)
+ if not reduce(lambda x, y: x and y, map(infos["elmt_type"]["check"], value), True):
+ return HandleError("Attribute '%s' must be a list of valid elements." % name, raise_exception)
+ elif infos.has_key("fixed") and value != infos["fixed"]:
+ return HandleError("Value of attribute '%s' can only be '%s'." % (name, str(infos["fixed"])), raise_exception)
+ else:
+ return infos["elmt_type"]["check"](value)
+ return True
+
+def GetContentInfos(name, choices):
+ for choice_infos in choices:
+ if choices_infos["type"] == "sequence":
+ for element_infos in choices_infos["elements"]:
+ if element_infos["type"] == CHOICE:
+ if GetContentInfos(name, element_infos["choices"]):
+ return choices_infos
+ elif element_infos["name"] == name:
+ return choices_infos
+ elif choice_infos["name"] == name:
+ return choices_infos
+ return None
+
+def ComputeContentChoices(factory, name, infos):
+ choices = []
+ for choice in infos["choices"]:
+ if choice["type"] == "sequence":
+ choice["name"] = "sequence"
+ for sequence_element in choice["elements"]:
+ if sequence_element["type"] != CHOICE:
+ element_infos = factory.ExtractTypeInfos(sequence_element["name"], name, sequence_element["elmt_type"])
+ if element_infos is not None:
+ sequence_element["elmt_type"] = element_infos
+ elif choice["elmt_type"] == "tag":
+ choice["elmt_type"] = GenerateTagInfos(choice["name"])
+ else:
+ choice_infos = factory.ExtractTypeInfos(choice["name"], name, choice["elmt_type"])
+ if choice_infos is not None:
+ choice["elmt_type"] = choice_infos
+ choices.append((choice["name"], choice))
+ return choices
+
+def ExtractContentElement(factory, tree, infos, content):
+ infos["elmt_type"] = FindTypeInfos(factory, infos["elmt_type"])
+ if infos["maxOccurs"] == "unbounded" or infos["maxOccurs"] > 1:
+ if isinstance(content, ListType) and len(content) > 0 and \
+ content[-1]["name"] == tree.nodeName:
+ 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"] == tree.nodeName:
+ return {"name": tree.nodeName,
+ "value": content["value"] + [infos["elmt_type"]["extract"](tree)]}
+ else:
+ return {"name": tree.nodeName,
+ "value": [infos["elmt_type"]["extract"](tree)]}
+ else:
+ return {"name": tree.nodeName,
+ "value": infos["elmt_type"]["extract"](tree)}
+
+def GenerateContentInfos(factory, name, choices):
+ choices_dict = {}
+ for choice_name, infos in choices:
+ if choice_name == "sequence":
+ 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"]):
+ 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):
+ raise ValueError("'%s' element defined two times in choice" % choice_name)
+ choices_dict[choice_name] = infos
+
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"]()}
+ if content_name == "sequence":
+ content_value = []
+ for i in xrange(infos["minOccurs"]):
+ for element_infos in infos["elements"]:
+ value = GetElementInitialValue(factory, element_infos)
+ if value is not None:
+ if element_infos["type"] == CHOICE:
+ content_value.append(value)
+ else:
+ content_value.append({"name": element_infos["name"], "value": value})
+ else:
+ content_value = GetElementInitialValue(factory, infos)
+ return {"name": content_name, "value": content_value}
+
+ def CheckContent(value):
+ if value["name"] != "sequence":
+ infos = choices_dict.get(value["name"], None)
+ if infos is not None:
+ return CheckElementValue(factory, value["name"], infos, value["value"], False)
+ elif len(value["value"]) > 0:
+ infos = choices_dict.get(value["value"][0]["name"], None)
+ if infos is None:
+ for choice_name, infos in choices:
+ if infos["type"] == "sequence":
+ for element_infos in infos["elements"]:
+ if element_infos["type"] == CHOICE:
+ infos = GetContentInfos(value["value"][0]["name"], element_infos["choices"])
+ if infos is not None:
+ sequence_number = 0
+ element_idx = 0
+ while element_idx < len(value["value"]):
+ for element_infos in infos["elements"]:
+ if element_infos["name"] == value["value"][element_idx]["name"]:
+ element_value = value["value"][element_idx]["value"]
+ element_idx += 1
+ else:
+ element_value = None
+ if not CheckElementValue(factory, element_infos["name"], element_infos, element_value, False):
+ raise ValueError("Invalid sequence value in attribute 'content'")
+ sequence_number += 1
+ if sequence_number < infos["minOccurs"] or infos["maxOccurs"] != "unbounded" and sequence_number > infos["maxOccurs"]:
+ raise ValueError("Invalid sequence value in attribute 'content'")
+ return True
+ else:
+ for element_name, infos in choices:
+ if element_name == "sequence":
+ required = 0
+ for element in infos["elements"]:
+ if element["minOccurs"] > 0:
+ required += 1
+ if required == 0:
+ return True
+ return False
- 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)}
+ infos = choices_dict.get(tree.nodeName, None)
+ if infos is not None:
+ if infos["name"] == "sequence":
+ sequence_dict = dict([(element_infos["name"], element_infos) for element_infos in infos["elements"] if element_infos["type"] != CHOICE])
+ element_infos = sequence_dict.get(tree.nodeName)
+ if content is not None and \
+ content["name"] == "sequence" and \
+ len(content["value"]) > 0 and \
+ choices_dict.get(content["value"][-1]["name"]) == infos:
+ return {"name": "sequence",
+ "value": content["value"] + [ExtractContentElement(factory, tree, element_infos, content["value"][-1])]}
+ else:
+ return {"name": "sequence",
+ "value": [ExtractContentElement(factory, tree, element_infos, None)]}
+ else:
+ return ExtractContentElement(factory, tree, infos, content)
+ else:
+ for choice_name, infos in choices:
+ if infos["type"] == "sequence":
+ for element_infos in infos["elements"]:
+ if element_infos["type"] == CHOICE:
+ try:
+ if content is not None and \
+ content["name"] == "sequence" and \
+ len(content["value"]) > 0:
+ return {"name": "sequence",
+ "value": content["value"] + [element_infos["elmt_type"]["extract"](tree, content["value"][-1])]}
+ else:
+ return {"name": "sequence",
+ "value": [element_infos["elmt_type"]["extract"](tree, None)]}
+ except:
+ pass
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)
+ text = ""
+ if value["name"] != "sequence":
+ infos = choices_dict.get(value["name"], None)
+ if infos is not None:
+ infos["elmt_type"] = FindTypeInfos(factory, infos["elmt_type"])
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 ""
+ text += infos["elmt_type"]["generate"](item, value["name"], indent)
+ else:
+ text += infos["elmt_type"]["generate"](value["value"], value["name"], indent)
+ elif len(value["value"]) > 0:
+ infos = choices_dict.get(value["value"][0]["name"], None)
+ if infos is None:
+ for choice_name, infos in choices:
+ if infos["type"] == "sequence":
+ for element_infos in infos["elements"]:
+ if element_infos["type"] == CHOICE:
+ infos = GetContentInfos(value["value"][0]["name"], element_infos["choices"])
+ if infos is not None:
+ sequence_dict = dict([(element_infos["name"], element_infos) for element_infos in infos["elements"]])
+ for element_value in value["value"]:
+ element_infos = sequence_dict.get(element_value["name"])
+ if element_infos["maxOccurs"] == "unbounded" or element_infos["maxOccurs"] > 1:
+ for item in element_value["value"]:
+ text += element_infos["elmt_type"]["generate"](item, element_value["name"], indent)
+ else:
+ text += element_infos["elmt_type"]["generate"](element_value["value"], element_infos["name"], indent)
+ return text
return {
+ "type": COMPLEXTYPE,
"initial": GetContentInitial,
"check": CheckContent,
"extract": ExtractContent,
@@ -707,8 +872,12 @@
"""
class ClassFactory:
- def __init__(self, document, debug=False):
+ def __init__(self, document, filepath=None, debug=False):
self.Document = document
+ if filepath is not None:
+ self.BaseFolder, self.FileName = os.path.split(filepath)
+ else:
+ self.BaseFolder = self.FileName = None
self.Debug = debug
# Dictionary for stocking Classes and Types definitions created from
@@ -724,7 +893,10 @@
# Dictionaries for stocking Classes and Types generated
self.ComputeAfter = []
- self.ComputedClasses = {}
+ if self.FileName is not None:
+ self.ComputedClasses = {self.FileName: {}}
+ else:
+ self.ComputedClasses = {}
self.ComputedClassesInfos = {}
self.AlreadyComputed = {}
@@ -732,7 +904,7 @@
if namespace is None:
if self.Namespaces[self.SchemaNamespace].has_key(name):
return self.Namespaces[self.SchemaNamespace][name]
- for space, elements in self.Namespaces.items():
+ for space, elements in self.Namespaces.iteritems():
if space != self.SchemaNamespace and elements.has_key(name):
return elements[name]
parts = name.split("_", 1)
@@ -846,15 +1018,18 @@
def ReduceElements(self, elements, schema=False):
result = []
for child_infos in elements:
- if child_infos[1].has_key("name") 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 child_infos[1].has_key("name") and schema:
- self.CurrentCompilations.pop(-1)
+ if child_infos is not None:
+ if child_infos[1].has_key("name") 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)
+ 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:
+ self.CurrentCompilations.pop(-1)
annotations = []
children = []
for element in result:
@@ -948,10 +1123,11 @@
# If base classes haven't been generated
bases = []
- if classinfos.has_key("base"):
- result = self.ExtractTypeInfos("base", name, classinfos["base"])
+ base_infos = classinfos.get("base", None)
+ if base_infos is not None:
+ result = self.ExtractTypeInfos("base", name, base_infos)
if result is None:
- namespace, base_name = DecomposeQualifiedName(classinfos["base"])
+ namespace, base_name = DecomposeQualifiedName(base_infos)
if self.AlreadyComputed.get(base_name, False):
self.ComputeAfter.append((name, parent, classinfos))
if self.TargetNamespace is not None:
@@ -959,8 +1135,19 @@
else:
return classname
elif result is not None:
- classinfos["base"] = self.ComputedClasses[result["name"]]
- bases.append(self.ComputedClasses[result["name"]])
+ if self.FileName is not None:
+ classinfos["base"] = self.ComputedClasses[self.FileName].get(result["name"], None)
+ if classinfos["base"] is None:
+ for filename, classes in self.ComputedClasses.iteritems():
+ if filename != self.FileName:
+ classinfos["base"] = classes.get(result["name"], None)
+ if classinfos["base"] is not None:
+ break
+ else:
+ classinfos["base"] = self.ComputedClasses.get(result["name"], None)
+ if classinfos["base"] is None:
+ raise ValueError("No class found for base type")
+ bases.append(classinfos["base"])
bases.append(object)
bases = tuple(bases)
classmembers = {"__doc__": classinfos.get("doc", ""), "IsBaseClass": baseclass}
@@ -984,30 +1171,22 @@
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))
+ choices = ComputeContentChoices(self, name, element)
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"])
else:
classmembers["set%sbytype" % elmtname] = generateSetChoiceByTypeMethod(self, element["choices"])
- infos = GenerateContentInfos(self, choices)
+ infos = GenerateContentInfos(self, name, choices)
elif element["type"] == ANY:
elmtname = element["name"] = "text"
element["minOccurs"] = element["maxOccurs"] = 1
- infos = GenerateAnyInfos()
+ infos = GenerateAnyInfos(element)
else:
elmtname = element["name"]
infos = self.ExtractTypeInfos(element["name"], name, element["elmt_type"])
@@ -1050,7 +1229,10 @@
"extract": generateClassExtractFunction(class_definition),
"generate": class_definition.generateXMLText}
- self.ComputedClasses[classname] = 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
return class_infos
@@ -1061,8 +1243,16 @@
def PrintClasses(self):
items = self.ComputedClasses.items()
items.sort()
- for classname, xmlclass in items:
- print "%s : %s" % (classname, str(xmlclass))
+ if self.FileName is not None:
+ for filename, classes in items:
+ print "File '%s':" % filename
+ class_items = classes.items()
+ class_items.sort()
+ for classname, xmlclass in class_items:
+ print "%s: %s" % (classname, str(xmlclass))
+ else:
+ for classname, xmlclass in items:
+ print "%s: %s" % (classname, str(xmlclass))
def PrintClassNames(self):
classnames = self.XMLClassDefinitions.keys()
@@ -1107,9 +1297,7 @@
def setattrMethod(self, name, value):
if attributes.has_key(name):
- if isinstance(attributes[name]["attr_type"], (UnicodeType, StringType)):
- namespace, name = DecomposeQualifiedName(infos)
- attributes[name]["attr_type"] = factory.GetQualifiedNameInfos(name, namespace)
+ attributes[name]["attr_type"] = FindTypeInfos(factory, attributes[name]["attr_type"])
if value is None:
if optional_attributes.get(name, False):
return object.__setattr__(self, name, None)
@@ -1122,22 +1310,7 @@
else:
raise ValueError("Invalid value for attribute '%s'." % (name))
elif elements.has_key(name):
- 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 elements[name].has_key("fixed") 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):
+ if CheckElementValue(factory, name, elements[name], value):
return object.__setattr__(self, name, value)
else:
raise ValueError("Invalid value for attribute '%s'." % (name))
@@ -1166,7 +1339,7 @@
if infos["maxOccurs"] == "unbounded":
return "(?:%s)+" % name
elif infos["maxOccurs"] == 1:
- return name
+ return "(?:%s)" % name
else:
return "(?:%s){1,%d}" % (name, infos["maxOccurs"])
else:
@@ -1176,23 +1349,32 @@
return "(?:%s){%d,%d}" % (name, infos["minOccurs"],
infos["maxOccurs"])
-def generateStructureMethod(classinfos):
+def GetStructure(classinfos):
elements = []
for element in classinfos["elements"]:
if element["type"] == ANY:
- elements.append(ComputeMultiplicity("(?:#cdata-section )?", element))
+ elements.append(ComputeMultiplicity("#cdata-section |\w* ", element))
elif element["type"] == CHOICE:
- elements.append(ComputeMultiplicity(
- "|".join([ComputeMultiplicity("%s " % infos["name"], infos) for infos in element["choices"]]),
- element))
+ choices = []
+ for infos in element["choices"]:
+ if infos["type"] == "sequence":
+ structure = "(?:%s)" % GetStructure(infos)
+ else:
+ structure = "%s " % infos["name"]
+ choices.append(ComputeMultiplicity(structure, infos))
+ elements.append(ComputeMultiplicity("|".join(choices), element))
+ elif element["name"] == "content" and element["elmt_type"]["type"] == SIMPLETYPE:
+ elements.append("(?:#cdata-section )?")
else:
elements.append(ComputeMultiplicity("%s " % element["name"], element))
if classinfos.get("order", True) or len(elements) == 0:
- structure = "".join(elements)
+ return "".join(elements)
else:
raise ValueError("XSD structure not yet supported!")
-
+
+def generateStructureMethod(classinfos):
def getStructureMethod(self):
+ structure = GetStructure(classinfos)
if classinfos.has_key("base"):
return classinfos["base"].getStructure(self) + structure
return structure
@@ -1213,20 +1395,20 @@
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)
+ structure_pattern = self.getStructure()
+ if structure_pattern != "":
+ structure_model = re.compile("(%s)$" % structure_pattern)
+ result = structure_model.match(children_structure)
+ if not result:
+ raise ValueError("Invalid structure for \"%s\" children!." % tree.nodeName)
required_attributes = dict([(attr["name"], True) for attr in classinfos["attributes"] if attr["use"] == "required"])
if classinfos.has_key("base"):
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.iteritems():
if attributes.has_key(attrname):
- 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))
+ attributes[attrname]["attr_type"] = FindTypeInfos(factory, attributes[attrname]["attr_type"])
+ object.__setattr__(self, attrname, attributes[attrname]["attr_type"]["extract"](attr))
elif not classinfos.has_key("base") and attrname not in extras:
raise ValueError("Invalid attribute \"%s\" for \"%s\" element!" % (attrname, tree.nodeName))
required_attributes.pop(attrname, None)
@@ -1237,37 +1419,39 @@
name = node.nodeName
if name in ["#text", "#comment"]:
continue
- if elements.has_key(name):
- if isinstance(elements[name]["elmt_type"], (UnicodeType, StringType)):
- namespace, name = DecomposeQualifiedName(infos)
- elements[name]["elmt_type"] = factory.GetQualifiedNameInfos(name, namespace)
+ elif elements.has_key(name):
+ elements[name]["elmt_type"] = FindTypeInfos(factory, elements[name]["elmt_type"])
if elements[name]["maxOccurs"] == "unbounded" or elements[name]["maxOccurs"] > 1:
if first.get(name, True):
- setattr(self, name, [elements[name]["elmt_type"]["extract"](node)])
+ object.__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 elements.has_key("text"):
+ object.__setattr__(self, name, elements[name]["elmt_type"]["extract"](node))
+ elif elements.has_key("text"):
if elements["text"]["maxOccurs"] == "unbounded" or elements["text"]["maxOccurs"] > 1:
if first.get("text", True):
- setattr(self, "text", [elements["text"]["elmt_type"]["extract"](node)])
+ object.__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))
+ object.__setattr__(self, "text", elements["text"]["elmt_type"]["extract"](node))
elif elements.has_key("content"):
- 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
+ if name == "#cdata-section":
+ if elements["content"]["elmt_type"]["type"] == SIMPLETYPE:
+ object.__setattr__(self, "content", elements["content"]["elmt_type"]["extract"](node.data, False))
+ else:
+ content = getattr(self, "content")
+ if elements["content"]["maxOccurs"] == "unbounded" or elements["content"]["maxOccurs"] > 1:
+ if first.get("content", True):
+ object.__setattr__(self, "content", [elements["content"]["elmt_type"]["extract"](node, None)])
+ first["content"] = False
+ else:
+ content.append(elements["content"]["elmt_type"]["extract"](node, content))
else:
- content.append(elements["content"]["elmt_type"]["extract"](node, content))
- else:
- setattr(self, "content", elements["content"]["elmt_type"]["extract"](node, content))
+ object.__setattr__(self, "content", elements["content"]["elmt_type"]["extract"](node, content))
return loadXMLTreeMethod
@@ -1293,9 +1477,7 @@
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)
+ attr["attr_type"] = FindTypeInfos(factory, attr["attr_type"])
value = getattr(self, attr["name"], None)
if value != None:
computed_value = attr["attr_type"]["generate"](value)
@@ -1316,9 +1498,7 @@
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)
+ element["elmt_type"] = FindTypeInfos(factory, element["elmt_type"])
value = getattr(self, element["name"], None)
if element["minOccurs"] == 0 and element["maxOccurs"] == 1:
if value is not None:
@@ -1330,7 +1510,10 @@
if first:
text += u'>\n'
first = False
- text += element["elmt_type"]["generate"](value, element["name"], indent + 1)
+ if element["name"] == "content" and element["elmt_type"]["type"] == SIMPLETYPE:
+ text += element["elmt_type"]["generate"](value)
+ else:
+ text += element["elmt_type"]["generate"](value, element["name"], indent + 1)
else:
if first and len(value) > 0:
text += u'>\n'
@@ -1422,14 +1605,20 @@
for element_name, element in elements.items():
if element["minOccurs"] == 0:
use = "optional"
- if element_name == "content":
+ if element_name == "content" and element["type"] == CHOICE:
attr_type = [(choice["name"], None) for choice in element["choices"]]
if self.content is None:
value = ""
else:
value = self.content["name"]
if self.content["value"] is not None:
- children.extend(self.content["value"].getElementInfos(self.content["name"])["children"])
+ if self.content["name"] == "sequence":
+ choices_dict = dict([(choice["name"], choice) for choice in element["choices"]])
+ sequence_infos = choices_dict.get("sequence", None)
+ if sequence_infos is not None:
+ children.extend([item.getElementInfos(infos["name"]) for item, infos in zip(self.content["value"], sequence_infos["elements"])])
+ else:
+ 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"],
@@ -1495,9 +1684,7 @@
if classinfos.has_key("base"):
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)
+ attribute["attr_type"] = FindTypeInfos(factory, attribute["attr_type"])
if attribute["use"] == "required":
setattr(self, attribute["name"], attribute["attr_type"]["initial"]())
elif attribute["use"] == "optional":
@@ -1506,21 +1693,7 @@
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)
+ setattr(self, element["name"], GetElementInitialValue(factory, element))
return initMethod
def generateSetMethod(attr):
@@ -1536,15 +1709,11 @@
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)
+ infos["attr_type"] = FindTypeInfos(factory, infos["attr_type"])
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)
+ infos["elmt_type"] = FindTypeInfos(factory, infos["elmt_type"])
initial = infos["elmt_type"]["initial"]
extract = infos["elmt_type"]["extract"]
else:
@@ -1562,9 +1731,7 @@
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)
+ infos["elmt_type"] = FindTypeInfos(factory, infos["elmt_type"])
attr_list = getattr(self, attr)
if maxOccurs == "unbounded" or len(attr_list) < maxOccurs:
if infos["elmt_type"]["check"](value):
@@ -1577,9 +1744,7 @@
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)
+ infos["elmt_type"] = FindTypeInfos(factory, infos["elmt_type"])
attr_list = getattr(self, attr)
if maxOccurs == "unbounded" or len(attr_list) < maxOccurs:
if infos["elmt_type"]["check"](value):
@@ -1600,9 +1765,7 @@
def setChoiceMethod(self, type):
if not choices.has_key(type):
raise ValueError("Unknown \"%s\" choice type for \"content\"!" % type)
- if isinstance(choices[type]["elmt_type"], (UnicodeType, StringType)):
- namespace, name = DecomposeQualifiedName(choices[type]["elmt_type"])
- choices[name]["elmt_type"] = factory.GetQualifiedNameInfos(name, namespace)
+ choices[type]["elmt_type"] = FindTypeInfos(factory, choices[type]["elmt_type"])
new_element = choices[type]["elmt_type"]["initial"]()
self.content = {"name": type, "value": new_element}
return new_element
@@ -1613,9 +1776,7 @@
def appendChoiceMethod(self, type):
if not choices.has_key(type):
raise ValueError("Unknown \"%s\" choice type for \"content\"!" % type)
- if isinstance(choices[type]["elmt_type"], (UnicodeType, StringType)):
- namespace, name = DecomposeQualifiedName(choices[type]["elmt_type"])
- choices[type]["elmt_type"] = factory.GetQualifiedNameInfos(name, namespace)
+ choices[type]["elmt_type"] = FindTypeInfos(factory, choices[type]["elmt_type"])
if maxOccurs == "unbounded" or len(self.content) < maxOccurs:
new_element = choices[type]["elmt_type"]["initial"]()
self.content.append({"name": type, "value": new_element})
@@ -1629,9 +1790,7 @@
def insertChoiceMethod(self, index, type):
if not choices.has_key(type):
raise ValueError("Unknown \"%s\" choice type for \"content\"!" % type)
- if isinstance(choices[type]["elmt_type"], (UnicodeType, StringType)):
- namespace, name = DecomposeQualifiedName(choices[type]["elmt_type"])
- choices[name]["elmt_type"] = factory.GetQualifiedNameInfos(name, namespace)
+ choices[type]["elmt_type"] = FindTypeInfos(factory, choices[type]["elmt_type"])
if maxOccurs == "unbounded" or len(self.content) < maxOccurs:
new_element = choices[type]["elmt_type"]["initial"]()
self.content.insert(index, {"name" : type, "value" : new_element})
@@ -1665,6 +1824,10 @@
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
-
+ if factory.FileName is not None and len(ComputedClasses) == 1:
+ globals().update(ComputedClasses[factory.FileName])
+ return ComputedClasses[factory.FileName]
+ else:
+ globals().update(ComputedClasses)
+ return ComputedClasses
+