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 #------------------------------------------------------------------------------- |
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() |
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"): |
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, xsd_schema, *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 self.XSDSchema = xsd_schema |
|
1746 |
|
1747 def set_element_class_lookup(self, class_lookup): |
|
1748 etree.XMLParser.set_element_class_lookup(self, class_lookup) |
|
1749 self.ClassLookup = class_lookup |
|
1750 |
|
1751 def LoadXMLString(self, xml_string): |
|
1752 tree = etree.fromstring(xml_string, self) |
|
1753 if not self.XSDSchema.validate(tree): |
|
1754 error = self.XSDSchema.error_log.last_error |
|
1755 return tree, (error.line, error.message) |
|
1756 return tree, None |
|
1757 |
|
1758 def Dumps(self, xml_obj): |
|
1759 return etree.tostring(xml_obj) |
|
1760 |
|
1761 def Loads(self, xml_string): |
|
1762 return etree.fromstring(xml_string, self) |
|
1763 |
|
1764 def CreateRoot(self): |
|
1765 if self.BaseClass is not None: |
|
1766 root = self.makeelement( |
|
1767 self.DefaultNamespaceFormat % self.BaseClass[0], |
|
1768 nsmap=self.RootNSMAP) |
|
1769 root._init_() |
|
1770 return root |
|
1771 return None |
|
1772 |
|
1773 def GetElementClass(self, element_tag, parent_tag=None): |
|
1774 return self.ClassLookup.GetElementClass( |
|
1775 self.DefaultNamespaceFormat % element_tag, |
|
1776 self.DefaultNamespaceFormat % parent_tag |
|
1777 if parent_tag is not None else parent_tag, |
|
1778 None) |
|
1779 |
|
1780 def CreateElement(self, element_tag, parent_tag=None, class_idx=None): |
|
1781 element_class = self.GetElementClass(element_tag, parent_tag) |
|
1782 if isinstance(element_class, ListType): |
|
1783 if class_idx is not None and class_idx < len(element_class): |
|
1784 new_element = element_class[class_idx]() |
|
1785 else: |
|
1786 raise ValueError, "No corresponding class found!" |
|
1787 else: |
|
1788 new_element = element_class() |
|
1789 DefaultElementClass.__setattr__(new_element, "tag", self.DefaultNamespaceFormat % element_tag) |
|
1790 new_element._init_() |
|
1791 return new_element |
|
1792 |
|
1793 def GenerateParser(factory, xsdstring): |
1863 ComputedClasses = factory.CreateClasses() |
1794 ComputedClasses = factory.CreateClasses() |
1864 if factory.FileName is not None and len(ComputedClasses) == 1: |
1795 |
1865 UpdateXMLClassGlobals(ComputedClasses[factory.FileName]) |
1796 if factory.FileName is not None: |
1866 return ComputedClasses[factory.FileName] |
1797 ComputedClasses = ComputedClasses[factory.FileName] |
1867 else: |
1798 BaseClass = [(name, XSDclass) for name, XSDclass in ComputedClasses.items() if XSDclass.IsBaseClass] |
1868 UpdateXMLClassGlobals(ComputedClasses) |
1799 |
1869 return ComputedClasses |
1800 parser = XMLClassParser( |
1870 |
1801 factory.NSMAP, |
1871 def UpdateXMLClassGlobals(classes): |
1802 factory.etreeNamespaceFormat, |
1872 globals().update(classes) |
1803 BaseClass[0] if len(BaseClass) == 1 else None, |
|
1804 etree.XMLSchema(etree.fromstring(xsdstring)), |
|
1805 strip_cdata = False, remove_blank_text=True) |
|
1806 class_lookup = XMLElementClassLookUp(factory.ComputedClassesLookUp) |
|
1807 parser.set_element_class_lookup(class_lookup) |
|
1808 |
|
1809 return parser |
|
1810 |