xmlclass/xmlclass.py
changeset 1329 9d0cb01312f0
parent 1322 0a9227f743b3
child 1330 96b242e4c59d
equal deleted inserted replaced
1288:adc79fc44079 1329:9d0cb01312f0
    26 import re
    26 import re
    27 import datetime
    27 import datetime
    28 from types import *
    28 from types import *
    29 from xml.dom import minidom
    29 from xml.dom import minidom
    30 from xml.sax.saxutils import escape, unescape, quoteattr
    30 from xml.sax.saxutils import escape, unescape, quoteattr
       
    31 from lxml import etree
    31 from new import classobj
    32 from new import classobj
       
    33 from collections import OrderedDict
    32 
    34 
    33 def CreateNode(name):
    35 def CreateNode(name):
    34     node = minidom.Node()
    36     node = minidom.Node()
    35     node.nodeName = name
    37     node.nodeName = name
    36     node._attrs = {}
    38     node._attrs = {}
   531                                  (value, type))
   533                                  (value, type))
   532         return values
   534         return values
   533     return GetModelNameList
   535     return GetModelNameList
   534 
   536 
   535 def GenerateAnyInfos(infos):
   537 def GenerateAnyInfos(infos):
       
   538     
       
   539     def GetTextElement(tree):
       
   540         if infos["namespace"][0] == "##any":
       
   541             return tree.xpath("p")[0]
       
   542         return tree.xpath("ns:p", namespaces={"ns": infos["namespace"][0]})[0]
       
   543     
   536     def ExtractAny(tree):
   544     def ExtractAny(tree):
   537         if tree.nodeName in ["#text", "#cdata-section"]:
   545         return GetTextElement(tree).text
   538             return unicode(unescape(tree.data))
   546     
   539         else:
   547     def GenerateAny(tree, value):
   540             return tree
   548         GetTextElement(tree).text = etree.CDATA(value)
   541     
   549         
   542     def GenerateAny(value, name=None, indent=0):
   550     def InitialAny():
   543         if isinstance(value, (StringType, UnicodeType)):
   551         if infos["namespace"][0] == "##any":
   544             try:
   552             element_name = "p"
   545                 value = value.decode("utf-8")
   553         else:
   546             except:
   554             element_name = "{%s}p" % infos["namespace"][0]
   547                 pass
   555         p = etree.Element(element_name)
   548             return u'<![CDATA[%s]]>\n' % value
   556         p.text = etree.CDATA("")
   549         else:
   557         return p
   550             return value.toprettyxml(indent=" "*indent, encoding="utf-8")
       
   551         
   558         
   552     return {
   559     return {
   553         "type": COMPLEXTYPE, 
   560         "type": COMPLEXTYPE, 
   554         "extract": ExtractAny,
   561         "extract": ExtractAny,
   555         "generate": GenerateAny,
   562         "generate": GenerateAny,
   556         "initial": lambda: "",
   563         "initial": InitialAny,
   557         "check": lambda x: isinstance(x, (StringType, UnicodeType, minidom.Node))
   564         "check": lambda x: isinstance(x, (StringType, UnicodeType, etree.ElementBase))
   558     }
   565     }
   559 
   566 
   560 def GenerateTagInfos(infos):
   567 def GenerateTagInfos(infos):
   561     def ExtractTag(tree):
   568     def ExtractTag(tree):
   562         if len(tree._attrs) > 0:
   569         if len(tree._attrs) > 0:
   589         return factory.GetQualifiedNameInfos(name, namespace)
   596         return factory.GetQualifiedNameInfos(name, namespace)
   590     return infos
   597     return infos
   591     
   598     
   592 def GetElementInitialValue(factory, infos):
   599 def GetElementInitialValue(factory, infos):
   593     infos["elmt_type"] = FindTypeInfos(factory, infos["elmt_type"])
   600     infos["elmt_type"] = FindTypeInfos(factory, infos["elmt_type"])
   594     if infos["minOccurs"] == 0 and infos["maxOccurs"] == 1:
   601     if infos["minOccurs"] == 1:
   595         if infos.has_key("default"):
   602         element_name = factory.etreeNamespaceFormat % infos["name"]
   596             return infos["elmt_type"]["extract"](infos["default"], False)
   603         if infos["elmt_type"]["type"] == SIMPLETYPE:
   597         else:
   604             def initial_value():
   598             return None
   605                 value = etree.Element(element_name)
   599     elif infos["minOccurs"] == 1 and infos["maxOccurs"] == 1:
   606                 value.text = (infos["elmt_type"]["generate"](infos["elmt_type"]["initial"]()))
   600         return infos["elmt_type"]["initial"]()
   607                 return value
       
   608         else:
       
   609             def initial_value():
       
   610                 value = infos["elmt_type"]["initial"]()
       
   611                 if infos["type"] != ANY:
       
   612                     DefaultElementClass.__setattr__(value, "tag", element_name)
       
   613                     value._init_()
       
   614                 return value
       
   615         return [initial_value() for i in xrange(infos["minOccurs"])]
   601     else:
   616     else:
   602         return [infos["elmt_type"]["initial"]() for i in xrange(infos["minOccurs"])]
   617         return []
   603 
       
   604 def HandleError(message, raise_exception):
       
   605     if raise_exception:
       
   606         raise ValueError(message)
       
   607     return False
       
   608 
       
   609 def CheckElementValue(factory, name, infos, value, raise_exception=True):
       
   610     infos["elmt_type"] = FindTypeInfos(factory, infos["elmt_type"])
       
   611     if value is None and raise_exception:
       
   612         if not (infos["minOccurs"] == 0 and infos["maxOccurs"] == 1):
       
   613             return HandleError("Attribute '%s' isn't optional." % name, raise_exception)
       
   614     elif infos["maxOccurs"] == "unbounded" or infos["maxOccurs"] > 1:
       
   615         if not isinstance(value, ListType):
       
   616             return HandleError("Attribute '%s' must be a list." % name, raise_exception)
       
   617         if len(value) < infos["minOccurs"] or infos["maxOccurs"] != "unbounded" and len(value) > infos["maxOccurs"]:
       
   618             return HandleError("List out of bounds for attribute '%s'." % name, raise_exception)
       
   619         if not reduce(lambda x, y: x and y, map(infos["elmt_type"]["check"], value), True):
       
   620             return HandleError("Attribute '%s' must be a list of valid elements." % name, raise_exception)
       
   621     elif infos.has_key("fixed") and value != infos["fixed"]:
       
   622         return HandleError("Value of attribute '%s' can only be '%s'." % (name, str(infos["fixed"])), raise_exception)
       
   623     else:
       
   624         return infos["elmt_type"]["check"](value)
       
   625     return True
       
   626 
   618 
   627 def GetContentInfos(name, choices):
   619 def GetContentInfos(name, choices):
   628     for choice_infos in choices:
   620     for choice_infos in choices:
   629         if choices_infos["type"] == "sequence":
   621         if choices_infos["type"] == "sequence":
   630             for element_infos in choices_infos["elements"]:
   622             for element_infos in choices_infos["elements"]:
   647                     element_infos = factory.ExtractTypeInfos(sequence_element["name"], name, sequence_element["elmt_type"])
   639                     element_infos = factory.ExtractTypeInfos(sequence_element["name"], name, sequence_element["elmt_type"])
   648                     if element_infos is not None:
   640                     if element_infos is not None:
   649                         sequence_element["elmt_type"] = element_infos
   641                         sequence_element["elmt_type"] = element_infos
   650         elif choice["elmt_type"] == "tag":
   642         elif choice["elmt_type"] == "tag":
   651             choice["elmt_type"] = GenerateTagInfos(choice)
   643             choice["elmt_type"] = GenerateTagInfos(choice)
       
   644             factory.AddToLookupClass(choice["name"], name, DefaultElementClass)
   652         else:
   645         else:
   653             choice_infos = factory.ExtractTypeInfos(choice["name"], name, choice["elmt_type"])
   646             choice_infos = factory.ExtractTypeInfos(choice["name"], name, choice["elmt_type"])
   654             if choice_infos is not None:
   647             if choice_infos is not None:
   655                 choice["elmt_type"] = choice_infos
   648                 choice["elmt_type"] = choice_infos
   656         choices.append((choice["name"], choice))
   649         choices.append((choice["name"], choice))
   657     return choices
   650     return choices
   658 
       
   659 def ExtractContentElement(factory, tree, infos, content):
       
   660     infos["elmt_type"] = FindTypeInfos(factory, infos["elmt_type"])
       
   661     if infos["maxOccurs"] == "unbounded" or infos["maxOccurs"] > 1:
       
   662         if isinstance(content, ListType) and len(content) > 0 and \
       
   663            content[-1]["name"] == tree.nodeName:
       
   664             content_item = content.pop(-1)
       
   665             content_item["value"].append(infos["elmt_type"]["extract"](tree))
       
   666             return content_item
       
   667         elif not isinstance(content, ListType) and \
       
   668              content is not None and \
       
   669              content["name"] == tree.nodeName:
       
   670             return {"name": tree.nodeName, 
       
   671                     "value": content["value"] + [infos["elmt_type"]["extract"](tree)]}
       
   672         else:
       
   673             return {"name": tree.nodeName, 
       
   674                     "value": [infos["elmt_type"]["extract"](tree)]}
       
   675     else:
       
   676         return {"name": tree.nodeName, 
       
   677                 "value": infos["elmt_type"]["extract"](tree)}
       
   678 
   651 
   679 def GenerateContentInfos(factory, name, choices):
   652 def GenerateContentInfos(factory, name, choices):
   680     choices_dict = {}
   653     choices_dict = {}
   681     for choice_name, infos in choices:
   654     for choice_name, infos in choices:
   682         if choice_name == "sequence":
   655         if choice_name == "sequence":
   689                     choices_dict[element["name"]] = infos
   662                     choices_dict[element["name"]] = infos
   690         else:
   663         else:
   691             if choices_dict.has_key(choice_name):
   664             if choices_dict.has_key(choice_name):
   692                 raise ValueError("'%s' element defined two times in choice" % choice_name)
   665                 raise ValueError("'%s' element defined two times in choice" % choice_name)
   693             choices_dict[choice_name] = infos
   666             choices_dict[choice_name] = infos
       
   667     prefix = ("%s:" % factory.TargetNamespace
       
   668               if factory.TargetNamespace is not None else "")
       
   669     choices_xpath = "|".join(map(lambda x: prefix + x, choices_dict.keys()))
   694     
   670     
   695     def GetContentInitial():
   671     def GetContentInitial():
   696         content_name, infos = choices[0]
   672         content_name, infos = choices[0]
   697         if content_name == "sequence":
   673         if content_name == "sequence":
   698             content_value = []
   674             content_value = []
   699             for i in xrange(infos["minOccurs"]):
   675             for i in xrange(infos["minOccurs"]):
   700                 for element_infos in infos["elements"]:
   676                 for element_infos in infos["elements"]:
   701                     value = GetElementInitialValue(factory, element_infos)
   677                     content_value.extend(GetElementInitialValue(factory, element_infos))
   702                     if value is not None:
       
   703                         if element_infos["type"] == CHOICE:
       
   704                             content_value.append(value)
       
   705                         else:
       
   706                             content_value.append({"name": element_infos["name"], "value": value})
       
   707         else:
   678         else:
   708             content_value = GetElementInitialValue(factory, infos)
   679             content_value = GetElementInitialValue(factory, infos)
   709         return {"name": content_name, "value": content_value}
   680         return content_value
   710         
       
   711     def CheckContent(value):
       
   712         if value["name"] != "sequence":
       
   713             infos = choices_dict.get(value["name"], None)
       
   714             if infos is not None:
       
   715                 return CheckElementValue(factory, value["name"], infos, value["value"], False)
       
   716         elif len(value["value"]) > 0:
       
   717             infos = choices_dict.get(value["value"][0]["name"], None)
       
   718             if infos is None:
       
   719                 for choice_name, infos in choices:
       
   720                     if infos["type"] == "sequence":
       
   721                         for element_infos in infos["elements"]:
       
   722                             if element_infos["type"] == CHOICE:
       
   723                                 infos = GetContentInfos(value["value"][0]["name"], element_infos["choices"])
       
   724             if infos is not None:
       
   725                 sequence_number = 0
       
   726                 element_idx = 0
       
   727                 while element_idx < len(value["value"]):
       
   728                     for element_infos in infos["elements"]:
       
   729                         element_value = None
       
   730                         if element_infos["type"] == CHOICE:
       
   731                             choice_infos = None
       
   732                             if element_idx < len(value["value"]):
       
   733                                 for choice in element_infos["choices"]:
       
   734                                     if choice["name"] == value["value"][element_idx]["name"]:
       
   735                                         choice_infos = choice
       
   736                                         element_value = value["value"][element_idx]["value"]
       
   737                                         element_idx += 1
       
   738                                         break
       
   739                             if ((choice_infos is not None and 
       
   740                                  not CheckElementValue(factory, choice_infos["name"], choice_infos, element_value, False)) or
       
   741                                 (choice_infos is None and element_infos["minOccurs"] > 0)):
       
   742                                 raise ValueError("Invalid sequence value in attribute 'content'")
       
   743                         else:
       
   744                             if element_idx < len(value["value"]) and element_infos["name"] == value["value"][element_idx]["name"]:
       
   745                                 element_value = value["value"][element_idx]["value"]
       
   746                                 element_idx += 1
       
   747                             if not CheckElementValue(factory, element_infos["name"], element_infos, element_value, False):
       
   748                                 raise ValueError("Invalid sequence value in attribute 'content'")
       
   749                     sequence_number += 1
       
   750                 if sequence_number < infos["minOccurs"] or infos["maxOccurs"] != "unbounded" and sequence_number > infos["maxOccurs"]:
       
   751                     raise ValueError("Invalid sequence value in attribute 'content'")
       
   752                 return True
       
   753         else:
       
   754             for element_name, infos in choices:
       
   755                 if element_name == "sequence":
       
   756                     required = 0
       
   757                     for element in infos["elements"]:
       
   758                         if element["minOccurs"] > 0:
       
   759                             required += 1
       
   760                     if required == 0:
       
   761                         return True
       
   762         return False
       
   763     
       
   764     def ExtractContent(tree, content):
       
   765         infos = choices_dict.get(tree.nodeName, None)
       
   766         if infos is not None:
       
   767             if infos["name"] == "sequence":
       
   768                 sequence_dict = dict([(element_infos["name"], element_infos) for element_infos in infos["elements"] if element_infos["type"] != CHOICE])
       
   769                 element_infos = sequence_dict.get(tree.nodeName)
       
   770                 if content is not None and \
       
   771                    content["name"] == "sequence" and \
       
   772                    len(content["value"]) > 0 and \
       
   773                    choices_dict.get(content["value"][-1]["name"]) == infos:
       
   774                     return {"name": "sequence",
       
   775                             "value": content["value"] + [ExtractContentElement(factory, tree, element_infos, content["value"][-1])]}
       
   776                 else:
       
   777                     return {"name": "sequence",
       
   778                             "value": [ExtractContentElement(factory, tree, element_infos, None)]}
       
   779             else:
       
   780                 return ExtractContentElement(factory, tree, infos, content)
       
   781         else:
       
   782             for choice_name, infos in choices:
       
   783                 if infos["type"] == "sequence":
       
   784                     for element_infos in infos["elements"]:
       
   785                         if element_infos["type"] == CHOICE:
       
   786                             try:
       
   787                                 if content is not None and \
       
   788                                     content["name"] == "sequence" and \
       
   789                                     len(content["value"]) > 0:
       
   790                                     return {"name": "sequence",
       
   791                                             "value": content["value"] + [element_infos["elmt_type"]["extract"](tree, content["value"][-1])]}
       
   792                                 else:
       
   793                                     return {"name": "sequence",
       
   794                                             "value": [element_infos["elmt_type"]["extract"](tree, None)]}
       
   795                             except:
       
   796                                 pass
       
   797         raise ValueError("Invalid element \"%s\" for content!" % tree.nodeName)
       
   798     
       
   799     def GenerateContent(value, name=None, indent=0):
       
   800         text = ""
       
   801         if value["name"] != "sequence":
       
   802             infos = choices_dict.get(value["name"], None)
       
   803             if infos is not None:
       
   804                 infos["elmt_type"] = FindTypeInfos(factory, infos["elmt_type"])
       
   805                 if infos["maxOccurs"] == "unbounded" or infos["maxOccurs"] > 1:
       
   806                     for item in value["value"]:
       
   807                         text += infos["elmt_type"]["generate"](item, value["name"], indent)
       
   808                 else:
       
   809                     text += infos["elmt_type"]["generate"](value["value"], value["name"], indent)
       
   810         elif len(value["value"]) > 0:
       
   811             infos = choices_dict.get(value["value"][0]["name"], None)
       
   812             if infos is None:
       
   813                 for choice_name, infos in choices:
       
   814                     if infos["type"] == "sequence":
       
   815                         for element_infos in infos["elements"]:
       
   816                             if element_infos["type"] == CHOICE:
       
   817                                 infos = GetContentInfos(value["value"][0]["name"], element_infos["choices"])
       
   818             if infos is not None:
       
   819                 sequence_dict = dict([(element_infos["name"], element_infos) for element_infos in infos["elements"]]) 
       
   820                 for element_value in value["value"]:
       
   821                     element_infos = sequence_dict.get(element_value["name"])
       
   822                     if element_infos["maxOccurs"] == "unbounded" or element_infos["maxOccurs"] > 1:
       
   823                         for item in element_value["value"]:
       
   824                             text += element_infos["elmt_type"]["generate"](item, element_value["name"], indent)
       
   825                     else:
       
   826                         text += element_infos["elmt_type"]["generate"](element_value["value"], element_infos["name"], indent)
       
   827         return text
       
   828         
   681         
   829     return {
   682     return {
   830         "type": COMPLEXTYPE,
   683         "type": COMPLEXTYPE,
       
   684         "choices_xpath": etree.XPath(choices_xpath, namespaces=factory.NSMAP),
   831         "initial": GetContentInitial,
   685         "initial": GetContentInitial,
   832         "check": CheckContent,
       
   833         "extract": ExtractContent,
       
   834         "generate": GenerateContent
       
   835     }
   686     }
   836 
   687 
   837 #-------------------------------------------------------------------------------
   688 #-------------------------------------------------------------------------------
   838 #                           Structure extraction functions
   689 #                           Structure extraction functions
   839 #-------------------------------------------------------------------------------
   690 #-------------------------------------------------------------------------------
   899         # Dictionary for stocking Classes and Types definitions created from
   750         # Dictionary for stocking Classes and Types definitions created from
   900         # the XML tree
   751         # the XML tree
   901         self.XMLClassDefinitions = {}
   752         self.XMLClassDefinitions = {}
   902         
   753         
   903         self.DefinedNamespaces = {}
   754         self.DefinedNamespaces = {}
       
   755         self.NSMAP = {}
   904         self.Namespaces = {}
   756         self.Namespaces = {}
   905         self.SchemaNamespace = None
   757         self.SchemaNamespace = None
   906         self.TargetNamespace = None
   758         self.TargetNamespace = None
       
   759         self.etreeNamespaceFormat = "%s"
   907         
   760         
   908         self.CurrentCompilations = []
   761         self.CurrentCompilations = []
   909         
   762         
   910         # Dictionaries for stocking Classes and Types generated
   763         # Dictionaries for stocking Classes and Types generated
   911         self.ComputeAfter = []
   764         self.ComputeAfter = []
   912         if self.FileName is not None:
   765         if self.FileName is not None:
   913             self.ComputedClasses = {self.FileName: {}}
   766             self.ComputedClasses = {self.FileName: {}}
   914         else:
   767         else:
   915             self.ComputedClasses = {}
   768             self.ComputedClasses = {}
   916         self.ComputedClassesInfos = {}
   769         self.ComputedClassesInfos = {}
       
   770         self.ComputedClassesLookUp = {}
       
   771         self.EquivalentClassesParent = {}
   917         self.AlreadyComputed = {}
   772         self.AlreadyComputed = {}
   918 
   773 
   919     def GetQualifiedNameInfos(self, name, namespace=None, canbenone=False):
   774     def GetQualifiedNameInfos(self, name, namespace=None, canbenone=False):
   920         if namespace is None:
   775         if namespace is None:
   921             if self.Namespaces[self.SchemaNamespace].has_key(name):
   776             if self.Namespaces[self.SchemaNamespace].has_key(name):
  1014                     attrs[name] = infos["extract"][element_name](attr)
   869                     attrs[name] = infos["extract"][element_name](attr)
  1015                 else:
   870                 else:
  1016                     attrs[name] = infos["extract"]["default"](attr)
   871                     attrs[name] = infos["extract"]["default"](attr)
  1017             elif namespace == "xmlns":
   872             elif namespace == "xmlns":
  1018                 infos = self.GetQualifiedNameInfos("anyURI", self.SchemaNamespace)
   873                 infos = self.GetQualifiedNameInfos("anyURI", self.SchemaNamespace)
  1019                 self.DefinedNamespaces[infos["extract"](attr)] = name
   874                 value = infos["extract"](attr)
       
   875                 self.DefinedNamespaces[value] = name
       
   876                 self.NSMAP[name] = value
  1020             else:
   877             else:
  1021                 raise ValueError("Invalid attribute \"%s\" for member \"%s\"!" % (qualified_name, node.nodeName))
   878                 raise ValueError("Invalid attribute \"%s\" for member \"%s\"!" % (qualified_name, node.nodeName))
  1022         for attr in valid_attrs:
   879         for attr in valid_attrs:
  1023             if attr not in attrs and \
   880             if attr not in attrs and \
  1024                self.Namespaces[self.SchemaNamespace].has_key(attr) and \
   881                self.Namespaces[self.SchemaNamespace].has_key(attr) and \
  1061         else:
   918         else:
  1062             raise ValueError("\"%s\" class already defined. Choose another name!" % typename)
   919             raise ValueError("\"%s\" class already defined. Choose another name!" % typename)
  1063 
   920 
  1064     def ParseSchema(self):
   921     def ParseSchema(self):
  1065         pass
   922         pass
  1066 
   923     
       
   924     def AddEquivalentClass(self, name, base):
       
   925         if name != base:
       
   926             equivalences = self.EquivalentClassesParent.setdefault(self.etreeNamespaceFormat % base, {})
       
   927             equivalences[self.etreeNamespaceFormat % name] = True
       
   928     
       
   929     def AddDistinctionBetweenParentsInLookupClass(
       
   930                                     self, lookup_classes, parent, typeinfos):
       
   931         parent = (self.etreeNamespaceFormat % parent 
       
   932                   if parent is not None else None)
       
   933         parent_class = lookup_classes.get(parent)
       
   934         if parent_class is not None:
       
   935             if isinstance(parent_class, ListType):
       
   936                 if typeinfos not in parent_class:
       
   937                     lookup_classes[parent].append(typeinfos)
       
   938             elif parent_class != typeinfos:
       
   939                 lookup_classes[parent] = [parent_class, typeinfos]
       
   940         else:
       
   941             lookup_classes[parent] = typeinfos
       
   942     
       
   943     def AddToLookupClass(self, name, parent, typeinfos):
       
   944         lookup_name = self.etreeNamespaceFormat % name
       
   945         if isinstance(typeinfos, (StringType, UnicodeType)):
       
   946             self.AddEquivalentClass(name, typeinfos)
       
   947             typeinfos = self.etreeNamespaceFormat % typeinfos
       
   948         lookup_classes = self.ComputedClassesLookUp.get(lookup_name)
       
   949         if lookup_classes is None:
       
   950             self.ComputedClassesLookUp[lookup_name] = (typeinfos, parent)
       
   951         elif isinstance(lookup_classes, DictType):
       
   952             self.AddDistinctionBetweenParentsInLookupClass(
       
   953                 lookup_classes, parent, typeinfos)
       
   954         else:
       
   955             lookup_classes = {
       
   956                 self.etreeNamespaceFormat % lookup_classes[1]
       
   957                 if lookup_classes[1] is not None else None: lookup_classes[0]}
       
   958             self.AddDistinctionBetweenParentsInLookupClass(
       
   959                 lookup_classes, parent, typeinfos)
       
   960             self.ComputedClassesLookUp[lookup_name] = lookup_classes
       
   961     
  1067     def ExtractTypeInfos(self, name, parent, typeinfos):
   962     def ExtractTypeInfos(self, name, parent, typeinfos):
  1068         if isinstance(typeinfos, (StringType, UnicodeType)):
   963         if isinstance(typeinfos, (StringType, UnicodeType)):
  1069             namespace, name = DecomposeQualifiedName(typeinfos)
   964             namespace, type_name = DecomposeQualifiedName(typeinfos)
  1070             infos = self.GetQualifiedNameInfos(name, namespace)
   965             infos = self.GetQualifiedNameInfos(type_name, namespace)
       
   966             if name != "base":
       
   967                 if infos["type"] == SIMPLETYPE:
       
   968                     self.AddToLookupClass(name, parent, DefaultElementClass)
       
   969                 elif namespace == self.TargetNamespace:
       
   970                     self.AddToLookupClass(name, parent, type_name)
  1071             if infos["type"] == COMPLEXTYPE:
   971             if infos["type"] == COMPLEXTYPE:
  1072                 name, parent = self.SplitQualifiedName(name, namespace)
   972                 type_name, parent = self.SplitQualifiedName(type_name, namespace)
  1073                 result = self.CreateClass(name, parent, infos)
   973                 result = self.CreateClass(type_name, parent, infos)
  1074                 if result is not None and not isinstance(result, (UnicodeType, StringType)):
   974                 if result is not None and not isinstance(result, (UnicodeType, StringType)):
  1075                     self.Namespaces[self.TargetNamespace][result["name"]] = result
   975                     self.Namespaces[self.TargetNamespace][result["name"]] = result
  1076                 return result
   976                 return result
  1077             elif infos["type"] == ELEMENT and infos["elmt_type"]["type"] == COMPLEXTYPE:
   977             elif infos["type"] == ELEMENT and infos["elmt_type"]["type"] == COMPLEXTYPE:
  1078                 name, parent = self.SplitQualifiedName(name, namespace)
   978                 type_name, parent = self.SplitQualifiedName(type_name, namespace)
  1079                 result = self.CreateClass(name, parent, infos["elmt_type"])
   979                 result = self.CreateClass(type_name, parent, infos["elmt_type"])
  1080                 if result is not None and not isinstance(result, (UnicodeType, StringType)):
   980                 if result is not None and not isinstance(result, (UnicodeType, StringType)):
  1081                     self.Namespaces[self.TargetNamespace][result["name"]] = result
   981                     self.Namespaces[self.TargetNamespace][result["name"]] = result
  1082                 return result
   982                 return result
  1083             else:
   983             else:
  1084                 return infos
   984                 return infos
  1085         elif typeinfos["type"] == COMPLEXTYPE:
   985         elif typeinfos["type"] == COMPLEXTYPE:
  1086             return self.CreateClass(name, parent, typeinfos)
   986             return self.CreateClass(name, parent, typeinfos)
  1087         elif typeinfos["type"] == SIMPLETYPE:
   987         elif typeinfos["type"] == SIMPLETYPE:
  1088             return typeinfos
   988             return typeinfos
  1089             
   989     
       
   990     def GetEquivalentParents(self, parent):
       
   991         return reduce(lambda x, y: x + y,
       
   992             [[p] + self.GetEquivalentParents(p)
       
   993              for p in self.EquivalentClassesParent.get(parent, {}).keys()], [])
       
   994     
  1090     """
   995     """
  1091     Methods that generates the classes
   996     Methods that generates the classes
  1092     """
   997     """
  1093     def CreateClasses(self):
   998     def CreateClasses(self):
  1094         self.ParseSchema()
   999         self.ParseSchema()
  1121                         while len(self.ComputeAfter) > 0:
  1026                         while len(self.ComputeAfter) > 0:
  1122                             result = self.CreateClass(*self.ComputeAfter.pop(0))
  1027                             result = self.CreateClass(*self.ComputeAfter.pop(0))
  1123                             if result is not None and \
  1028                             if result is not None and \
  1124                                not isinstance(result, (UnicodeType, StringType)):
  1029                                not isinstance(result, (UnicodeType, StringType)):
  1125                                 self.Namespaces[self.TargetNamespace][result["name"]] = result
  1030                                 self.Namespaces[self.TargetNamespace][result["name"]] = result
       
  1031         
       
  1032         for name, parents in self.ComputedClassesLookUp.iteritems():
       
  1033             if isinstance(parents, DictType):
       
  1034                 computed_classes = parents.items()
       
  1035             elif parents[1] is not None:
       
  1036                 computed_classes = [(self.etreeNamespaceFormat % parents[1], parents[0])]
       
  1037             else:
       
  1038                 computed_classes = []
       
  1039             for parent, computed_class in computed_classes:
       
  1040                 for equivalent_parent in self.GetEquivalentParents(parent):
       
  1041                     if not isinstance(parents, DictType):
       
  1042                         parents = dict(computed_classes)
       
  1043                         self.ComputedClassesLookUp[name] = parents
       
  1044                     parents[equivalent_parent] = computed_class
       
  1045         
  1126         return self.ComputedClasses
  1046         return self.ComputedClasses
  1127 
  1047 
  1128     def CreateClass(self, name, parent, classinfos, baseclass = False):
  1048     def CreateClass(self, name, parent, classinfos, baseclass = False):
  1129         if parent is not None:
  1049         if parent is not None:
  1130             classname = "%s_%s" % (parent, name)
  1050             classname = "%s_%s" % (parent, name)
  1139         
  1059         
  1140         # If base classes haven't been generated
  1060         # If base classes haven't been generated
  1141         bases = []
  1061         bases = []
  1142         base_infos = classinfos.get("base", None)
  1062         base_infos = classinfos.get("base", None)
  1143         if base_infos is not None:
  1063         if base_infos is not None:
       
  1064             namespace, base_name = DecomposeQualifiedName(base_infos)
       
  1065             if namespace == self.TargetNamespace:
       
  1066                 self.AddEquivalentClass(name, base_name)
  1144             result = self.ExtractTypeInfos("base", name, base_infos)
  1067             result = self.ExtractTypeInfos("base", name, base_infos)
  1145             if result is None:
  1068             if result is None:
  1146                 namespace, base_name = DecomposeQualifiedName(base_infos)                
  1069                 namespace, base_name = DecomposeQualifiedName(base_infos)
  1147                 if self.AlreadyComputed.get(base_name, False):
  1070                 if self.AlreadyComputed.get(base_name, False):
  1148                     self.ComputeAfter.append((name, parent, classinfos))
  1071                     self.ComputeAfter.append((name, parent, classinfos))
  1149                     if self.TargetNamespace is not None:
  1072                     if self.TargetNamespace is not None:
  1150                         return "%s:%s" % (self.TargetNamespace, classname)
  1073                         return "%s:%s" % (self.TargetNamespace, classname)
  1151                     else:
  1074                     else:
  1162                 else:
  1085                 else:
  1163                     classinfos["base"] = self.ComputedClasses.get(result["name"], None)
  1086                     classinfos["base"] = self.ComputedClasses.get(result["name"], None)
  1164                 if classinfos["base"] is None:
  1087                 if classinfos["base"] is None:
  1165                     raise ValueError("No class found for base type")
  1088                     raise ValueError("No class found for base type")
  1166                 bases.append(classinfos["base"])
  1089                 bases.append(classinfos["base"])
  1167         bases.append(object)
  1090         bases.append(DefaultElementClass)
  1168         bases = tuple(bases)
  1091         bases = tuple(bases)
  1169         classmembers = {"__doc__": classinfos.get("doc", ""), "IsBaseClass": baseclass}
  1092         classmembers = {"__doc__": classinfos.get("doc", ""), "IsBaseClass": baseclass}
  1170         
  1093         
  1171         self.AlreadyComputed[classname] = True
  1094         self.AlreadyComputed[classname] = True
  1172         
  1095         
  1175             if infos is not None:                    
  1098             if infos is not None:                    
  1176                 if infos["type"] != SIMPLETYPE:
  1099                 if infos["type"] != SIMPLETYPE:
  1177                     raise ValueError("\"%s\" type is not a simple type!" % attribute["attr_type"])
  1100                     raise ValueError("\"%s\" type is not a simple type!" % attribute["attr_type"])
  1178                 attrname = attribute["name"]
  1101                 attrname = attribute["name"]
  1179                 if attribute["use"] == "optional":
  1102                 if attribute["use"] == "optional":
  1180                     classmembers[attrname] = None
       
  1181                     classmembers["add%s"%attrname] = generateAddMethod(attrname, self, attribute)
  1103                     classmembers["add%s"%attrname] = generateAddMethod(attrname, self, attribute)
  1182                     classmembers["delete%s"%attrname] = generateDeleteMethod(attrname)
  1104                     classmembers["delete%s"%attrname] = generateDeleteMethod(attrname)
  1183                 else:
       
  1184                     classmembers[attrname] = infos["initial"]()
       
  1185                 classmembers["set%s"%attrname] = generateSetMethod(attrname)
  1105                 classmembers["set%s"%attrname] = generateSetMethod(attrname)
  1186                 classmembers["get%s"%attrname] = generateGetMethod(attrname)
  1106                 classmembers["get%s"%attrname] = generateGetMethod(attrname)
  1187             else:
  1107             else:
  1188                 raise ValueError("\"%s\" type unrecognized!" % attribute["attr_type"])
  1108                 raise ValueError("\"%s\" type unrecognized!" % attribute["attr_type"])
  1189             attribute["attr_type"] = infos
  1109             attribute["attr_type"] = infos
  1198                     classmembers["insert%sbytype" % elmtname] = generateInsertChoiceByTypeMethod(element["maxOccurs"], self, element["choices"])
  1118                     classmembers["insert%sbytype" % elmtname] = generateInsertChoiceByTypeMethod(element["maxOccurs"], self, element["choices"])
  1199                 else:
  1119                 else:
  1200                     classmembers["set%sbytype" % elmtname] = generateSetChoiceByTypeMethod(self, element["choices"])
  1120                     classmembers["set%sbytype" % elmtname] = generateSetChoiceByTypeMethod(self, element["choices"])
  1201                 infos = GenerateContentInfos(self, name, choices)
  1121                 infos = GenerateContentInfos(self, name, choices)
  1202             elif element["type"] == ANY:
  1122             elif element["type"] == ANY:
  1203                 elmtname = element["name"] = "text"
  1123                 elmtname = element["name"] = "anyText"
  1204                 element["minOccurs"] = element["maxOccurs"] = 1
  1124                 element["minOccurs"] = element["maxOccurs"] = 1
  1205                 infos = GenerateAnyInfos(element)
  1125                 infos = GenerateAnyInfos(element)
  1206             else:
  1126             else:
  1207                 elmtname = element["name"]
  1127                 elmtname = element["name"]
  1208                 if element["elmt_type"] == "tag":
  1128                 if element["elmt_type"] == "tag":
  1209                     infos = GenerateTagInfos(element)
  1129                     infos = GenerateTagInfos(element)
       
  1130                     self.AddToLookupClass(element["name"], name, DefaultElementClass)
  1210                 else:
  1131                 else:
  1211                     infos = self.ExtractTypeInfos(element["name"], name, element["elmt_type"])
  1132                     infos = self.ExtractTypeInfos(element["name"], name, element["elmt_type"])
  1212             if infos is not None:
  1133             if infos is not None:
  1213                 element["elmt_type"] = infos
  1134                 element["elmt_type"] = infos
  1214             if element["maxOccurs"] == "unbounded" or element["maxOccurs"] > 1:
  1135             if element["maxOccurs"] == "unbounded" or element["maxOccurs"] > 1:
  1215                 classmembers[elmtname] = []
       
  1216                 classmembers["append%s" % elmtname] = generateAppendMethod(elmtname, element["maxOccurs"], self, element)
  1136                 classmembers["append%s" % elmtname] = generateAppendMethod(elmtname, element["maxOccurs"], self, element)
  1217                 classmembers["insert%s" % elmtname] = generateInsertMethod(elmtname, element["maxOccurs"], self, element)
  1137                 classmembers["insert%s" % elmtname] = generateInsertMethod(elmtname, element["maxOccurs"], self, element)
  1218                 classmembers["remove%s" % elmtname] = generateRemoveMethod(elmtname, element["minOccurs"])
  1138                 classmembers["remove%s" % elmtname] = generateRemoveMethod(elmtname, element["minOccurs"])
  1219                 classmembers["count%s" % elmtname] = generateCountMethod(elmtname)
  1139                 classmembers["count%s" % elmtname] = generateCountMethod(elmtname)
  1220             else:
  1140             else:
  1221                 if element["minOccurs"] == 0:
  1141                 if element["minOccurs"] == 0:
  1222                     classmembers[elmtname] = None
       
  1223                     classmembers["add%s" % elmtname] = generateAddMethod(elmtname, self, element)
  1142                     classmembers["add%s" % elmtname] = generateAddMethod(elmtname, self, element)
  1224                     classmembers["delete%s" % elmtname] = generateDeleteMethod(elmtname)
  1143                     classmembers["delete%s" % elmtname] = generateDeleteMethod(elmtname)
  1225                 elif not isinstance(element["elmt_type"], (UnicodeType, StringType)):
       
  1226                     classmembers[elmtname] = element["elmt_type"]["initial"]()
       
  1227                 else:
       
  1228                     classmembers[elmtname] = None
       
  1229             classmembers["set%s" % elmtname] = generateSetMethod(elmtname)
  1144             classmembers["set%s" % elmtname] = generateSetMethod(elmtname)
  1230             classmembers["get%s" % elmtname] = generateGetMethod(elmtname)
  1145             classmembers["get%s" % elmtname] = generateGetMethod(elmtname)
  1231             
  1146             
  1232         classmembers["__init__"] = generateInitMethod(self, classinfos)
  1147         classmembers["_init_"] = generateInitMethod(self, classinfos)
  1233         classmembers["getStructure"] = generateStructureMethod(classinfos)
  1148         classmembers["StructurePattern"] = GetStructurePattern(classinfos)
  1234         classmembers["loadXMLTree"] = generateLoadXMLTree(self, classinfos)
       
  1235         classmembers["generateXMLText"] = generateGenerateXMLText(self, classinfos)
       
  1236         classmembers["getElementAttributes"] = generateGetElementAttributes(self, classinfos)
  1149         classmembers["getElementAttributes"] = generateGetElementAttributes(self, classinfos)
  1237         classmembers["getElementInfos"] = generateGetElementInfos(self, classinfos)
  1150         classmembers["getElementInfos"] = generateGetElementInfos(self, classinfos)
  1238         classmembers["setElementValue"] = generateSetElementValue(self, classinfos)
  1151         classmembers["setElementValue"] = generateSetElementValue(self, classinfos)
  1239         classmembers["singleLineAttributes"] = True
       
  1240         classmembers["compatibility"] = lambda x, y: None
       
  1241         classmembers["extraAttrs"] = {}
       
  1242         
  1152         
  1243         class_definition = classobj(str(classname), bases, classmembers)
  1153         class_definition = classobj(str(classname), bases, classmembers)
       
  1154         setattr(class_definition, "__getattr__", generateGetattrMethod(self, class_definition, classinfos))
  1244         setattr(class_definition, "__setattr__", generateSetattrMethod(self, class_definition, classinfos))
  1155         setattr(class_definition, "__setattr__", generateSetattrMethod(self, class_definition, classinfos))
  1245         class_infos = {"type": COMPILEDCOMPLEXTYPE,
  1156         class_infos = {"type": COMPILEDCOMPLEXTYPE,
  1246                        "name": classname,
  1157                        "name": classname,
  1247                        "check": generateClassCheckFunction(class_definition),
       
  1248                        "initial": generateClassCreateFunction(class_definition),
  1158                        "initial": generateClassCreateFunction(class_definition),
  1249                        "extract": generateClassExtractFunction(class_definition),
  1159         }
  1250                        "generate": class_definition.generateXMLText}
       
  1251         
  1160         
  1252         if self.FileName is not None:
  1161         if self.FileName is not None:
  1253             self.ComputedClasses[self.FileName][classname] = class_definition
  1162             self.ComputedClasses[self.FileName][classname] = class_definition
  1254         else:
  1163         else:
  1255             self.ComputedClasses[classname] = class_definition
  1164             self.ComputedClasses[classname] = class_definition
  1256         self.ComputedClassesInfos[classname] = class_infos
  1165         self.ComputedClassesInfos[classname] = class_infos
  1257         
  1166         
       
  1167         self.AddToLookupClass(name, parent, class_definition)
       
  1168         self.AddToLookupClass(classname, None, class_definition)
       
  1169             
  1258         return class_infos
  1170         return class_infos
  1259 
  1171 
  1260     """
  1172     """
  1261     Methods that print the classes generated
  1173     Methods that print the classes generated
  1262     """
  1174     """
  1279         classnames.sort()
  1191         classnames.sort()
  1280         for classname in classnames:
  1192         for classname in classnames:
  1281             print classname
  1193             print classname
  1282 
  1194 
  1283 """
  1195 """
  1284 Method that generate the method for checking a class instance
       
  1285 """
       
  1286 def generateClassCheckFunction(class_definition):
       
  1287     def classCheckfunction(instance):
       
  1288         return isinstance(instance, class_definition)
       
  1289     return classCheckfunction
       
  1290 
       
  1291 """
       
  1292 Method that generate the method for creating a class instance
       
  1293 """
       
  1294 def generateClassCreateFunction(class_definition):
       
  1295     def classCreatefunction():
       
  1296         return class_definition()
       
  1297     return classCreatefunction
       
  1298 
       
  1299 """
       
  1300 Method that generate the method for extracting a class instance
       
  1301 """
       
  1302 def generateClassExtractFunction(class_definition):
       
  1303     def classExtractfunction(node):
       
  1304         instance = class_definition()
       
  1305         instance.loadXMLTree(node)
       
  1306         return instance
       
  1307     return classExtractfunction
       
  1308 
       
  1309 """
       
  1310 Method that generate the method for loading an xml tree by following the
       
  1311 attributes list defined
       
  1312 """
       
  1313 def generateSetattrMethod(factory, class_definition, classinfos):
       
  1314     attributes = dict([(attr["name"], attr) for attr in classinfos["attributes"] if attr["use"] != "prohibited"])
       
  1315     optional_attributes = dict([(attr["name"], True) for attr in classinfos["attributes"] if attr["use"] == "optional"])
       
  1316     elements = dict([(element["name"], element) for element in classinfos["elements"]])
       
  1317     
       
  1318     def setattrMethod(self, name, value):
       
  1319         if attributes.has_key(name):
       
  1320             attributes[name]["attr_type"] = FindTypeInfos(factory, attributes[name]["attr_type"])
       
  1321             if value is None:
       
  1322                 if optional_attributes.get(name, False):
       
  1323                     return object.__setattr__(self, name, None)
       
  1324                 else:
       
  1325                     raise ValueError("Attribute '%s' isn't optional." % name)
       
  1326             elif attributes[name].has_key("fixed") and value != attributes[name]["fixed"]:
       
  1327                 raise ValueError, "Value of attribute '%s' can only be '%s'."%(name, str(attributes[name]["fixed"]))
       
  1328             elif attributes[name]["attr_type"]["check"](value):
       
  1329                 return object.__setattr__(self, name, value)
       
  1330             else:
       
  1331                 raise ValueError("Invalid value for attribute '%s'." % (name))
       
  1332         elif elements.has_key(name):
       
  1333             if CheckElementValue(factory, name, elements[name], value):
       
  1334                 return object.__setattr__(self, name, value)
       
  1335             else:
       
  1336                 raise ValueError("Invalid value for attribute '%s'." % (name))
       
  1337         elif classinfos.has_key("base"):
       
  1338             return classinfos["base"].__setattr__(self, name, value)
       
  1339         elif class_definition.__dict__.has_key(name):
       
  1340             return object.__setattr__(self, name, value)
       
  1341         else:
       
  1342             raise AttributeError("'%s' can't have an attribute '%s'." % (self.__class__.__name__, name))
       
  1343         
       
  1344     return setattrMethod
       
  1345 
       
  1346 """
       
  1347 Method that generate the method for generating the xml tree structure model by 
  1196 Method that generate the method for generating the xml tree structure model by 
  1348 following the attributes list defined
  1197 following the attributes list defined
  1349 """
  1198 """
  1350 def ComputeMultiplicity(name, infos):
  1199 def ComputeMultiplicity(name, infos):
  1351     if infos["minOccurs"] == 0:
  1200     if infos["minOccurs"] == 0:
  1367             return "(?:%s){%d,}" % (name, infos["minOccurs"], name)
  1216             return "(?:%s){%d,}" % (name, infos["minOccurs"], name)
  1368         else:
  1217         else:
  1369             return "(?:%s){%d,%d}" % (name, infos["minOccurs"], 
  1218             return "(?:%s){%d,%d}" % (name, infos["minOccurs"], 
  1370                                        infos["maxOccurs"])
  1219                                        infos["maxOccurs"])
  1371 
  1220 
  1372 def GetStructure(classinfos):
  1221 def GetStructurePattern(classinfos):
       
  1222     base_structure_pattern = (
       
  1223         classinfos["base"].StructurePattern.pattern[:-1]
       
  1224         if classinfos.has_key("base") else "")
  1373     elements = []
  1225     elements = []
  1374     for element in classinfos["elements"]:
  1226     for element in classinfos["elements"]:
  1375         if element["type"] == ANY:
  1227         if element["type"] == ANY:
  1376             infos = element.copy()
  1228             infos = element.copy()
  1377             infos["minOccurs"] = 0
  1229             infos["minOccurs"] = 0
  1378             elements.append(ComputeMultiplicity("#text |#cdata-section |\w* ", infos))
  1230             elements.append(ComputeMultiplicity("#text |#cdata-section |\w* ", infos))
  1379         elif element["type"] == CHOICE:
  1231         elif element["type"] == CHOICE:
  1380             choices = []
  1232             choices = []
  1381             for infos in element["choices"]:
  1233             for infos in element["choices"]:
  1382                 if infos["type"] == "sequence":
  1234                 if infos["type"] == "sequence":
  1383                     structure = "(?:%s)" % GetStructure(infos)
  1235                     structure = "(?:%s)" % GetStructurePattern(infos)
  1384                 else:
  1236                 else:
  1385                     structure = "%s " % infos["name"]
  1237                     structure = "%s " % infos["name"]
  1386                 choices.append(ComputeMultiplicity(structure, infos))
  1238                 choices.append(ComputeMultiplicity(structure, infos))
  1387             elements.append(ComputeMultiplicity("|".join(choices), element))
  1239             elements.append(ComputeMultiplicity("|".join(choices), element))
  1388         elif element["name"] == "content" and element["elmt_type"]["type"] == SIMPLETYPE:
  1240         elif element["name"] == "content" and element["elmt_type"]["type"] == SIMPLETYPE:
  1389             elements.append("(?:#text |#cdata-section )?")
  1241             elements.append("(?:#text |#cdata-section )?")
  1390         else:
  1242         else:
  1391             elements.append(ComputeMultiplicity("%s " % element["name"], element))
  1243             elements.append(ComputeMultiplicity("%s " % element["name"], element))
  1392     if classinfos.get("order", True) or len(elements) == 0:
  1244     if classinfos.get("order", True) or len(elements) == 0:
  1393         return "".join(elements)
  1245         return re.compile(base_structure_pattern + "".join(elements) + "$")
  1394     else:
  1246     else:
  1395         raise ValueError("XSD structure not yet supported!")
  1247         raise ValueError("XSD structure not yet supported!")
  1396 
  1248 
  1397 def generateStructureMethod(classinfos):
       
  1398     def getStructureMethod(self):
       
  1399         structure = GetStructure(classinfos)
       
  1400         if classinfos.has_key("base"):
       
  1401             return classinfos["base"].getStructure(self) + structure
       
  1402         return structure
       
  1403     return getStructureMethod
       
  1404 
       
  1405 """
  1249 """
  1406 Method that generate the method for loading an xml tree by following the
  1250 Method that generate the method for creating a class instance
  1407 attributes list defined
       
  1408 """
  1251 """
  1409 def generateLoadXMLTree(factory, classinfos):
  1252 def generateClassCreateFunction(class_definition):
       
  1253     def classCreatefunction():
       
  1254         return class_definition()
       
  1255     return classCreatefunction
       
  1256 
       
  1257 def generateGetattrMethod(factory, class_definition, classinfos):
  1410     attributes = dict([(attr["name"], attr) for attr in classinfos["attributes"] if attr["use"] != "prohibited"])
  1258     attributes = dict([(attr["name"], attr) for attr in classinfos["attributes"] if attr["use"] != "prohibited"])
       
  1259     optional_attributes = dict([(attr["name"], True) for attr in classinfos["attributes"] if attr["use"] == "optional"])
  1411     elements = dict([(element["name"], element) for element in classinfos["elements"]])
  1260     elements = dict([(element["name"], element) for element in classinfos["elements"]])
  1412     
  1261     
  1413     def loadXMLTreeMethod(self, tree, extras=[], derived=False):
  1262     def getattrMethod(self, name):
  1414         self.extraAttrs = {}
  1263         if attributes.has_key(name):
  1415         self.compatibility(tree)
  1264             attribute_infos = attributes[name]
  1416         if not derived:
  1265             attribute_infos["attr_type"] = FindTypeInfos(factory, attribute_infos["attr_type"])
  1417             children_structure = ""
  1266             value = self.get(name)
  1418             for node in tree.childNodes:
  1267             if value is not None:
  1419                 if not (node.nodeName == "#text" and node.data.strip() == "") and node.nodeName != "#comment":
  1268                 return attribute_infos["attr_type"]["extract"](value, extract=False)
  1420                     children_structure += "%s " % node.nodeName
  1269             elif attribute_infos.has_key("fixed"):
  1421             structure_pattern = self.getStructure()
  1270                 return attribute_infos["attr_type"]["extract"](attribute_infos["fixed"], extract=False)
  1422             if structure_pattern != "":
  1271             elif attribute_infos.has_key("default"):
  1423                 structure_model = re.compile("(%s)$" % structure_pattern)
  1272                 return attribute_infos["attr_type"]["extract"](attribute_infos["default"], extract=False)
  1424                 result = structure_model.match(children_structure)
  1273             return None
  1425                 if not result:
  1274         
  1426                     raise ValueError("Invalid structure for \"%s\" children!." % tree.nodeName)
  1275         elif elements.has_key(name):
  1427         required_attributes = dict([(attr["name"], True) for attr in classinfos["attributes"] if attr["use"] == "required"])
  1276             element_infos = elements[name]
  1428         if classinfos.has_key("base"):
  1277             element_infos["elmt_type"] = FindTypeInfos(factory, element_infos["elmt_type"])
  1429             extras.extend([attr["name"] for attr in classinfos["attributes"] if attr["use"] != "prohibited"])
  1278             if element_infos["type"] == CHOICE:
  1430             classinfos["base"].loadXMLTree(self, tree, extras, True)
  1279                 content = element_infos["elmt_type"]["choices_xpath"](self)
  1431         for attrname, attr in tree._attrs.iteritems():
  1280                 if element_infos["maxOccurs"] == "unbounded" or element_infos["maxOccurs"] > 1:
  1432             if attributes.has_key(attrname):
  1281                     return content
  1433                 attributes[attrname]["attr_type"] = FindTypeInfos(factory, attributes[attrname]["attr_type"])
  1282                 elif len(content) > 0:
  1434                 object.__setattr__(self, attrname, attributes[attrname]["attr_type"]["extract"](attr))
  1283                     return content[0]
  1435             elif not classinfos.has_key("base") and not attrname in extras and not self.extraAttrs.has_key(attrname):
  1284                 return None 
  1436                 self.extraAttrs[attrname] = GetAttributeValue(attr)
  1285             elif element_infos["type"] == ANY:
  1437             required_attributes.pop(attrname, None)
  1286                 return element_infos["elmt_type"]["extract"](self)
  1438         if len(required_attributes) > 0:
  1287             elif name == "content" and element_infos["elmt_type"]["type"] == SIMPLETYPE:
  1439             raise ValueError("Required attributes %s missing for \"%s\" element!" % (", ".join(["\"%s\""%name for name in required_attributes]), tree.nodeName))
  1288                 return element_infos["elmt_type"]["extract"](self.text, extract=False)
  1440         first = {}
  1289             else:
  1441         for node in tree.childNodes:
  1290                 element_name = factory.etreeNamespaceFormat % name
  1442             name = node.nodeName
  1291                 if element_infos["maxOccurs"] == "unbounded" or element_infos["maxOccurs"] > 1:
  1443             if name == "#text" and node.data.strip() == "" or name == "#comment":
  1292                     values = self.findall(element_name)
  1444                 continue
  1293                     if element_infos["elmt_type"]["type"] == SIMPLETYPE:
  1445             elif elements.has_key(name):
  1294                         return map(lambda value:
  1446                 elements[name]["elmt_type"] = FindTypeInfos(factory, elements[name]["elmt_type"])
  1295                             element_infos["elmt_type"]["extract"](value.text, extract=False), 
  1447                 if elements[name]["maxOccurs"] == "unbounded" or elements[name]["maxOccurs"] > 1:
  1296                             values)
  1448                     if first.get(name, True):
  1297                     return values
  1449                         object.__setattr__(self, name, [elements[name]["elmt_type"]["extract"](node)])
  1298                 else:
  1450                         first[name] = False
  1299                     value = self.find(element_name)
       
  1300                     if element_infos["elmt_type"]["type"] == SIMPLETYPE:
       
  1301                         return element_infos["elmt_type"]["extract"](value.text, extract=False)
       
  1302                     return value
       
  1303             
       
  1304         elif classinfos.has_key("base"):
       
  1305             return classinfos["base"].__getattr__(self, name)
       
  1306         
       
  1307         return DefaultElementClass.__getattribute__(self, name)
       
  1308     
       
  1309     return getattrMethod
       
  1310 
       
  1311 def generateSetattrMethod(factory, class_definition, classinfos):
       
  1312     attributes = dict([(attr["name"], attr) for attr in classinfos["attributes"] if attr["use"] != "prohibited"])
       
  1313     optional_attributes = dict([(attr["name"], True) for attr in classinfos["attributes"] if attr["use"] == "optional"])
       
  1314     elements = OrderedDict([(element["name"], element) for element in classinfos["elements"]])
       
  1315     
       
  1316     def setattrMethod(self, name, value):
       
  1317         if attributes.has_key(name):
       
  1318             attribute_infos = attributes[name]
       
  1319             attribute_infos["attr_type"] = FindTypeInfos(factory, attribute_infos["attr_type"])
       
  1320             if optional_attributes.get(name, False):
       
  1321                 default = attribute_infos.get("default", None)
       
  1322                 if value is None or value == default:
       
  1323                     self.attrib.pop(name, None)
       
  1324                     return
       
  1325             elif attribute_infos.has_key("fixed"):
       
  1326                 return
       
  1327             return self.set(name, attribute_infos["attr_type"]["generate"](value))
       
  1328         
       
  1329         elif elements.has_key(name):
       
  1330             element_infos = elements[name]
       
  1331             element_infos["elmt_type"] = FindTypeInfos(factory, element_infos["elmt_type"])
       
  1332             if element_infos["type"] == ANY:
       
  1333                 element_infos["elmt_type"]["generate"](self, value)
       
  1334             
       
  1335             elif name == "content" and element_infos["elmt_type"]["type"] == SIMPLETYPE:
       
  1336                 self.text = element_infos["elmt_type"]["generate"](value)
       
  1337             
       
  1338             else:
       
  1339                 prefix = ("%s:" % factory.TargetNamespace
       
  1340                           if factory.TargetNamespace is not None else "")
       
  1341                 element_xpath = (prefix + name
       
  1342                                  if name != "content"
       
  1343                                  else elements["content"]["elmt_type"]["choices_xpath"].path)
       
  1344                 
       
  1345                 for element in self.xpath(element_xpath, namespaces=factory.NSMAP):
       
  1346                     self.remove(element)
       
  1347                 
       
  1348                 if value is not None:
       
  1349                     element_idx = elements.keys().index(name)
       
  1350                     if element_idx > 0:
       
  1351                         previous_elements_xpath = "|".join(map(
       
  1352                             lambda x: prefix + x
       
  1353                                       if x != "content"
       
  1354                                       else elements["content"]["elmt_type"]["choices_xpath"].path,
       
  1355                             elements.keys()[:element_idx]))
       
  1356                         
       
  1357                         insertion_point = len(self.xpath(previous_elements_xpath, namespaces=factory.NSMAP))
  1451                     else:
  1358                     else:
  1452                         getattr(self, name).append(elements[name]["elmt_type"]["extract"](node))
  1359                         insertion_point = 0
  1453                 else:
  1360                     
  1454                     object.__setattr__(self, name, elements[name]["elmt_type"]["extract"](node))
  1361                     if not isinstance(value, ListType):
  1455             elif elements.has_key("text"):
  1362                         value = [value]
  1456                 if elements["text"]["maxOccurs"] == "unbounded" or elements["text"]["maxOccurs"] > 1:
  1363                     
  1457                     if first.get("text", True):
  1364                     for element in reversed(value):
  1458                         object.__setattr__(self, "text", [elements["text"]["elmt_type"]["extract"](node)])
  1365                         if element_infos["elmt_type"]["type"] == SIMPLETYPE:
  1459                         first["text"] = False
  1366                             tmp_element = etree.Element(factory.etreeNamespaceFormat % name)
  1460                     else:
  1367                             tmp_element.text = element_infos["elmt_type"]["generate"](element)
  1461                         getattr(self, "text").append(elements["text"]["elmt_type"]["extract"](node))
  1368                             element = tmp_element
  1462                 else:
  1369                         self.insert(insertion_point, element)
  1463                     object.__setattr__(self, "text", elements["text"]["elmt_type"]["extract"](node))
  1370         
  1464             elif elements.has_key("content"):
  1371         elif classinfos.has_key("base"):
  1465                 if name in ["#cdata-section", "#text"]:
  1372             return classinfos["base"].__setattr__(self, name, value)
  1466                     if elements["content"]["elmt_type"]["type"] == SIMPLETYPE:
  1373         
  1467                         object.__setattr__(self, "content", elements["content"]["elmt_type"]["extract"](node.data, False))
  1374         else:
  1468                 else:
  1375             raise AttributeError("'%s' can't have an attribute '%s'." % (self.__class__.__name__, name))
  1469                     content = getattr(self, "content")
  1376         
  1470                     if elements["content"]["maxOccurs"] == "unbounded" or elements["content"]["maxOccurs"] > 1:
  1377     return setattrMethod
  1471                         if first.get("content", True):
       
  1472                             object.__setattr__(self, "content", [elements["content"]["elmt_type"]["extract"](node, None)])
       
  1473                             first["content"] = False
       
  1474                         else:
       
  1475                             content.append(elements["content"]["elmt_type"]["extract"](node, content))
       
  1476                     else:
       
  1477                         object.__setattr__(self, "content", elements["content"]["elmt_type"]["extract"](node, content))
       
  1478     return loadXMLTreeMethod
       
  1479         
       
  1480 
       
  1481 """
       
  1482 Method that generates the method for generating an xml text by following the
       
  1483 attributes list defined
       
  1484 """
       
  1485 def generateGenerateXMLText(factory, classinfos):
       
  1486     def generateXMLTextMethod(self, name, indent=0, extras={}, derived=False):
       
  1487         ind1, ind2 = getIndent(indent, name)
       
  1488         if not derived:
       
  1489             text = ind1 + u'<%s' % name
       
  1490         else:
       
  1491             text = u''
       
  1492         
       
  1493         first = True
       
  1494         
       
  1495         if not classinfos.has_key("base"):
       
  1496             extras.update(self.extraAttrs)
       
  1497             for attr, value in extras.iteritems():
       
  1498                 if not first and not self.singleLineAttributes:
       
  1499                     text += u'\n%s' % (ind2)
       
  1500                 text += u' %s=%s' % (attr, quoteattr(value))
       
  1501                 first = False
       
  1502             extras.clear()
       
  1503         for attr in classinfos["attributes"]:
       
  1504             if attr["use"] != "prohibited":
       
  1505                 attr["attr_type"] = FindTypeInfos(factory, attr["attr_type"])
       
  1506                 value = getattr(self, attr["name"], None)
       
  1507                 if value != None:
       
  1508                     computed_value = attr["attr_type"]["generate"](value)
       
  1509                 else:
       
  1510                     computed_value = None
       
  1511                 if attr["use"] != "optional" or (value != None and \
       
  1512                    computed_value != attr.get("default", attr["attr_type"]["generate"](attr["attr_type"]["initial"]()))):
       
  1513                     if classinfos.has_key("base"):
       
  1514                         extras[attr["name"]] = computed_value
       
  1515                     else:
       
  1516                         if not first and not self.singleLineAttributes:
       
  1517                             text += u'\n%s' % (ind2)
       
  1518                         text += ' %s=%s' % (attr["name"], quoteattr(computed_value))
       
  1519                     first = False
       
  1520         if classinfos.has_key("base"):
       
  1521             first, new_text = classinfos["base"].generateXMLText(self, name, indent, extras, True)
       
  1522             text += new_text
       
  1523         else:
       
  1524             first = True
       
  1525         for element in classinfos["elements"]:
       
  1526             element["elmt_type"] = FindTypeInfos(factory, element["elmt_type"])
       
  1527             value = getattr(self, element["name"], None)
       
  1528             if element["minOccurs"] == 0 and element["maxOccurs"] == 1:
       
  1529                 if value is not None:
       
  1530                     if first:
       
  1531                         text += u'>\n'
       
  1532                         first = False
       
  1533                     text += element["elmt_type"]["generate"](value, element["name"], indent + 1)
       
  1534             elif element["minOccurs"] == 1 and element["maxOccurs"] == 1:
       
  1535                 if first:
       
  1536                     text += u'>\n'
       
  1537                     first = False
       
  1538                 if element["name"] == "content" and element["elmt_type"]["type"] == SIMPLETYPE:
       
  1539                     text += element["elmt_type"]["generate"](value)
       
  1540                 else:
       
  1541                     text += element["elmt_type"]["generate"](value, element["name"], indent + 1)
       
  1542             else:
       
  1543                 if first and len(value) > 0:
       
  1544                     text += u'>\n'
       
  1545                     first = False
       
  1546                 for item in value:
       
  1547                     text += element["elmt_type"]["generate"](item, element["name"], indent + 1)
       
  1548         if not derived:
       
  1549             if first:
       
  1550                 text += u'/>\n'
       
  1551             else:
       
  1552                 text += ind1 + u'</%s>\n' % (name)
       
  1553             return text
       
  1554         else:
       
  1555             return first, text
       
  1556     return generateXMLTextMethod
       
  1557 
  1378 
  1558 def gettypeinfos(name, facets):
  1379 def gettypeinfos(name, facets):
  1559     if facets.has_key("enumeration") and facets["enumeration"][0] is not None:
  1380     if facets.has_key("enumeration") and facets["enumeration"][0] is not None:
  1560         return facets["enumeration"][0]
  1381         return facets["enumeration"][0]
  1561     elif facets.has_key("maxInclusive"):
  1382     elif facets.has_key("maxInclusive"):
  1609                         raise ValueError("Wrong path!")
  1430                         raise ValueError("Wrong path!")
  1610                     attr_type = gettypeinfos(elements[parts[0]]["elmt_type"]["basename"], 
  1431                     attr_type = gettypeinfos(elements[parts[0]]["elmt_type"]["basename"], 
  1611                                              elements[parts[0]]["elmt_type"]["facets"])
  1432                                              elements[parts[0]]["elmt_type"]["facets"])
  1612                     value = getattr(self, parts[0], "")
  1433                     value = getattr(self, parts[0], "")
  1613                 elif parts[0] == "content":
  1434                 elif parts[0] == "content":
  1614                     return self.content["value"].getElementInfos(self.content["name"], path)
  1435                     return self.content.getElementInfos(self.content.getLocalTag(), path)
  1615                 else:
  1436                 else:
  1616                     attr = getattr(self, parts[0], None)
  1437                     attr = getattr(self, parts[0], None)
  1617                     if attr is None:
  1438                     if attr is None:
  1618                         raise ValueError("Wrong path!")
  1439                         raise ValueError("Wrong path!")
  1619                     if len(parts) == 1:
  1440                     if len(parts) == 1:
  1620                         return attr.getElementInfos(parts[0])
  1441                         return attr.getElementInfos(parts[0])
  1621                     else:
  1442                     else:
  1622                         return attr.getElementInfos(parts[0], parts[1])
  1443                         return attr.getElementInfos(parts[0], parts[1])
  1623             elif elements.has_key("content"):
  1444             elif elements.has_key("content"):
  1624                 if len(parts) > 0:
  1445                 if len(parts) > 0:
  1625                     return self.content["value"].getElementInfos(name, path)
  1446                     return self.content.getElementInfos(name, path)
  1626             elif classinfos.has_key("base"):
  1447             elif classinfos.has_key("base"):
  1627                 classinfos["base"].getElementInfos(name, path)
  1448                 classinfos["base"].getElementInfos(name, path)
  1628             else:
  1449             else:
  1629                 raise ValueError("Wrong path!")
  1450                 raise ValueError("Wrong path!")
  1630         else:
  1451         else:
  1638                 if element_name == "content" and element["type"] == CHOICE:
  1459                 if element_name == "content" and element["type"] == CHOICE:
  1639                     attr_type = [(choice["name"], None) for choice in element["choices"]]
  1460                     attr_type = [(choice["name"], None) for choice in element["choices"]]
  1640                     if self.content is None:
  1461                     if self.content is None:
  1641                         value = ""
  1462                         value = ""
  1642                     else:
  1463                     else:
  1643                         value = self.content["name"]
  1464                         value = self.content.getLocalTag()
  1644                         if self.content["value"] is not None:
  1465                         if self.content is not None:
  1645                             if self.content["name"] == "sequence":
  1466                             children.extend(self.content.getElementInfos(value)["children"])
  1646                                 choices_dict = dict([(choice["name"], choice) for choice in element["choices"]])
       
  1647                                 sequence_infos = choices_dict.get("sequence", None)
       
  1648                                 if sequence_infos is not None:
       
  1649                                     children.extend([item.getElementInfos(infos["name"]) for item, infos in zip(self.content["value"], sequence_infos["elements"])])
       
  1650                             else:
       
  1651                                 children.extend(self.content["value"].getElementInfos(self.content["name"])["children"])
       
  1652                 elif element["elmt_type"]["type"] == SIMPLETYPE:
  1467                 elif element["elmt_type"]["type"] == SIMPLETYPE:
  1653                     children.append({"name": element_name, "require": element["minOccurs"] != 0, 
  1468                     children.append({"name": element_name, "require": element["minOccurs"] != 0, 
  1654                         "type": gettypeinfos(element["elmt_type"]["basename"], 
  1469                         "type": gettypeinfos(element["elmt_type"]["basename"], 
  1655                                              element["elmt_type"]["facets"]),
  1470                                              element["elmt_type"]["facets"]),
  1656                         "value": getattr(self, element_name, None)})
  1471                         "value": getattr(self, element_name, None)})
  1703                             instance.setElementValue(parts[1], value)
  1518                             instance.setElementValue(parts[1], value)
  1704                         else:
  1519                         else:
  1705                             instance.setElementValue(None, value)
  1520                             instance.setElementValue(None, value)
  1706             elif elements.has_key("content"):
  1521             elif elements.has_key("content"):
  1707                 if len(parts) > 0:
  1522                 if len(parts) > 0:
  1708                     self.content["value"].setElementValue(path, value)
  1523                     self.content.setElementValue(path, value)
  1709             elif classinfos.has_key("base"):
  1524             elif classinfos.has_key("base"):
  1710                 classinfos["base"].setElementValue(self, path, value)
  1525                 classinfos["base"].setElementValue(self, path, value)
  1711         elif elements.has_key("content"):
  1526         elif elements.has_key("content"):
  1712             if value == "":
  1527             if value == "":
  1713                 if elements["content"]["minOccurs"] == 0:
  1528                 if elements["content"]["minOccurs"] == 0:
  1714                     self.setcontent(None)
  1529                     self.setcontent([])
  1715                 else:
  1530                 else:
  1716                     raise ValueError("\"content\" element is required!")
  1531                     raise ValueError("\"content\" element is required!")
  1717             else:
  1532             else:
  1718                 self.setcontentbytype(value)
  1533                 self.setcontentbytype(value)
  1719     return setElementValue
  1534     return setElementValue
  1721 """
  1536 """
  1722 Methods that generates the different methods for setting and getting the attributes
  1537 Methods that generates the different methods for setting and getting the attributes
  1723 """
  1538 """
  1724 def generateInitMethod(factory, classinfos):
  1539 def generateInitMethod(factory, classinfos):
  1725     def initMethod(self):
  1540     def initMethod(self):
  1726         self.extraAttrs = {}
       
  1727         if classinfos.has_key("base"):
  1541         if classinfos.has_key("base"):
  1728             classinfos["base"].__init__(self)
  1542             classinfos["base"]._init_(self)
  1729         for attribute in classinfos["attributes"]:
  1543         for attribute in classinfos["attributes"]:
  1730             attribute["attr_type"] = FindTypeInfos(factory, attribute["attr_type"])
  1544             attribute["attr_type"] = FindTypeInfos(factory, attribute["attr_type"])
  1731             if attribute["use"] == "required":
  1545             if attribute["use"] == "required":
  1732                 setattr(self, attribute["name"], attribute["attr_type"]["initial"]())
  1546                 self.set(attribute["name"], attribute["attr_type"]["generate"](attribute["attr_type"]["initial"]()))
  1733             elif attribute["use"] == "optional":
       
  1734                 if attribute.has_key("default"):
       
  1735                     setattr(self, attribute["name"], attribute["attr_type"]["extract"](attribute["default"], False))
       
  1736                 else:
       
  1737                     setattr(self, attribute["name"], None)
       
  1738         for element in classinfos["elements"]:
  1547         for element in classinfos["elements"]:
  1739             setattr(self, element["name"], GetElementInitialValue(factory, element))
  1548             if element["type"] != CHOICE:
       
  1549                 element_name = (
       
  1550                     etree.QName(factory.NSMAP["xhtml"], "p")
       
  1551                     if element["type"] == ANY
       
  1552                     else factory.etreeNamespaceFormat % element["name"])
       
  1553                 initial = GetElementInitialValue(factory, element)
       
  1554                 if initial is not None:
       
  1555                     map(self.append, initial)
  1740     return initMethod
  1556     return initMethod
  1741 
  1557 
  1742 def generateSetMethod(attr):
  1558 def generateSetMethod(attr):
  1743     def setMethod(self, value):
  1559     def setMethod(self, value):
  1744         setattr(self, attr, value)
  1560         setattr(self, attr, value)
  1751 
  1567 
  1752 def generateAddMethod(attr, factory, infos):
  1568 def generateAddMethod(attr, factory, infos):
  1753     def addMethod(self):
  1569     def addMethod(self):
  1754         if infos["type"] == ATTRIBUTE:
  1570         if infos["type"] == ATTRIBUTE:
  1755             infos["attr_type"] = FindTypeInfos(factory, infos["attr_type"])
  1571             infos["attr_type"] = FindTypeInfos(factory, infos["attr_type"])
  1756             initial = infos["attr_type"]["initial"]
  1572             if not infos.has_key("default"):
  1757             extract = infos["attr_type"]["extract"]
  1573                 setattr(self, attr, infos["attr_type"]["initial"]())
  1758         elif infos["type"] == ELEMENT:
  1574         elif infos["type"] == ELEMENT:
  1759             infos["elmt_type"] = FindTypeInfos(factory, infos["elmt_type"])
  1575             infos["elmt_type"] = FindTypeInfos(factory, infos["elmt_type"])
  1760             initial = infos["elmt_type"]["initial"]
  1576             value = infos["elmt_type"]["initial"]()
  1761             extract = infos["elmt_type"]["extract"]
  1577             DefaultElementClass.__setattr__(value, "tag", factory.etreeNamespaceFormat % attr)
       
  1578             setattr(self, attr, value)
       
  1579             value._init_()
  1762         else:
  1580         else:
  1763             raise ValueError("Invalid class attribute!")
  1581             raise ValueError("Invalid class attribute!")
  1764         if infos.has_key("default"):
       
  1765             setattr(self, attr, extract(infos["default"], False))
       
  1766         else:
       
  1767             setattr(self, attr, initial())
       
  1768     return addMethod
  1582     return addMethod
  1769 
  1583 
  1770 def generateDeleteMethod(attr):
  1584 def generateDeleteMethod(attr):
  1771     def deleteMethod(self):
  1585     def deleteMethod(self):
  1772         setattr(self, attr, None)
  1586         setattr(self, attr, None)
  1775 def generateAppendMethod(attr, maxOccurs, factory, infos):
  1589 def generateAppendMethod(attr, maxOccurs, factory, infos):
  1776     def appendMethod(self, value):
  1590     def appendMethod(self, value):
  1777         infos["elmt_type"] = FindTypeInfos(factory, infos["elmt_type"])
  1591         infos["elmt_type"] = FindTypeInfos(factory, infos["elmt_type"])
  1778         attr_list = getattr(self, attr)
  1592         attr_list = getattr(self, attr)
  1779         if maxOccurs == "unbounded" or len(attr_list) < maxOccurs:
  1593         if maxOccurs == "unbounded" or len(attr_list) < maxOccurs:
  1780             if infos["elmt_type"]["check"](value):
  1594             if len(attr_list) == 0:
  1781                 attr_list.append(value)
  1595                 setattr(self, attr, [value])
  1782             else:
  1596             else:
  1783                 raise ValueError("\"%s\" value isn't valid!" % attr)
  1597                 attr_list[-1].addnext(value)
  1784         else:
  1598         else:
  1785             raise ValueError("There can't be more than %d values in \"%s\"!" % (maxOccurs, attr))
  1599             raise ValueError("There can't be more than %d values in \"%s\"!" % (maxOccurs, attr))
  1786     return appendMethod
  1600     return appendMethod
  1787 
  1601 
  1788 def generateInsertMethod(attr, maxOccurs, factory, infos):
  1602 def generateInsertMethod(attr, maxOccurs, factory, infos):
  1789     def insertMethod(self, index, value):
  1603     def insertMethod(self, index, value):
  1790         infos["elmt_type"] = FindTypeInfos(factory, infos["elmt_type"])
  1604         infos["elmt_type"] = FindTypeInfos(factory, infos["elmt_type"])
  1791         attr_list = getattr(self, attr)
  1605         attr_list = getattr(self, attr)
  1792         if maxOccurs == "unbounded" or len(attr_list) < maxOccurs:
  1606         if maxOccurs == "unbounded" or len(attr_list) < maxOccurs:
  1793             if infos["elmt_type"]["check"](value):
  1607             if len(attr_list) == 0:
  1794                 attr_list.insert(index, value)
  1608                 setattr(self, attr, [value])
       
  1609             elif index == 0:
       
  1610                 attr_list[0].addprevious(value)
  1795             else:
  1611             else:
  1796                 raise ValueError("\"%s\" value isn't valid!" % attr)
  1612                 attr_list[min(index - 1, len(attr_list) - 1)].addnext(value)
  1797         else:
  1613         else:
  1798             raise ValueError("There can't be more than %d values in \"%s\"!" % (maxOccurs, attr))
  1614             raise ValueError("There can't be more than %d values in \"%s\"!" % (maxOccurs, attr))
  1799     return insertMethod
  1615     return insertMethod
  1800 
  1616 
  1801 def generateGetChoicesMethod(choice_types):
  1617 def generateGetChoicesMethod(choice_types):
  1803         return [choice["name"] for choice in choice_types]
  1619         return [choice["name"] for choice in choice_types]
  1804     return getChoicesMethod
  1620     return getChoicesMethod
  1805 
  1621 
  1806 def generateSetChoiceByTypeMethod(factory, choice_types):
  1622 def generateSetChoiceByTypeMethod(factory, choice_types):
  1807     choices = dict([(choice["name"], choice) for choice in choice_types])
  1623     choices = dict([(choice["name"], choice) for choice in choice_types])
  1808     def setChoiceMethod(self, type):
  1624     def setChoiceMethod(self, content_type):
  1809         if not choices.has_key(type):
  1625         if not choices.has_key(content_type):
  1810             raise ValueError("Unknown \"%s\" choice type for \"content\"!" % type)
  1626             raise ValueError("Unknown \"%s\" choice type for \"content\"!" % content_type)
  1811         choices[type]["elmt_type"] = FindTypeInfos(factory, choices[type]["elmt_type"])
  1627         choices[content_type]["elmt_type"] = FindTypeInfos(factory, choices[content_type]["elmt_type"])
  1812         new_element = choices[type]["elmt_type"]["initial"]()
  1628         new_content = choices[content_type]["elmt_type"]["initial"]()
  1813         self.content = {"name": type, "value": new_element}
  1629         DefaultElementClass.__setattr__(new_content, "tag", factory.etreeNamespaceFormat % content_type)
  1814         return new_element
  1630         self.content = new_content
       
  1631         return new_content
  1815     return setChoiceMethod
  1632     return setChoiceMethod
  1816 
  1633 
  1817 def generateAppendChoiceByTypeMethod(maxOccurs, factory, choice_types):
  1634 def generateAppendChoiceByTypeMethod(maxOccurs, factory, choice_types):
  1818     choices = dict([(choice["name"], choice) for choice in choice_types])
  1635     choices = dict([(choice["name"], choice) for choice in choice_types])
  1819     def appendChoiceMethod(self, type):
  1636     def appendChoiceMethod(self, content_type):
  1820         if not choices.has_key(type):
  1637         if not choices.has_key(content_type):
  1821             raise ValueError("Unknown \"%s\" choice type for \"content\"!" % type)
  1638             raise ValueError("Unknown \"%s\" choice type for \"content\"!" % content_type)
  1822         choices[type]["elmt_type"] = FindTypeInfos(factory, choices[type]["elmt_type"])
  1639         choices[content_type]["elmt_type"] = FindTypeInfos(factory, choices[content_type]["elmt_type"])
  1823         if maxOccurs == "unbounded" or len(self.content) < maxOccurs:
  1640         if maxOccurs == "unbounded" or len(self.content) < maxOccurs:
  1824             new_element = choices[type]["elmt_type"]["initial"]()
  1641             new_element = choices[content_type]["elmt_type"]["initial"]()
  1825             self.content.append({"name": type, "value": new_element})
  1642             DefaultElementClass.__setattr__(new_element, "tag", factory.etreeNamespaceFormat % content_type)
       
  1643             self.appendcontent(new_element)
  1826             return new_element
  1644             return new_element
  1827         else:
  1645         else:
  1828             raise ValueError("There can't be more than %d values in \"content\"!" % maxOccurs)
  1646             raise ValueError("There can't be more than %d values in \"content\"!" % maxOccurs)
  1829     return appendChoiceMethod
  1647     return appendChoiceMethod
  1830 
  1648 
  1831 def generateInsertChoiceByTypeMethod(maxOccurs, factory, choice_types):
  1649 def generateInsertChoiceByTypeMethod(maxOccurs, factory, choice_types):
  1832     choices = dict([(choice["name"], choice) for choice in choice_types])
  1650     choices = dict([(choice["name"], choice) for choice in choice_types])
  1833     def insertChoiceMethod(self, index, type):
  1651     def insertChoiceMethod(self, index, content_type):
  1834         if not choices.has_key(type):
  1652         if not choices.has_key(content_type):
  1835             raise ValueError("Unknown \"%s\" choice type for \"content\"!" % type)
  1653             raise ValueError("Unknown \"%s\" choice type for \"content\"!" % content_type)
  1836         choices[type]["elmt_type"] = FindTypeInfos(factory, choices[type]["elmt_type"])
  1654         choices[type]["elmt_type"] = FindTypeInfos(factory, choices[content_type]["elmt_type"])
  1837         if maxOccurs == "unbounded" or len(self.content) < maxOccurs:
  1655         if maxOccurs == "unbounded" or len(self.content) < maxOccurs:
  1838             new_element = choices[type]["elmt_type"]["initial"]()
  1656             new_element = choices[content_type]["elmt_type"]["initial"]()
  1839             self.content.insert(index, {"name" : type, "value" : new_element})
  1657             DefaultElementClass.__setattr__(new_element, "tag", factory.etreeNamespaceFormat % content_type)
       
  1658             self.insertcontent(index, new_element)
  1840             return new_element
  1659             return new_element
  1841         else:
  1660         else:
  1842             raise ValueError("There can't be more than %d values in \"content\"!" % maxOccurs)
  1661             raise ValueError("There can't be more than %d values in \"content\"!" % maxOccurs)
  1843     return insertChoiceMethod
  1662     return insertChoiceMethod
  1844 
  1663 
  1845 def generateRemoveMethod(attr, minOccurs):
  1664 def generateRemoveMethod(attr, minOccurs):
  1846     def removeMethod(self, index):
  1665     def removeMethod(self, index):
  1847         attr_list = getattr(self, attr)
  1666         attr_list = getattr(self, attr)
  1848         if len(attr_list) > minOccurs:
  1667         if len(attr_list) > minOccurs:
  1849             getattr(self, attr).pop(index)
  1668             self.remove(attr_list[index])
  1850         else:
  1669         else:
  1851             raise ValueError("There can't be less than %d values in \"%s\"!" % (minOccurs, attr))
  1670             raise ValueError("There can't be less than %d values in \"%s\"!" % (minOccurs, attr))
  1852     return removeMethod
  1671     return removeMethod
  1853 
  1672 
  1854 def generateCountMethod(attr):
  1673 def generateCountMethod(attr):
  1855     def countMethod(self):
  1674     def countMethod(self):
  1856         return len(getattr(self, attr))
  1675         return len(getattr(self, attr))
  1857     return countMethod
  1676     return countMethod
  1858 
  1677 
  1859 """
  1678 """
  1860 This function generate the classes from a class factory
  1679 This function generate a xml parser from a class factory
  1861 """
  1680 """
  1862 def GenerateClasses(factory):
  1681 
       
  1682 NAMESPACE_PATTERN = re.compile("xmlns(?:\:[^\=]*)?=\"[^\"]*\" ")
       
  1683 
       
  1684 class DefaultElementClass(etree.ElementBase):
       
  1685     
       
  1686     StructurePattern = re.compile("$")
       
  1687     
       
  1688     def _init_(self):
       
  1689         pass
       
  1690     
       
  1691     def getLocalTag(self):
       
  1692         return etree.QName(self.tag).localname
       
  1693         
       
  1694     def tostring(self):
       
  1695         return NAMESPACE_PATTERN.sub("", etree.tostring(self, pretty_print=True))
       
  1696 
       
  1697 class XMLElementClassLookUp(etree.PythonElementClassLookup):
       
  1698     
       
  1699     def __init__(self, classes, *args, **kwargs):
       
  1700         etree.PythonElementClassLookup.__init__(self, *args, **kwargs)
       
  1701         self.LookUpClasses = classes
       
  1702     
       
  1703     def GetElementClass(self, element_tag, parent_tag=None, default=DefaultElementClass):
       
  1704         element_class = self.LookUpClasses.get(element_tag, (default, None))
       
  1705         if not isinstance(element_class, DictType):
       
  1706             if isinstance(element_class[0], (StringType, UnicodeType)):
       
  1707                 return self.GetElementClass(element_class[0], default=default)
       
  1708             return element_class[0]
       
  1709         
       
  1710         element_with_parent_class = element_class.get(parent_tag, default)
       
  1711         if isinstance(element_with_parent_class, (StringType, UnicodeType)):
       
  1712             return self.GetElementClass(element_with_parent_class, default=default)
       
  1713         return element_with_parent_class
       
  1714         
       
  1715     def lookup(self, document, element):
       
  1716         parent = element.getparent()
       
  1717         element_class = self.GetElementClass(element.tag, 
       
  1718             parent.tag if parent is not None else None)
       
  1719         if isinstance(element_class, ListType):
       
  1720             children = "".join([
       
  1721                 "%s " % etree.QName(child.tag).localname
       
  1722                 for child in element])
       
  1723             for possible_class in element_class:
       
  1724                 if isinstance(possible_class, (StringType, UnicodeType)):
       
  1725                     possible_class = self.GetElementClass(possible_class)
       
  1726                 if possible_class.StructurePattern.match(children) is not None:
       
  1727                     return possible_class
       
  1728             return element_class[0]
       
  1729         return element_class
       
  1730 
       
  1731 class XMLClassParser(etree.XMLParser):
       
  1732 
       
  1733     def __init__(self, namespaces, default_namespace_format, base_class, *args, **kwargs):
       
  1734         etree.XMLParser.__init__(self, *args, **kwargs)
       
  1735         self.DefaultNamespaceFormat = default_namespace_format
       
  1736         self.NSMAP = namespaces
       
  1737         targetNamespace = etree.QName(default_namespace_format % "d").namespace
       
  1738         if targetNamespace is not None:
       
  1739             self.RootNSMAP = {
       
  1740                 name if targetNamespace != uri else None: uri
       
  1741                 for name, uri in namespaces.iteritems()}
       
  1742         else:
       
  1743             self.RootNSMAP = namespaces
       
  1744         self.BaseClass = base_class
       
  1745     
       
  1746     def set_element_class_lookup(self, class_lookup):
       
  1747         etree.XMLParser.set_element_class_lookup(self, class_lookup)
       
  1748         self.ClassLookup = class_lookup
       
  1749     
       
  1750     def Dumps(self, xml_obj):
       
  1751         return etree.tostring(xml_obj)
       
  1752     
       
  1753     def Loads(self, xml_string):
       
  1754         return etree.fromstring(xml_string, self)
       
  1755     
       
  1756     def CreateRoot(self):
       
  1757         if self.BaseClass is not None:
       
  1758             root = self.makeelement(
       
  1759                 self.DefaultNamespaceFormat % self.BaseClass[0],
       
  1760                 nsmap=self.RootNSMAP)
       
  1761             root._init_()
       
  1762             return root
       
  1763         return None
       
  1764     
       
  1765     def GetElementClass(self, element_tag, parent_tag=None):
       
  1766         return self.ClassLookup.GetElementClass(
       
  1767             self.DefaultNamespaceFormat % element_tag, 
       
  1768             self.DefaultNamespaceFormat % parent_tag 
       
  1769             if parent_tag is not None else parent_tag, 
       
  1770             None)
       
  1771     
       
  1772     def CreateElement(self, element_tag, parent_tag=None, class_idx=None):
       
  1773         element_class = self.GetElementClass(element_tag, parent_tag)
       
  1774         if isinstance(element_class, ListType):
       
  1775             if class_idx is not None and class_idx < len(element_class):
       
  1776                 new_element = element_class[class_idx]()
       
  1777             else:
       
  1778                 raise ValueError, "No corresponding class found!"
       
  1779         else:
       
  1780             new_element = element_class()
       
  1781         DefaultElementClass.__setattr__(new_element, "tag", self.DefaultNamespaceFormat % element_tag)
       
  1782         new_element._init_()
       
  1783         return new_element
       
  1784     
       
  1785 def GenerateParser(factory, xsdstring):
  1863     ComputedClasses = factory.CreateClasses()
  1786     ComputedClasses = factory.CreateClasses()
  1864     if factory.FileName is not None and len(ComputedClasses) == 1:
  1787     
  1865         UpdateXMLClassGlobals(ComputedClasses[factory.FileName])
  1788     if factory.FileName is not None:
  1866         return ComputedClasses[factory.FileName]
  1789         ComputedClasses = ComputedClasses[factory.FileName]
  1867     else:
  1790     BaseClass = [(name, XSDclass) for name, XSDclass in ComputedClasses.items() if XSDclass.IsBaseClass]
  1868         UpdateXMLClassGlobals(ComputedClasses)
  1791        
  1869         return ComputedClasses
  1792     parser = XMLClassParser(
  1870 
  1793         factory.NSMAP,
  1871 def UpdateXMLClassGlobals(classes):
  1794         factory.etreeNamespaceFormat,
  1872     globals().update(classes)
  1795         BaseClass[0] if len(BaseClass) == 1 else None,
       
  1796         schema = etree.XMLSchema(etree.fromstring(xsdstring)),
       
  1797         strip_cdata = False, remove_blank_text=True)
       
  1798     class_lookup = XMLElementClassLookUp(factory.ComputedClassesLookUp)
       
  1799     parser.set_element_class_lookup(class_lookup)
       
  1800     
       
  1801     return parser
       
  1802