xmlclass/xmlclass.py
changeset 1322 0a9227f743b3
parent 1315 ff14a66bbd12
child 1330 96b242e4c59d
equal deleted inserted replaced
1321:83f41ea00b97 1322:0a9227f743b3
   923     
   923     
   924     def AddEquivalentClass(self, name, base):
   924     def AddEquivalentClass(self, name, base):
   925         if name != base:
   925         if name != base:
   926             equivalences = self.EquivalentClassesParent.setdefault(self.etreeNamespaceFormat % base, {})
   926             equivalences = self.EquivalentClassesParent.setdefault(self.etreeNamespaceFormat % base, {})
   927             equivalences[self.etreeNamespaceFormat % name] = True
   927             equivalences[self.etreeNamespaceFormat % name] = True
   928         
   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     
   929     def AddToLookupClass(self, name, parent, typeinfos):
   943     def AddToLookupClass(self, name, parent, typeinfos):
   930         lookup_name = self.etreeNamespaceFormat % name
   944         lookup_name = self.etreeNamespaceFormat % name
   931         if isinstance(typeinfos, (StringType, UnicodeType)):
   945         if isinstance(typeinfos, (StringType, UnicodeType)):
   932             self.AddEquivalentClass(name, typeinfos)
   946             self.AddEquivalentClass(name, typeinfos)
   933             typeinfos = self.etreeNamespaceFormat % typeinfos
   947             typeinfos = self.etreeNamespaceFormat % typeinfos
   934         lookup_classes = self.ComputedClassesLookUp.get(lookup_name)
   948         lookup_classes = self.ComputedClassesLookUp.get(lookup_name)
   935         if lookup_classes is None:
   949         if lookup_classes is None:
   936             self.ComputedClassesLookUp[lookup_name] = (typeinfos, parent)
   950             self.ComputedClassesLookUp[lookup_name] = (typeinfos, parent)
   937         elif isinstance(lookup_classes, DictType):
   951         elif isinstance(lookup_classes, DictType):
   938             lookup_classes[self.etreeNamespaceFormat % parent 
   952             self.AddDistinctionBetweenParentsInLookupClass(
   939                            if parent is not None else None] = typeinfos
   953                 lookup_classes, parent, typeinfos)
   940         else:
   954         else:
   941             lookup_classes = {self.etreeNamespaceFormat % lookup_classes[1]
   955             lookup_classes = {
   942                               if lookup_classes[1] is not None else None: lookup_classes[0]}
   956                 self.etreeNamespaceFormat % lookup_classes[1]
   943             lookup_classes[self.etreeNamespaceFormat % parent
   957                 if lookup_classes[1] is not None else None: lookup_classes[0]}
   944                            if parent is not None else None] = typeinfos
   958             self.AddDistinctionBetweenParentsInLookupClass(
       
   959                 lookup_classes, parent, typeinfos)
   945             self.ComputedClassesLookUp[lookup_name] = lookup_classes
   960             self.ComputedClassesLookUp[lookup_name] = lookup_classes
   946     
   961     
   947     def ExtractTypeInfos(self, name, parent, typeinfos):
   962     def ExtractTypeInfos(self, name, parent, typeinfos):
   948         if isinstance(typeinfos, (StringType, UnicodeType)):
   963         if isinstance(typeinfos, (StringType, UnicodeType)):
   949             namespace, type_name = DecomposeQualifiedName(typeinfos)
   964             namespace, type_name = DecomposeQualifiedName(typeinfos)
  1128                     classmembers["delete%s" % elmtname] = generateDeleteMethod(elmtname)
  1143                     classmembers["delete%s" % elmtname] = generateDeleteMethod(elmtname)
  1129             classmembers["set%s" % elmtname] = generateSetMethod(elmtname)
  1144             classmembers["set%s" % elmtname] = generateSetMethod(elmtname)
  1130             classmembers["get%s" % elmtname] = generateGetMethod(elmtname)
  1145             classmembers["get%s" % elmtname] = generateGetMethod(elmtname)
  1131             
  1146             
  1132         classmembers["_init_"] = generateInitMethod(self, classinfos)
  1147         classmembers["_init_"] = generateInitMethod(self, classinfos)
       
  1148         classmembers["StructurePattern"] = GetStructurePattern(classinfos)
  1133         classmembers["getElementAttributes"] = generateGetElementAttributes(self, classinfos)
  1149         classmembers["getElementAttributes"] = generateGetElementAttributes(self, classinfos)
  1134         classmembers["getElementInfos"] = generateGetElementInfos(self, classinfos)
  1150         classmembers["getElementInfos"] = generateGetElementInfos(self, classinfos)
  1135         classmembers["setElementValue"] = generateSetElementValue(self, classinfos)
  1151         classmembers["setElementValue"] = generateSetElementValue(self, classinfos)
  1136         
  1152         
  1137         class_definition = classobj(str(classname), bases, classmembers)
  1153         class_definition = classobj(str(classname), bases, classmembers)
  1173     def PrintClassNames(self):
  1189     def PrintClassNames(self):
  1174         classnames = self.XMLClassDefinitions.keys()
  1190         classnames = self.XMLClassDefinitions.keys()
  1175         classnames.sort()
  1191         classnames.sort()
  1176         for classname in classnames:
  1192         for classname in classnames:
  1177             print classname
  1193             print classname
       
  1194 
       
  1195 """
       
  1196 Method that generate the method for generating the xml tree structure model by 
       
  1197 following the attributes list defined
       
  1198 """
       
  1199 def ComputeMultiplicity(name, infos):
       
  1200     if infos["minOccurs"] == 0:
       
  1201         if infos["maxOccurs"] == "unbounded":
       
  1202             return "(?:%s)*" % name
       
  1203         elif infos["maxOccurs"] == 1:
       
  1204             return "(?:%s)?" % name
       
  1205         else:
       
  1206             return "(?:%s){,%d}" % (name, infos["maxOccurs"])
       
  1207     elif infos["minOccurs"] == 1:
       
  1208         if infos["maxOccurs"] == "unbounded":
       
  1209             return "(?:%s)+" % name
       
  1210         elif infos["maxOccurs"] == 1:
       
  1211             return "(?:%s)" % name
       
  1212         else:
       
  1213             return "(?:%s){1,%d}" % (name, infos["maxOccurs"])
       
  1214     else:
       
  1215         if infos["maxOccurs"] == "unbounded":
       
  1216             return "(?:%s){%d,}" % (name, infos["minOccurs"], name)
       
  1217         else:
       
  1218             return "(?:%s){%d,%d}" % (name, infos["minOccurs"], 
       
  1219                                        infos["maxOccurs"])
       
  1220 
       
  1221 def GetStructurePattern(classinfos):
       
  1222     base_structure_pattern = (
       
  1223         classinfos["base"].StructurePattern.pattern[:-1]
       
  1224         if classinfos.has_key("base") else "")
       
  1225     elements = []
       
  1226     for element in classinfos["elements"]:
       
  1227         if element["type"] == ANY:
       
  1228             infos = element.copy()
       
  1229             infos["minOccurs"] = 0
       
  1230             elements.append(ComputeMultiplicity("#text |#cdata-section |\w* ", infos))
       
  1231         elif element["type"] == CHOICE:
       
  1232             choices = []
       
  1233             for infos in element["choices"]:
       
  1234                 if infos["type"] == "sequence":
       
  1235                     structure = "(?:%s)" % GetStructurePattern(infos)
       
  1236                 else:
       
  1237                     structure = "%s " % infos["name"]
       
  1238                 choices.append(ComputeMultiplicity(structure, infos))
       
  1239             elements.append(ComputeMultiplicity("|".join(choices), element))
       
  1240         elif element["name"] == "content" and element["elmt_type"]["type"] == SIMPLETYPE:
       
  1241             elements.append("(?:#text |#cdata-section )?")
       
  1242         else:
       
  1243             elements.append(ComputeMultiplicity("%s " % element["name"], element))
       
  1244     if classinfos.get("order", True) or len(elements) == 0:
       
  1245         return re.compile(base_structure_pattern + "".join(elements) + "$")
       
  1246     else:
       
  1247         raise ValueError("XSD structure not yet supported!")
  1178 
  1248 
  1179 """
  1249 """
  1180 Method that generate the method for creating a class instance
  1250 Method that generate the method for creating a class instance
  1181 """
  1251 """
  1182 def generateClassCreateFunction(class_definition):
  1252 def generateClassCreateFunction(class_definition):
  1212                 elif len(content) > 0:
  1282                 elif len(content) > 0:
  1213                     return content[0]
  1283                     return content[0]
  1214                 return None 
  1284                 return None 
  1215             elif element_infos["type"] == ANY:
  1285             elif element_infos["type"] == ANY:
  1216                 return element_infos["elmt_type"]["extract"](self)
  1286                 return element_infos["elmt_type"]["extract"](self)
       
  1287             elif name == "content" and element_infos["elmt_type"]["type"] == SIMPLETYPE:
       
  1288                 return element_infos["elmt_type"]["extract"](self.text, extract=False)
  1217             else:
  1289             else:
  1218                 element_name = factory.etreeNamespaceFormat % name
  1290                 element_name = factory.etreeNamespaceFormat % name
  1219                 if element_infos["maxOccurs"] == "unbounded" or element_infos["maxOccurs"] > 1:
  1291                 if element_infos["maxOccurs"] == "unbounded" or element_infos["maxOccurs"] > 1:
  1220                     return self.findall(element_name)
  1292                     values = self.findall(element_name)
       
  1293                     if element_infos["elmt_type"]["type"] == SIMPLETYPE:
       
  1294                         return map(lambda value:
       
  1295                             element_infos["elmt_type"]["extract"](value.text, extract=False), 
       
  1296                             values)
       
  1297                     return values
  1221                 else:
  1298                 else:
  1222                     return self.find(element_name)
  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
  1223             
  1303             
  1224         elif classinfos.has_key("base"):
  1304         elif classinfos.has_key("base"):
  1225             return classinfos["base"].__getattr__(self, name)
  1305             return classinfos["base"].__getattr__(self, name)
  1226         
  1306         
  1227         return DefaultElementClass.__getattribute__(self, name)
  1307         return DefaultElementClass.__getattribute__(self, name)
  1249         elif elements.has_key(name):
  1329         elif elements.has_key(name):
  1250             element_infos = elements[name]
  1330             element_infos = elements[name]
  1251             element_infos["elmt_type"] = FindTypeInfos(factory, element_infos["elmt_type"])
  1331             element_infos["elmt_type"] = FindTypeInfos(factory, element_infos["elmt_type"])
  1252             if element_infos["type"] == ANY:
  1332             if element_infos["type"] == ANY:
  1253                 element_infos["elmt_type"]["generate"](self, value)
  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)
  1254             
  1337             
  1255             else:
  1338             else:
  1256                 prefix = ("%s:" % factory.TargetNamespace
  1339                 prefix = ("%s:" % factory.TargetNamespace
  1257                           if factory.TargetNamespace is not None else "")
  1340                           if factory.TargetNamespace is not None else "")
  1258                 element_xpath = (prefix + name
  1341                 element_xpath = (prefix + name
  1275                     else:
  1358                     else:
  1276                         insertion_point = 0
  1359                         insertion_point = 0
  1277                     
  1360                     
  1278                     if not isinstance(value, ListType):
  1361                     if not isinstance(value, ListType):
  1279                         value = [value]
  1362                         value = [value]
  1280                         
  1363                     
  1281                     for element in reversed(value):
  1364                     for element in reversed(value):
       
  1365                         if element_infos["elmt_type"]["type"] == SIMPLETYPE:
       
  1366                             tmp_element = etree.Element(factory.etreeNamespaceFormat % name)
       
  1367                             tmp_element.text = element_infos["elmt_type"]["generate"](element)
       
  1368                             element = tmp_element
  1282                         self.insert(insertion_point, element)
  1369                         self.insert(insertion_point, element)
  1283         
  1370         
  1284         elif classinfos.has_key("base"):
  1371         elif classinfos.has_key("base"):
  1285             return classinfos["base"].__setattr__(self, name, value)
  1372             return classinfos["base"].__setattr__(self, name, value)
  1286         
  1373         
  1594 
  1681 
  1595 NAMESPACE_PATTERN = re.compile("xmlns(?:\:[^\=]*)?=\"[^\"]*\" ")
  1682 NAMESPACE_PATTERN = re.compile("xmlns(?:\:[^\=]*)?=\"[^\"]*\" ")
  1596 
  1683 
  1597 class DefaultElementClass(etree.ElementBase):
  1684 class DefaultElementClass(etree.ElementBase):
  1598     
  1685     
       
  1686     StructurePattern = re.compile("$")
       
  1687     
  1599     def _init_(self):
  1688     def _init_(self):
  1600         pass
  1689         pass
  1601     
  1690     
  1602     def getLocalTag(self):
  1691     def getLocalTag(self):
  1603         return etree.QName(self.tag).localname
  1692         return etree.QName(self.tag).localname
  1623             return self.GetElementClass(element_with_parent_class, default=default)
  1712             return self.GetElementClass(element_with_parent_class, default=default)
  1624         return element_with_parent_class
  1713         return element_with_parent_class
  1625         
  1714         
  1626     def lookup(self, document, element):
  1715     def lookup(self, document, element):
  1627         parent = element.getparent()
  1716         parent = element.getparent()
  1628         return self.GetElementClass(element.tag, 
  1717         element_class = self.GetElementClass(element.tag, 
  1629             parent.tag if parent is not None else None)
  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
  1630 
  1730 
  1631 class XMLClassParser(etree.XMLParser):
  1731 class XMLClassParser(etree.XMLParser):
  1632 
  1732 
  1633     def __init__(self, namespaces, default_namespace_format, base_class, *args, **kwargs):
  1733     def __init__(self, namespaces, default_namespace_format, base_class, *args, **kwargs):
  1634         etree.XMLParser.__init__(self, *args, **kwargs)
  1734         etree.XMLParser.__init__(self, *args, **kwargs)
  1667             self.DefaultNamespaceFormat % element_tag, 
  1767             self.DefaultNamespaceFormat % element_tag, 
  1668             self.DefaultNamespaceFormat % parent_tag 
  1768             self.DefaultNamespaceFormat % parent_tag 
  1669             if parent_tag is not None else parent_tag, 
  1769             if parent_tag is not None else parent_tag, 
  1670             None)
  1770             None)
  1671     
  1771     
  1672     def CreateElement(self, element_tag, parent_tag=None):
  1772     def CreateElement(self, element_tag, parent_tag=None, class_idx=None):
  1673         new_element = self.GetElementClass(element_tag, parent_tag)()
  1773         element_class = self.GetElementClass(element_tag, parent_tag)
       
  1774         if isinstance(element_class, ListType):
       
  1775             if class_idx is not None and class_idx < len(element_class):
       
  1776                 new_element = element_class[class_idx]()
       
  1777             else:
       
  1778                 raise ValueError, "No corresponding class found!"
       
  1779         else:
       
  1780             new_element = element_class()
  1674         DefaultElementClass.__setattr__(new_element, "tag", self.DefaultNamespaceFormat % element_tag)
  1781         DefaultElementClass.__setattr__(new_element, "tag", self.DefaultNamespaceFormat % element_tag)
  1675         new_element._init_()
  1782         new_element._init_()
  1676         return new_element
  1783         return new_element
  1677     
  1784     
  1678 def GenerateParser(factory, xsdstring):
  1785 def GenerateParser(factory, xsdstring):
  1679     ComputedClasses = factory.CreateClasses()
  1786     ComputedClasses = factory.CreateClasses()
  1680     if factory.FileName is not None and len(ComputedClasses) == 1:
  1787     
       
  1788     if factory.FileName is not None:
  1681         ComputedClasses = ComputedClasses[factory.FileName]
  1789         ComputedClasses = ComputedClasses[factory.FileName]
  1682     BaseClass = [(name, XSDclass) for name, XSDclass in ComputedClasses.items() if XSDclass.IsBaseClass]
  1790     BaseClass = [(name, XSDclass) for name, XSDclass in ComputedClasses.items() if XSDclass.IsBaseClass]
  1683     UpdateXMLClassGlobals(ComputedClasses)
  1791        
  1684     
       
  1685     parser = XMLClassParser(
  1792     parser = XMLClassParser(
  1686         factory.NSMAP,
  1793         factory.NSMAP,
  1687         factory.etreeNamespaceFormat,
  1794         factory.etreeNamespaceFormat,
  1688         BaseClass[0] if len(BaseClass) == 1 else None,
  1795         BaseClass[0] if len(BaseClass) == 1 else None,
  1689         schema = etree.XMLSchema(etree.fromstring(xsdstring)),
  1796         schema = etree.XMLSchema(etree.fromstring(xsdstring)),
  1691     class_lookup = XMLElementClassLookUp(factory.ComputedClassesLookUp)
  1798     class_lookup = XMLElementClassLookUp(factory.ComputedClassesLookUp)
  1692     parser.set_element_class_lookup(class_lookup)
  1799     parser.set_element_class_lookup(class_lookup)
  1693     
  1800     
  1694     return parser
  1801     return parser
  1695 
  1802 
  1696 def UpdateXMLClassGlobals(classes):
       
  1697     globals().update(classes)
       
  1698