xmlclass/xmlclass.py
changeset 1290 13ee5f4ab612
parent 1179 3e7bd88fcff7
child 1291 42ea51d083ce
equal deleted inserted replaced
1286:adda406d3960 1290:13ee5f4ab612
    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 = {}
   589         return factory.GetQualifiedNameInfos(name, namespace)
   591         return factory.GetQualifiedNameInfos(name, namespace)
   590     return infos
   592     return infos
   591     
   593     
   592 def GetElementInitialValue(factory, infos):
   594 def GetElementInitialValue(factory, infos):
   593     infos["elmt_type"] = FindTypeInfos(factory, infos["elmt_type"])
   595     infos["elmt_type"] = FindTypeInfos(factory, infos["elmt_type"])
   594     if infos["minOccurs"] == 0 and infos["maxOccurs"] == 1:
   596     if infos["minOccurs"] == 1:
   595         if infos.has_key("default"):
   597         element_name = factory.etreeNamespaceFormat % infos["name"]
   596             return infos["elmt_type"]["extract"](infos["default"], False)
   598         if infos["type"] == SIMPLETYPE:
   597         else:
   599             def initial_value():
   598             return None
   600                 value = etree.Element(element_name)
   599     elif infos["minOccurs"] == 1 and infos["maxOccurs"] == 1:
   601                 value.text = (infos["elmt_type"]["generate"](infos["elmt_type"]["initial"]()))
   600         return infos["elmt_type"]["initial"]()
   602                 return value
       
   603         else:
       
   604             def initial_value():
       
   605                 value = infos["elmt_type"]["initial"]()
       
   606                 DefaultElementClass.__setattr__(value, "tag", element_name)
       
   607                 return value
       
   608         return [initial_value() for i in xrange(infos["minOccurs"])]
   601     else:
   609     else:
   602         return [infos["elmt_type"]["initial"]() for i in xrange(infos["minOccurs"])]
   610         return []
   603 
   611 
   604 def HandleError(message, raise_exception):
   612 def HandleError(message, raise_exception):
   605     if raise_exception:
   613     if raise_exception:
   606         raise ValueError(message)
   614         raise ValueError(message)
   607     return False
   615     return False
   689                     choices_dict[element["name"]] = infos
   697                     choices_dict[element["name"]] = infos
   690         else:
   698         else:
   691             if choices_dict.has_key(choice_name):
   699             if choices_dict.has_key(choice_name):
   692                 raise ValueError("'%s' element defined two times in choice" % choice_name)
   700                 raise ValueError("'%s' element defined two times in choice" % choice_name)
   693             choices_dict[choice_name] = infos
   701             choices_dict[choice_name] = infos
       
   702     choices_xpath = "|".join(map(lambda x: "%s:%s" % (factory.TargetNamespace, x), choices_dict.keys()))
       
   703     
       
   704     def GetContentChoicesXPath():
       
   705         return choices_xpath
   694     
   706     
   695     def GetContentInitial():
   707     def GetContentInitial():
   696         content_name, infos = choices[0]
   708         content_name, infos = choices[0]
   697         if content_name == "sequence":
   709         if content_name == "sequence":
   698             content_value = []
   710             content_value = []
   826                         text += element_infos["elmt_type"]["generate"](element_value["value"], element_infos["name"], indent)
   838                         text += element_infos["elmt_type"]["generate"](element_value["value"], element_infos["name"], indent)
   827         return text
   839         return text
   828         
   840         
   829     return {
   841     return {
   830         "type": COMPLEXTYPE,
   842         "type": COMPLEXTYPE,
       
   843         "choices_xpath": GetContentChoicesXPath,
   831         "initial": GetContentInitial,
   844         "initial": GetContentInitial,
   832         "check": CheckContent,
   845         "check": CheckContent,
   833         "extract": ExtractContent,
   846         "extract": ExtractContent,
   834         "generate": GenerateContent
   847         "generate": GenerateContent
   835     }
   848     }
   899         # Dictionary for stocking Classes and Types definitions created from
   912         # Dictionary for stocking Classes and Types definitions created from
   900         # the XML tree
   913         # the XML tree
   901         self.XMLClassDefinitions = {}
   914         self.XMLClassDefinitions = {}
   902         
   915         
   903         self.DefinedNamespaces = {}
   916         self.DefinedNamespaces = {}
       
   917         self.NSMAP = {}
   904         self.Namespaces = {}
   918         self.Namespaces = {}
   905         self.SchemaNamespace = None
   919         self.SchemaNamespace = None
   906         self.TargetNamespace = None
   920         self.TargetNamespace = None
       
   921         self.etreeNamespaceFormat = "%s"
   907         
   922         
   908         self.CurrentCompilations = []
   923         self.CurrentCompilations = []
   909         
   924         
   910         # Dictionaries for stocking Classes and Types generated
   925         # Dictionaries for stocking Classes and Types generated
   911         self.ComputeAfter = []
   926         self.ComputeAfter = []
   912         if self.FileName is not None:
   927         if self.FileName is not None:
   913             self.ComputedClasses = {self.FileName: {}}
   928             self.ComputedClasses = {self.FileName: {}}
   914         else:
   929         else:
   915             self.ComputedClasses = {}
   930             self.ComputedClasses = {}
   916         self.ComputedClassesInfos = {}
   931         self.ComputedClassesInfos = {}
       
   932         self.ComputedClassesLookUp = {}
       
   933         self.EquivalentClassesParent = {}
   917         self.AlreadyComputed = {}
   934         self.AlreadyComputed = {}
   918 
   935 
   919     def GetQualifiedNameInfos(self, name, namespace=None, canbenone=False):
   936     def GetQualifiedNameInfos(self, name, namespace=None, canbenone=False):
   920         if namespace is None:
   937         if namespace is None:
   921             if self.Namespaces[self.SchemaNamespace].has_key(name):
   938             if self.Namespaces[self.SchemaNamespace].has_key(name):
  1014                     attrs[name] = infos["extract"][element_name](attr)
  1031                     attrs[name] = infos["extract"][element_name](attr)
  1015                 else:
  1032                 else:
  1016                     attrs[name] = infos["extract"]["default"](attr)
  1033                     attrs[name] = infos["extract"]["default"](attr)
  1017             elif namespace == "xmlns":
  1034             elif namespace == "xmlns":
  1018                 infos = self.GetQualifiedNameInfos("anyURI", self.SchemaNamespace)
  1035                 infos = self.GetQualifiedNameInfos("anyURI", self.SchemaNamespace)
  1019                 self.DefinedNamespaces[infos["extract"](attr)] = name
  1036                 value = infos["extract"](attr)
       
  1037                 self.DefinedNamespaces[value] = name
       
  1038                 self.NSMAP[name] = value
  1020             else:
  1039             else:
  1021                 raise ValueError("Invalid attribute \"%s\" for member \"%s\"!" % (qualified_name, node.nodeName))
  1040                 raise ValueError("Invalid attribute \"%s\" for member \"%s\"!" % (qualified_name, node.nodeName))
  1022         for attr in valid_attrs:
  1041         for attr in valid_attrs:
  1023             if attr not in attrs and \
  1042             if attr not in attrs and \
  1024                self.Namespaces[self.SchemaNamespace].has_key(attr) and \
  1043                self.Namespaces[self.SchemaNamespace].has_key(attr) and \
  1061         else:
  1080         else:
  1062             raise ValueError("\"%s\" class already defined. Choose another name!" % typename)
  1081             raise ValueError("\"%s\" class already defined. Choose another name!" % typename)
  1063 
  1082 
  1064     def ParseSchema(self):
  1083     def ParseSchema(self):
  1065         pass
  1084         pass
  1066 
  1085     
       
  1086     def AddEquivalentClass(self, name, base):
       
  1087         equivalences = self.EquivalentClassesParent.setdefault(self.etreeNamespaceFormat % name, {})
       
  1088         equivalences[self.etreeNamespaceFormat % base] = True
       
  1089         
       
  1090     def AddToLookupClass(self, name, parent, typeinfos):
       
  1091         lookup_name = self.etreeNamespaceFormat % name
       
  1092         if isinstance(typeinfos, (StringType, UnicodeType)):
       
  1093             self.AddEquivalentClass(name, typeinfos)
       
  1094             typeinfos = self.etreeNamespaceFormat % typeinfos
       
  1095         lookup_classes = self.ComputedClassesLookUp.get(lookup_name)
       
  1096         if lookup_classes is None:
       
  1097             self.ComputedClassesLookUp[lookup_name] = (typeinfos, parent)
       
  1098         elif isinstance(lookup_classes, DictType):
       
  1099             lookup_classes[self.etreeNamespaceFormat % parent 
       
  1100                            if parent is not None else None] = typeinfos
       
  1101         else:
       
  1102             lookup_classes = {self.etreeNamespaceFormat % lookup_classes[1]
       
  1103                               if lookup_classes[1] is not None else None: lookup_classes[0]}
       
  1104             lookup_classes[self.etreeNamespaceFormat % parent
       
  1105                            if parent is not None else None] = typeinfos
       
  1106             self.ComputedClassesLookUp[lookup_name] = lookup_classes
       
  1107     
  1067     def ExtractTypeInfos(self, name, parent, typeinfos):
  1108     def ExtractTypeInfos(self, name, parent, typeinfos):
  1068         if isinstance(typeinfos, (StringType, UnicodeType)):
  1109         if isinstance(typeinfos, (StringType, UnicodeType)):
  1069             namespace, name = DecomposeQualifiedName(typeinfos)
  1110             namespace, type_name = DecomposeQualifiedName(typeinfos)
  1070             infos = self.GetQualifiedNameInfos(name, namespace)
  1111             if namespace == self.TargetNamespace and name != "base":
       
  1112                 self.AddToLookupClass(name, parent, type_name)
       
  1113             infos = self.GetQualifiedNameInfos(type_name, namespace)
  1071             if infos["type"] == COMPLEXTYPE:
  1114             if infos["type"] == COMPLEXTYPE:
  1072                 name, parent = self.SplitQualifiedName(name, namespace)
  1115                 type_name, parent = self.SplitQualifiedName(type_name, namespace)
  1073                 result = self.CreateClass(name, parent, infos)
  1116                 result = self.CreateClass(type_name, parent, infos)
  1074                 if result is not None and not isinstance(result, (UnicodeType, StringType)):
  1117                 if result is not None and not isinstance(result, (UnicodeType, StringType)):
  1075                     self.Namespaces[self.TargetNamespace][result["name"]] = result
  1118                     self.Namespaces[self.TargetNamespace][result["name"]] = result
  1076                 return result
  1119                 return result
  1077             elif infos["type"] == ELEMENT and infos["elmt_type"]["type"] == COMPLEXTYPE:
  1120             elif infos["type"] == ELEMENT and infos["elmt_type"]["type"] == COMPLEXTYPE:
  1078                 name, parent = self.SplitQualifiedName(name, namespace)
  1121                 type_name, parent = self.SplitQualifiedName(type_name, namespace)
  1079                 result = self.CreateClass(name, parent, infos["elmt_type"])
  1122                 result = self.CreateClass(type_name, parent, infos["elmt_type"])
  1080                 if result is not None and not isinstance(result, (UnicodeType, StringType)):
  1123                 if result is not None and not isinstance(result, (UnicodeType, StringType)):
  1081                     self.Namespaces[self.TargetNamespace][result["name"]] = result
  1124                     self.Namespaces[self.TargetNamespace][result["name"]] = result
  1082                 return result
  1125                 return result
  1083             else:
  1126             else:
  1084                 return infos
  1127                 return infos
  1139         
  1182         
  1140         # If base classes haven't been generated
  1183         # If base classes haven't been generated
  1141         bases = []
  1184         bases = []
  1142         base_infos = classinfos.get("base", None)
  1185         base_infos = classinfos.get("base", None)
  1143         if base_infos is not None:
  1186         if base_infos is not None:
       
  1187             namespace, base_name = DecomposeQualifiedName(base_infos)
       
  1188             if namespace == self.TargetNamespace:
       
  1189                 self.AddEquivalentClass(name, base_name)
  1144             result = self.ExtractTypeInfos("base", name, base_infos)
  1190             result = self.ExtractTypeInfos("base", name, base_infos)
  1145             if result is None:
  1191             if result is None:
  1146                 namespace, base_name = DecomposeQualifiedName(base_infos)                
  1192                 namespace, base_name = DecomposeQualifiedName(base_infos)
  1147                 if self.AlreadyComputed.get(base_name, False):
  1193                 if self.AlreadyComputed.get(base_name, False):
  1148                     self.ComputeAfter.append((name, parent, classinfos))
  1194                     self.ComputeAfter.append((name, parent, classinfos))
  1149                     if self.TargetNamespace is not None:
  1195                     if self.TargetNamespace is not None:
  1150                         return "%s:%s" % (self.TargetNamespace, classname)
  1196                         return "%s:%s" % (self.TargetNamespace, classname)
  1151                     else:
  1197                     else:
  1162                 else:
  1208                 else:
  1163                     classinfos["base"] = self.ComputedClasses.get(result["name"], None)
  1209                     classinfos["base"] = self.ComputedClasses.get(result["name"], None)
  1164                 if classinfos["base"] is None:
  1210                 if classinfos["base"] is None:
  1165                     raise ValueError("No class found for base type")
  1211                     raise ValueError("No class found for base type")
  1166                 bases.append(classinfos["base"])
  1212                 bases.append(classinfos["base"])
  1167         bases.append(object)
  1213         bases.append(DefaultElementClass)
  1168         bases = tuple(bases)
  1214         bases = tuple(bases)
  1169         classmembers = {"__doc__": classinfos.get("doc", ""), "IsBaseClass": baseclass}
  1215         classmembers = {"__doc__": classinfos.get("doc", ""), "IsBaseClass": baseclass}
  1170         
  1216         
  1171         self.AlreadyComputed[classname] = True
  1217         self.AlreadyComputed[classname] = True
  1172         
  1218         
  1175             if infos is not None:                    
  1221             if infos is not None:                    
  1176                 if infos["type"] != SIMPLETYPE:
  1222                 if infos["type"] != SIMPLETYPE:
  1177                     raise ValueError("\"%s\" type is not a simple type!" % attribute["attr_type"])
  1223                     raise ValueError("\"%s\" type is not a simple type!" % attribute["attr_type"])
  1178                 attrname = attribute["name"]
  1224                 attrname = attribute["name"]
  1179                 if attribute["use"] == "optional":
  1225                 if attribute["use"] == "optional":
  1180                     classmembers[attrname] = None
       
  1181                     classmembers["add%s"%attrname] = generateAddMethod(attrname, self, attribute)
  1226                     classmembers["add%s"%attrname] = generateAddMethod(attrname, self, attribute)
  1182                     classmembers["delete%s"%attrname] = generateDeleteMethod(attrname)
  1227                     classmembers["delete%s"%attrname] = generateDeleteMethod(attrname)
  1183                 else:
       
  1184                     classmembers[attrname] = infos["initial"]()
       
  1185                 classmembers["set%s"%attrname] = generateSetMethod(attrname)
  1228                 classmembers["set%s"%attrname] = generateSetMethod(attrname)
  1186                 classmembers["get%s"%attrname] = generateGetMethod(attrname)
  1229                 classmembers["get%s"%attrname] = generateGetMethod(attrname)
  1187             else:
  1230             else:
  1188                 raise ValueError("\"%s\" type unrecognized!" % attribute["attr_type"])
  1231                 raise ValueError("\"%s\" type unrecognized!" % attribute["attr_type"])
  1189             attribute["attr_type"] = infos
  1232             attribute["attr_type"] = infos
  1210                 else:
  1253                 else:
  1211                     infos = self.ExtractTypeInfos(element["name"], name, element["elmt_type"])
  1254                     infos = self.ExtractTypeInfos(element["name"], name, element["elmt_type"])
  1212             if infos is not None:
  1255             if infos is not None:
  1213                 element["elmt_type"] = infos
  1256                 element["elmt_type"] = infos
  1214             if element["maxOccurs"] == "unbounded" or element["maxOccurs"] > 1:
  1257             if element["maxOccurs"] == "unbounded" or element["maxOccurs"] > 1:
  1215                 classmembers[elmtname] = []
       
  1216                 classmembers["append%s" % elmtname] = generateAppendMethod(elmtname, element["maxOccurs"], self, element)
  1258                 classmembers["append%s" % elmtname] = generateAppendMethod(elmtname, element["maxOccurs"], self, element)
  1217                 classmembers["insert%s" % elmtname] = generateInsertMethod(elmtname, element["maxOccurs"], self, element)
  1259                 classmembers["insert%s" % elmtname] = generateInsertMethod(elmtname, element["maxOccurs"], self, element)
  1218                 classmembers["remove%s" % elmtname] = generateRemoveMethod(elmtname, element["minOccurs"])
  1260                 classmembers["remove%s" % elmtname] = generateRemoveMethod(elmtname, element["minOccurs"])
  1219                 classmembers["count%s" % elmtname] = generateCountMethod(elmtname)
  1261                 classmembers["count%s" % elmtname] = generateCountMethod(elmtname)
  1220             else:
  1262             else:
  1221                 if element["minOccurs"] == 0:
  1263                 if element["minOccurs"] == 0:
  1222                     classmembers[elmtname] = None
       
  1223                     classmembers["add%s" % elmtname] = generateAddMethod(elmtname, self, element)
  1264                     classmembers["add%s" % elmtname] = generateAddMethod(elmtname, self, element)
  1224                     classmembers["delete%s" % elmtname] = generateDeleteMethod(elmtname)
  1265                     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)
  1266             classmembers["set%s" % elmtname] = generateSetMethod(elmtname)
  1230             classmembers["get%s" % elmtname] = generateGetMethod(elmtname)
  1267             classmembers["get%s" % elmtname] = generateGetMethod(elmtname)
  1231             
  1268             
  1232         classmembers["__init__"] = generateInitMethod(self, classinfos)
  1269         classmembers["_init"] = generateInitMethod(self, classinfos)
  1233         classmembers["getStructure"] = generateStructureMethod(classinfos)
  1270         classmembers["getStructure"] = generateStructureMethod(classinfos)
  1234         classmembers["loadXMLTree"] = generateLoadXMLTree(self, classinfos)
  1271         classmembers["loadXMLTree"] = generateLoadXMLTree(self, classinfos)
  1235         classmembers["generateXMLText"] = generateGenerateXMLText(self, classinfos)
  1272         classmembers["generateXMLText"] = generateGenerateXMLText(self, classinfos)
  1236         classmembers["getElementAttributes"] = generateGetElementAttributes(self, classinfos)
  1273         classmembers["getElementAttributes"] = generateGetElementAttributes(self, classinfos)
  1237         classmembers["getElementInfos"] = generateGetElementInfos(self, classinfos)
  1274         classmembers["getElementInfos"] = generateGetElementInfos(self, classinfos)
  1239         classmembers["singleLineAttributes"] = True
  1276         classmembers["singleLineAttributes"] = True
  1240         classmembers["compatibility"] = lambda x, y: None
  1277         classmembers["compatibility"] = lambda x, y: None
  1241         classmembers["extraAttrs"] = {}
  1278         classmembers["extraAttrs"] = {}
  1242         
  1279         
  1243         class_definition = classobj(str(classname), bases, classmembers)
  1280         class_definition = classobj(str(classname), bases, classmembers)
       
  1281         setattr(class_definition, "__getattr__", generateGetattrMethod(self, class_definition, classinfos))
  1244         setattr(class_definition, "__setattr__", generateSetattrMethod(self, class_definition, classinfos))
  1282         setattr(class_definition, "__setattr__", generateSetattrMethod(self, class_definition, classinfos))
  1245         class_infos = {"type": COMPILEDCOMPLEXTYPE,
  1283         class_infos = {"type": COMPILEDCOMPLEXTYPE,
  1246                        "name": classname,
  1284                        "name": classname,
  1247                        "check": generateClassCheckFunction(class_definition),
  1285                        "check": generateClassCheckFunction(class_definition),
  1248                        "initial": generateClassCreateFunction(class_definition),
  1286                        "initial": generateClassCreateFunction(class_definition),
  1253             self.ComputedClasses[self.FileName][classname] = class_definition
  1291             self.ComputedClasses[self.FileName][classname] = class_definition
  1254         else:
  1292         else:
  1255             self.ComputedClasses[classname] = class_definition
  1293             self.ComputedClasses[classname] = class_definition
  1256         self.ComputedClassesInfos[classname] = class_infos
  1294         self.ComputedClassesInfos[classname] = class_infos
  1257         
  1295         
       
  1296         self.AddToLookupClass(name, parent, class_definition)
       
  1297         self.AddToLookupClass(classname, None, class_definition)
       
  1298             
  1258         return class_infos
  1299         return class_infos
  1259 
  1300 
  1260     """
  1301     """
  1261     Methods that print the classes generated
  1302     Methods that print the classes generated
  1262     """
  1303     """
  1304         instance = class_definition()
  1345         instance = class_definition()
  1305         instance.loadXMLTree(node)
  1346         instance.loadXMLTree(node)
  1306         return instance
  1347         return instance
  1307     return classExtractfunction
  1348     return classExtractfunction
  1308 
  1349 
       
  1350 def generateGetattrMethod(factory, class_definition, classinfos):
       
  1351     attributes = dict([(attr["name"], attr) for attr in classinfos["attributes"] if attr["use"] != "prohibited"])
       
  1352     optional_attributes = dict([(attr["name"], True) for attr in classinfos["attributes"] if attr["use"] == "optional"])
       
  1353     elements = dict([(element["name"], element) for element in classinfos["elements"]])
       
  1354     
       
  1355     def getattrMethod(self, name):
       
  1356         if attributes.has_key(name):
       
  1357             attribute_infos = attributes[name]
       
  1358             attribute_infos["attr_type"] = FindTypeInfos(factory, attribute_infos["attr_type"])
       
  1359             value = self.get(name)
       
  1360             if value is not None:
       
  1361                 return attribute_infos["attr_type"]["extract"](value, extract=False)
       
  1362             elif attribute_infos.has_key("fixed"):
       
  1363                 return attribute_infos["attr_type"]["extract"](attribute_infos["fixed"], extract=False)
       
  1364             return attribute_infos["attr_type"]["initial"]()
       
  1365         
       
  1366         elif elements.has_key(name):
       
  1367             element_infos = elements[name]
       
  1368             element_infos["elmt_type"] = FindTypeInfos(factory, element_infos["elmt_type"])
       
  1369             if name == "content":
       
  1370                 content = self.xpath(element_infos["elmt_type"]["choices_xpath"](), namespaces=factory.NSMAP)
       
  1371                 if element_infos["maxOccurs"] == "unbounded" or element_infos["maxOccurs"] > 1:
       
  1372                     return content
       
  1373                 elif len(content) > 0:
       
  1374                     return content[0]
       
  1375                 return None 
       
  1376             else:
       
  1377                 element_name = factory.etreeNamespaceFormat % name
       
  1378                 if element_infos["maxOccurs"] == "unbounded" or element_infos["maxOccurs"] > 1:
       
  1379                     return self.findall(element_name)
       
  1380                 else:
       
  1381                     return self.find(element_name)
       
  1382             
       
  1383         elif classinfos.has_key("base"):
       
  1384             return classinfos["base"].__getattr__(self, name)
       
  1385         
       
  1386         return DefaultElementClass.__getattribute__(self, name)
       
  1387     
       
  1388     return getattrMethod
       
  1389 
  1309 """
  1390 """
  1310 Method that generate the method for loading an xml tree by following the
  1391 Method that generate the method for loading an xml tree by following the
  1311 attributes list defined
  1392 attributes list defined
  1312 """
  1393 """
  1313 def generateSetattrMethod(factory, class_definition, classinfos):
  1394 def generateSetattrMethod(factory, class_definition, classinfos):
  1314     attributes = dict([(attr["name"], attr) for attr in classinfos["attributes"] if attr["use"] != "prohibited"])
  1395     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"])
  1396     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"]])
  1397     elements = OrderedDict([(element["name"], element) for element in classinfos["elements"]])
  1317     
  1398     
  1318     def setattrMethod(self, name, value):
  1399     def setattrMethod(self, name, value):
  1319         if attributes.has_key(name):
  1400         if attributes.has_key(name):
  1320             attributes[name]["attr_type"] = FindTypeInfos(factory, attributes[name]["attr_type"])
  1401             attribute_infos = attributes[name]
  1321             if value is None:
  1402             attribute_infos["attr_type"] = FindTypeInfos(factory, attribute_infos["attr_type"])
  1322                 if optional_attributes.get(name, False):
  1403             if optional_attributes.get(name, False):
  1323                     return object.__setattr__(self, name, None)
  1404                 default = attribute_infos.get("default", None)
  1324                 else:
  1405                 if value is None or value == default:
  1325                     raise ValueError("Attribute '%s' isn't optional." % name)
  1406                     self.attrib.pop(name)
  1326             elif attributes[name].has_key("fixed") and value != attributes[name]["fixed"]:
  1407                     return
  1327                 raise ValueError, "Value of attribute '%s' can only be '%s'."%(name, str(attributes[name]["fixed"]))
  1408             elif attribute_infos.has_key("fixed"):
  1328             elif attributes[name]["attr_type"]["check"](value):
  1409                 return
  1329                 return object.__setattr__(self, name, value)
  1410             return self.set(name, attribute_infos["attr_type"]["generate"](value))
  1330             else:
  1411         
  1331                 raise ValueError("Invalid value for attribute '%s'." % (name))
       
  1332         elif elements.has_key(name):
  1412         elif elements.has_key(name):
  1333             if CheckElementValue(factory, name, elements[name], value):
  1413             element_infos = elements[name]
  1334                 return object.__setattr__(self, name, value)
  1414             element_infos["elmt_type"] = FindTypeInfos(factory, element_infos["elmt_type"])
  1335             else:
  1415             element_xpath = ("%s:%s" % (factory.TargetNamespace, name)
  1336                 raise ValueError("Invalid value for attribute '%s'." % (name))
  1416                              if name != "content"
       
  1417                              else elements["content"]["elmt_type"]["choices_xpath"]())
       
  1418             
       
  1419             for element in self.xpath(element_xpath, namespaces=factory.NSMAP):
       
  1420                 self.remove(element)
       
  1421             
       
  1422             if value is not None:
       
  1423                 previous_elements_xpath = "|".join(map(
       
  1424                     lambda x: "%s:%s" % (factory.TargetNamespace, x)
       
  1425                               if x != "content"
       
  1426                               else elements["content"]["elmt_type"]["choices_xpath"](),
       
  1427                     elements.keys()[elements.keys().index(name)]))
       
  1428                 
       
  1429                 insertion_point = len(self.xpath(previous_elements_xpath, namespaces=factory.NSMAP))
       
  1430                 
       
  1431                 if not isinstance(value, ListType):
       
  1432                     value = [value]
       
  1433                     
       
  1434                 for element in reversed(value):
       
  1435                     self.insert(insertion_point, element)
       
  1436         
  1337         elif classinfos.has_key("base"):
  1437         elif classinfos.has_key("base"):
  1338             return classinfos["base"].__setattr__(self, name, value)
  1438             return classinfos["base"].__setattr__(self, name, value)
       
  1439         
  1339         elif class_definition.__dict__.has_key(name):
  1440         elif class_definition.__dict__.has_key(name):
  1340             return object.__setattr__(self, name, value)
  1441             return DefaultElementClass.__setattr__(self, name, value)
       
  1442         
  1341         else:
  1443         else:
  1342             raise AttributeError("'%s' can't have an attribute '%s'." % (self.__class__.__name__, name))
  1444             raise AttributeError("'%s' can't have an attribute '%s'." % (self.__class__.__name__, name))
  1343         
  1445         
  1344     return setattrMethod
  1446     return setattrMethod
  1345 
  1447 
  1723 """
  1825 """
  1724 def generateInitMethod(factory, classinfos):
  1826 def generateInitMethod(factory, classinfos):
  1725     def initMethod(self):
  1827     def initMethod(self):
  1726         self.extraAttrs = {}
  1828         self.extraAttrs = {}
  1727         if classinfos.has_key("base"):
  1829         if classinfos.has_key("base"):
  1728             classinfos["base"].__init__(self)
  1830             classinfos["base"]._init(self)
  1729         for attribute in classinfos["attributes"]:
  1831         for attribute in classinfos["attributes"]:
  1730             attribute["attr_type"] = FindTypeInfos(factory, attribute["attr_type"])
  1832             attribute["attr_type"] = FindTypeInfos(factory, attribute["attr_type"])
  1731             if attribute["use"] == "required":
  1833             if attribute["use"] == "required" and self.get(attribute["name"]) is None:
  1732                 setattr(self, attribute["name"], attribute["attr_type"]["initial"]())
  1834                 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"]:
  1835         for element in classinfos["elements"]:
  1739             setattr(self, element["name"], GetElementInitialValue(factory, element))
  1836             if element["name"] != "content":
       
  1837                 element_name = (
       
  1838                     etree.QName(factory.NSMAP["xhtml"], "p")
       
  1839                     if element["type"] == ANY
       
  1840                     else factory.etreeNamespaceFormat % element["name"])
       
  1841                 if self.find(element_name) is None:
       
  1842                     initial = GetElementInitialValue(factory, element)
       
  1843                     if initial is not None:
       
  1844                         map(self.append, initial)
  1740     return initMethod
  1845     return initMethod
  1741 
  1846 
  1742 def generateSetMethod(attr):
  1847 def generateSetMethod(attr):
  1743     def setMethod(self, value):
  1848     def setMethod(self, value):
  1744         setattr(self, attr, value)
  1849         setattr(self, attr, value)
  1759             infos["elmt_type"] = FindTypeInfos(factory, infos["elmt_type"])
  1864             infos["elmt_type"] = FindTypeInfos(factory, infos["elmt_type"])
  1760             initial = infos["elmt_type"]["initial"]
  1865             initial = infos["elmt_type"]["initial"]
  1761             extract = infos["elmt_type"]["extract"]
  1866             extract = infos["elmt_type"]["extract"]
  1762         else:
  1867         else:
  1763             raise ValueError("Invalid class attribute!")
  1868             raise ValueError("Invalid class attribute!")
  1764         if infos.has_key("default"):
  1869         if not infos.has_key("default"):
  1765             setattr(self, attr, extract(infos["default"], False))
       
  1766         else:
       
  1767             setattr(self, attr, initial())
  1870             setattr(self, attr, initial())
  1768     return addMethod
  1871     return addMethod
  1769 
  1872 
  1770 def generateDeleteMethod(attr):
  1873 def generateDeleteMethod(attr):
  1771     def deleteMethod(self):
  1874     def deleteMethod(self):
  1775 def generateAppendMethod(attr, maxOccurs, factory, infos):
  1878 def generateAppendMethod(attr, maxOccurs, factory, infos):
  1776     def appendMethod(self, value):
  1879     def appendMethod(self, value):
  1777         infos["elmt_type"] = FindTypeInfos(factory, infos["elmt_type"])
  1880         infos["elmt_type"] = FindTypeInfos(factory, infos["elmt_type"])
  1778         attr_list = getattr(self, attr)
  1881         attr_list = getattr(self, attr)
  1779         if maxOccurs == "unbounded" or len(attr_list) < maxOccurs:
  1882         if maxOccurs == "unbounded" or len(attr_list) < maxOccurs:
  1780             if infos["elmt_type"]["check"](value):
  1883             if len(attr_list) == 0:
  1781                 attr_list.append(value)
  1884                 setattr(self, attr, [value])
  1782             else:
  1885             else:
  1783                 raise ValueError("\"%s\" value isn't valid!" % attr)
  1886                 attr_list[-1].addnext(value)
  1784         else:
  1887         else:
  1785             raise ValueError("There can't be more than %d values in \"%s\"!" % (maxOccurs, attr))
  1888             raise ValueError("There can't be more than %d values in \"%s\"!" % (maxOccurs, attr))
  1786     return appendMethod
  1889     return appendMethod
  1787 
  1890 
  1788 def generateInsertMethod(attr, maxOccurs, factory, infos):
  1891 def generateInsertMethod(attr, maxOccurs, factory, infos):
  1789     def insertMethod(self, index, value):
  1892     def insertMethod(self, index, value):
  1790         infos["elmt_type"] = FindTypeInfos(factory, infos["elmt_type"])
  1893         infos["elmt_type"] = FindTypeInfos(factory, infos["elmt_type"])
  1791         attr_list = getattr(self, attr)
  1894         attr_list = getattr(self, attr)
  1792         if maxOccurs == "unbounded" or len(attr_list) < maxOccurs:
  1895         if maxOccurs == "unbounded" or len(attr_list) < maxOccurs:
  1793             if infos["elmt_type"]["check"](value):
  1896             if len(attr_list) == 0:
  1794                 attr_list.insert(index, value)
  1897                 setattr(self, attr, [value])
       
  1898             elif index == 0:
       
  1899                 attr_list[0].addprevious(value)
  1795             else:
  1900             else:
  1796                 raise ValueError("\"%s\" value isn't valid!" % attr)
  1901                 attr_list[min(index - 1, len(attr_list) - 1)].addnext(value)
  1797         else:
  1902         else:
  1798             raise ValueError("There can't be more than %d values in \"%s\"!" % (maxOccurs, attr))
  1903             raise ValueError("There can't be more than %d values in \"%s\"!" % (maxOccurs, attr))
  1799     return insertMethod
  1904     return insertMethod
  1800 
  1905 
  1801 def generateGetChoicesMethod(choice_types):
  1906 def generateGetChoicesMethod(choice_types):
  1803         return [choice["name"] for choice in choice_types]
  1908         return [choice["name"] for choice in choice_types]
  1804     return getChoicesMethod
  1909     return getChoicesMethod
  1805 
  1910 
  1806 def generateSetChoiceByTypeMethod(factory, choice_types):
  1911 def generateSetChoiceByTypeMethod(factory, choice_types):
  1807     choices = dict([(choice["name"], choice) for choice in choice_types])
  1912     choices = dict([(choice["name"], choice) for choice in choice_types])
  1808     def setChoiceMethod(self, type):
  1913     def setChoiceMethod(self, content_type):
  1809         if not choices.has_key(type):
  1914         if not choices.has_key(content_type):
  1810             raise ValueError("Unknown \"%s\" choice type for \"content\"!" % type)
  1915             raise ValueError("Unknown \"%s\" choice type for \"content\"!" % content_type)
  1811         choices[type]["elmt_type"] = FindTypeInfos(factory, choices[type]["elmt_type"])
  1916         choices[content_type]["elmt_type"] = FindTypeInfos(factory, choices[content_type]["elmt_type"])
  1812         new_element = choices[type]["elmt_type"]["initial"]()
  1917         new_content = choices[content_type]["elmt_type"]["initial"]()
  1813         self.content = {"name": type, "value": new_element}
  1918         self.content = new_content
  1814         return new_element
  1919         return new_content
  1815     return setChoiceMethod
  1920     return setChoiceMethod
  1816 
  1921 
  1817 def generateAppendChoiceByTypeMethod(maxOccurs, factory, choice_types):
  1922 def generateAppendChoiceByTypeMethod(maxOccurs, factory, choice_types):
  1818     choices = dict([(choice["name"], choice) for choice in choice_types])
  1923     choices = dict([(choice["name"], choice) for choice in choice_types])
  1819     def appendChoiceMethod(self, type):
  1924     def appendChoiceMethod(self, content_type):
  1820         if not choices.has_key(type):
  1925         if not choices.has_key(content_type):
  1821             raise ValueError("Unknown \"%s\" choice type for \"content\"!" % type)
  1926             raise ValueError("Unknown \"%s\" choice type for \"content\"!" % content_type)
  1822         choices[type]["elmt_type"] = FindTypeInfos(factory, choices[type]["elmt_type"])
  1927         choices[content_type]["elmt_type"] = FindTypeInfos(factory, choices[content_type]["elmt_type"])
  1823         if maxOccurs == "unbounded" or len(self.content) < maxOccurs:
  1928         if maxOccurs == "unbounded" or len(self.content) < maxOccurs:
  1824             new_element = choices[type]["elmt_type"]["initial"]()
  1929             new_element = choices[content_type]["elmt_type"]["initial"]()
  1825             self.content.append({"name": type, "value": new_element})
  1930             self.appendcontent(new_element)
  1826             return new_element
  1931             return new_element
  1827         else:
  1932         else:
  1828             raise ValueError("There can't be more than %d values in \"content\"!" % maxOccurs)
  1933             raise ValueError("There can't be more than %d values in \"content\"!" % maxOccurs)
  1829     return appendChoiceMethod
  1934     return appendChoiceMethod
  1830 
  1935 
  1831 def generateInsertChoiceByTypeMethod(maxOccurs, factory, choice_types):
  1936 def generateInsertChoiceByTypeMethod(maxOccurs, factory, choice_types):
  1832     choices = dict([(choice["name"], choice) for choice in choice_types])
  1937     choices = dict([(choice["name"], choice) for choice in choice_types])
  1833     def insertChoiceMethod(self, index, type):
  1938     def insertChoiceMethod(self, index, content_type):
  1834         if not choices.has_key(type):
  1939         if not choices.has_key(content_type):
  1835             raise ValueError("Unknown \"%s\" choice type for \"content\"!" % type)
  1940             raise ValueError("Unknown \"%s\" choice type for \"content\"!" % content_type)
  1836         choices[type]["elmt_type"] = FindTypeInfos(factory, choices[type]["elmt_type"])
  1941         choices[type]["elmt_type"] = FindTypeInfos(factory, choices[content_type]["elmt_type"])
  1837         if maxOccurs == "unbounded" or len(self.content) < maxOccurs:
  1942         if maxOccurs == "unbounded" or len(self.content) < maxOccurs:
  1838             new_element = choices[type]["elmt_type"]["initial"]()
  1943             new_element = choices[content_type]["elmt_type"]["initial"]()
  1839             self.content.insert(index, {"name" : type, "value" : new_element})
  1944             self.insertcontent(index, new_element)
  1840             return new_element
  1945             return new_element
  1841         else:
  1946         else:
  1842             raise ValueError("There can't be more than %d values in \"content\"!" % maxOccurs)
  1947             raise ValueError("There can't be more than %d values in \"content\"!" % maxOccurs)
  1843     return insertChoiceMethod
  1948     return insertChoiceMethod
  1844 
  1949 
  1845 def generateRemoveMethod(attr, minOccurs):
  1950 def generateRemoveMethod(attr, minOccurs):
  1846     def removeMethod(self, index):
  1951     def removeMethod(self, index):
  1847         attr_list = getattr(self, attr)
  1952         attr_list = getattr(self, attr)
  1848         if len(attr_list) > minOccurs:
  1953         if len(attr_list) > minOccurs:
  1849             getattr(self, attr).pop(index)
  1954             self.remove(attr_list[index])
  1850         else:
  1955         else:
  1851             raise ValueError("There can't be less than %d values in \"%s\"!" % (minOccurs, attr))
  1956             raise ValueError("There can't be less than %d values in \"%s\"!" % (minOccurs, attr))
  1852     return removeMethod
  1957     return removeMethod
  1853 
  1958 
  1854 def generateCountMethod(attr):
  1959 def generateCountMethod(attr):
  1855     def countMethod(self):
  1960     def countMethod(self):
  1856         return len(getattr(self, attr))
  1961         return len(getattr(self, attr))
  1857     return countMethod
  1962     return countMethod
  1858 
  1963 
  1859 """
  1964 """
  1860 This function generate the classes from a class factory
  1965 This function generate a xml parser from a class factory
  1861 """
  1966 """
  1862 def GenerateClasses(factory):
  1967 
       
  1968 class DefaultElementClass(etree.ElementBase):
       
  1969     toto = True
       
  1970     
       
  1971     def getLocalTag(self):
       
  1972         return etree.QName(self.tag).localname
       
  1973         
       
  1974     def tostring(self):
       
  1975         return etree.tostring(self, pretty_print=True)
       
  1976 
       
  1977 class XMLElementClassLookUp(etree.PythonElementClassLookup):
       
  1978     
       
  1979     def __init__(self, classes, class_equivalence, *args, **kwargs):
       
  1980         etree.PythonElementClassLookup.__init__(self, *args, **kwargs)
       
  1981         self.LookUpClasses = classes
       
  1982         self.ClassEquivalence = class_equivalence
       
  1983     
       
  1984     def GetElementClass(self, element_tag, parent_tag=None, default=DefaultElementClass):
       
  1985         element_class = self.LookUpClasses.get(element_tag, (default, None))
       
  1986         if not isinstance(element_class, DictType):
       
  1987             if isinstance(element_class[0], (StringType, UnicodeType)):
       
  1988                 return self.GetElementClass(element_class[0], default=default)
       
  1989             return element_class[0]
       
  1990         
       
  1991         element_with_parent_class = element_class.get(parent_tag, default)
       
  1992         if isinstance(element_with_parent_class, (StringType, UnicodeType)):
       
  1993             return self.GetElementClass(element_with_parent_class, default=default)
       
  1994         elif element_with_parent_class == DefaultElementClass:
       
  1995             for equivalent_parent in self.ClassEquivalence.get(parent_tag, {}).keys():
       
  1996                 return self.GetElementClass(element_tag, equivalent_parent, default)
       
  1997         return element_with_parent_class
       
  1998         
       
  1999     def lookup(self, document, element):
       
  2000         parent = element.getparent()
       
  2001         return self.GetElementClass(element.tag, 
       
  2002             parent.tag if parent is not None else None)
       
  2003 
       
  2004 class XMLClassParser(etree.XMLParser):
       
  2005 
       
  2006     def __init__(self, namespaces, default_namespace_format, base_class, *args, **kwargs):
       
  2007         etree.XMLParser.__init__(self, *args, **kwargs)
       
  2008         self.DefaultNamespaceFormat = default_namespace_format
       
  2009         self.NSMAP = namespaces
       
  2010         targetNamespace = etree.QName(default_namespace_format % "d").namespace
       
  2011         if targetNamespace is not None:
       
  2012             self.RootNSMAP = {
       
  2013                 name if targetNamespace != uri else None: uri
       
  2014                 for name, uri in namespaces.iteritems()}
       
  2015         else:
       
  2016             self.RootNSMAP = namespaces
       
  2017         self.BaseClass = base_class
       
  2018     
       
  2019     def set_element_class_lookup(self, class_lookup):
       
  2020         etree.XMLParser.set_element_class_lookup(self, class_lookup)
       
  2021         self.ClassLookup = class_lookup
       
  2022     
       
  2023     def CreateRoot(self):
       
  2024         if self.BaseClass is not None:
       
  2025             return self.makeelement(
       
  2026                 self.DefaultNamespaceFormat % self.BaseClass[0],
       
  2027                 nsmap=self.RootNSMAP)
       
  2028         return None
       
  2029     
       
  2030     def GetElementClass(self, element_tag, parent_tag=None):
       
  2031         return self.ClassLookup.GetElementClass(
       
  2032             self.DefaultNamespaceFormat % element_tag, 
       
  2033             self.DefaultNamespaceFormat % parent_tag 
       
  2034             if parent_tag is not None else parent_tag, 
       
  2035             None)
       
  2036     
       
  2037     def CreateElement(self, element_tag, parent_tag=None):
       
  2038         new_element = self.GetElementClass(element_tag, parent_tag)()
       
  2039         DefaultElementClass.__setattr__(new_element, "tag", self.DefaultNamespaceFormat % element_tag)
       
  2040         return new_element
       
  2041     
       
  2042 def GenerateParser(factory, xsdstring):
  1863     ComputedClasses = factory.CreateClasses()
  2043     ComputedClasses = factory.CreateClasses()
  1864     if factory.FileName is not None and len(ComputedClasses) == 1:
  2044     if factory.FileName is not None and len(ComputedClasses) == 1:
  1865         UpdateXMLClassGlobals(ComputedClasses[factory.FileName])
  2045         ComputedClasses = ComputedClasses[factory.FileName]
  1866         return ComputedClasses[factory.FileName]
  2046         BaseClass = [(name, XSDclass) for name, XSDclass in ComputedClasses.items() if XSDclass.IsBaseClass]
  1867     else:
  2047     else:
  1868         UpdateXMLClassGlobals(ComputedClasses)
  2048         BaseClass = []
  1869         return ComputedClasses
  2049     UpdateXMLClassGlobals(ComputedClasses)
       
  2050     
       
  2051     parser = XMLClassParser(
       
  2052         factory.NSMAP,
       
  2053         factory.etreeNamespaceFormat,
       
  2054         BaseClass[0] if len(BaseClass) == 1 else None,
       
  2055         schema = etree.XMLSchema(etree.fromstring(xsdstring)),
       
  2056         strip_cdata = False, remove_blank_text=True)
       
  2057     class_lookup = XMLElementClassLookUp(factory.ComputedClassesLookUp, factory.EquivalentClassesParent)
       
  2058     parser.set_element_class_lookup(class_lookup)
       
  2059     return parser
  1870 
  2060 
  1871 def UpdateXMLClassGlobals(classes):
  2061 def UpdateXMLClassGlobals(classes):
  1872     globals().update(classes)
  2062     globals().update(classes)
       
  2063