616 infos["elmt_type"] = FindTypeInfos(factory, infos["elmt_type"]) |
616 infos["elmt_type"] = FindTypeInfos(factory, infos["elmt_type"]) |
617 if infos["minOccurs"] == 1: |
617 if infos["minOccurs"] == 1: |
618 element_name = factory.etreeNamespaceFormat % infos["name"] |
618 element_name = factory.etreeNamespaceFormat % infos["name"] |
619 if infos["elmt_type"]["type"] == SIMPLETYPE: |
619 if infos["elmt_type"]["type"] == SIMPLETYPE: |
620 def initial_value(): |
620 def initial_value(): |
621 value = etree.Element(element_name) |
621 value = factory.Parser.makeelement(element_name) |
622 value.text = (infos["elmt_type"]["generate"](infos["elmt_type"]["initial"]())) |
622 value.text = (infos["elmt_type"]["generate"](infos["elmt_type"]["initial"]())) |
|
623 value._init_() |
623 return value |
624 return value |
624 else: |
625 else: |
625 def initial_value(): |
626 def initial_value(): |
626 value = infos["elmt_type"]["initial"]() |
627 value = infos["elmt_type"]["initial"]() |
627 if infos["type"] != ANY: |
628 if infos["type"] != ANY: |
1160 classmembers["delete%s" % elmtname] = generateDeleteMethod(elmtname) |
1162 classmembers["delete%s" % elmtname] = generateDeleteMethod(elmtname) |
1161 classmembers["set%s" % elmtname] = generateSetMethod(elmtname) |
1163 classmembers["set%s" % elmtname] = generateSetMethod(elmtname) |
1162 classmembers["get%s" % elmtname] = generateGetMethod(elmtname) |
1164 classmembers["get%s" % elmtname] = generateGetMethod(elmtname) |
1163 |
1165 |
1164 classmembers["_init_"] = generateInitMethod(self, classinfos) |
1166 classmembers["_init_"] = generateInitMethod(self, classinfos) |
1165 classmembers["_tmp_initial_"] = None |
|
1166 classmembers["StructurePattern"] = GetStructurePattern(classinfos) |
1167 classmembers["StructurePattern"] = GetStructurePattern(classinfos) |
1167 classmembers["getElementAttributes"] = generateGetElementAttributes(self, classinfos) |
1168 classmembers["getElementAttributes"] = generateGetElementAttributes(self, classinfos) |
1168 classmembers["getElementInfos"] = generateGetElementInfos(self, classinfos) |
1169 classmembers["getElementInfos"] = generateGetElementInfos(self, classinfos) |
1169 classmembers["setElementValue"] = generateSetElementValue(self, classinfos) |
1170 classmembers["setElementValue"] = generateSetElementValue(self, classinfos) |
1170 |
1171 |
1172 setattr(class_definition, "__getattr__", generateGetattrMethod(self, class_definition, classinfos)) |
1173 setattr(class_definition, "__getattr__", generateGetattrMethod(self, class_definition, classinfos)) |
1173 setattr(class_definition, "__setattr__", generateSetattrMethod(self, class_definition, classinfos)) |
1174 setattr(class_definition, "__setattr__", generateSetattrMethod(self, class_definition, classinfos)) |
1174 class_infos = { |
1175 class_infos = { |
1175 "type": COMPILEDCOMPLEXTYPE, |
1176 "type": COMPILEDCOMPLEXTYPE, |
1176 "name": classname, |
1177 "name": classname, |
1177 "initial": generateClassCreateFunction(class_definition), |
1178 "initial": generateClassCreateFunction(self, class_definition), |
1178 } |
1179 } |
1179 |
|
1180 if self.FileName is not None: |
1180 if self.FileName is not None: |
1181 self.ComputedClasses[self.FileName][classname] = class_definition |
1181 self.ComputedClasses[self.FileName][classname] = class_definition |
1182 else: |
1182 else: |
1183 self.ComputedClasses[classname] = class_definition |
1183 self.ComputedClasses[classname] = class_definition |
1184 self.ComputedClassesInfos[classname] = class_infos |
1184 self.ComputedClassesInfos[classname] = class_infos |
1267 return re.compile(base_structure_pattern + "".join(elements) + "$") |
1267 return re.compile(base_structure_pattern + "".join(elements) + "$") |
1268 else: |
1268 else: |
1269 raise ValueError("XSD structure not yet supported!") |
1269 raise ValueError("XSD structure not yet supported!") |
1270 |
1270 |
1271 |
1271 |
1272 def generateClassCreateFunction(class_definition): |
1272 def generateClassCreateFunction(factory, class_definition): |
1273 """ |
1273 """ |
1274 Method that generate the method for creating a class instance |
1274 Method that generate the method for creating a class instance |
1275 """ |
1275 """ |
1276 def classCreatefunction(): |
1276 def classCreatefunction(): |
1277 return class_definition() |
1277 return factory.Parser.CreateElementFromClass(class_definition) |
1278 return classCreatefunction |
1278 return classCreatefunction |
1279 |
1279 |
1280 |
1280 |
1281 def generateGetattrMethod(factory, class_definition, classinfos): |
1281 def generateGetattrMethod(factory, class_definition, classinfos): |
1282 attributes = dict([(attr["name"], attr) for attr in classinfos["attributes"] if attr["use"] != "prohibited"]) |
1282 attributes = dict([(attr["name"], attr) for attr in classinfos["attributes"] if attr["use"] != "prohibited"]) |
1385 if not isinstance(value, ListType): |
1385 if not isinstance(value, ListType): |
1386 value = [value] |
1386 value = [value] |
1387 |
1387 |
1388 for element in reversed(value): |
1388 for element in reversed(value): |
1389 if element_infos["elmt_type"]["type"] == SIMPLETYPE: |
1389 if element_infos["elmt_type"]["type"] == SIMPLETYPE: |
1390 tmp_element = etree.Element(factory.etreeNamespaceFormat % name) |
1390 tmp_element = factory.Parser.makeelement(factory.etreeNamespaceFormat % name) |
1391 tmp_element.text = element_infos["elmt_type"]["generate"](element) |
1391 tmp_element.text = element_infos["elmt_type"]["generate"](element) |
1392 element = tmp_element |
1392 element = tmp_element |
1393 self.insert(insertion_point, element) |
1393 self.insert(insertion_point, element) |
1394 |
1394 |
1395 elif "base" in classinfos: |
1395 elif "base" in classinfos: |
1580 self.set(attribute["name"], attribute["attr_type"]["generate"](attribute["attr_type"]["initial"]())) |
1580 self.set(attribute["name"], attribute["attr_type"]["generate"](attribute["attr_type"]["initial"]())) |
1581 for element in classinfos["elements"]: |
1581 for element in classinfos["elements"]: |
1582 if element["type"] != CHOICE: |
1582 if element["type"] != CHOICE: |
1583 initial = GetElementInitialValue(factory, element) |
1583 initial = GetElementInitialValue(factory, element) |
1584 if initial is not None: |
1584 if initial is not None: |
1585 # FIXME: this is looks like dirty hack to fix strange problem with initial[0] |
|
1586 # changing its type after returning from _init_ method to lxml.etree._Element |
|
1587 # As a result all methods generated by class factory are lost. |
|
1588 object.__setattr__(self, "_tmp_initial_", initial) |
|
1589 map(self.append, initial) |
1585 map(self.append, initial) |
1590 return initMethod |
1586 return initMethod |
1591 |
1587 |
1592 |
1588 |
1593 def generateSetMethod(attr): |
1589 def generateSetMethod(attr): |
1745 class XMLElementClassLookUp(etree.PythonElementClassLookup): |
1741 class XMLElementClassLookUp(etree.PythonElementClassLookup): |
1746 |
1742 |
1747 def __init__(self, classes, *args, **kwargs): |
1743 def __init__(self, classes, *args, **kwargs): |
1748 etree.PythonElementClassLookup.__init__(self, *args, **kwargs) |
1744 etree.PythonElementClassLookup.__init__(self, *args, **kwargs) |
1749 self.LookUpClasses = classes |
1745 self.LookUpClasses = classes |
|
1746 self.ElementTag = None |
|
1747 self.ElementClass = None |
1750 |
1748 |
1751 def GetElementClass(self, element_tag, parent_tag=None, default=DefaultElementClass): |
1749 def GetElementClass(self, element_tag, parent_tag=None, default=DefaultElementClass): |
1752 element_class = self.LookUpClasses.get(element_tag, (default, None)) |
1750 element_class = self.LookUpClasses.get(element_tag, (default, None)) |
1753 if not isinstance(element_class, DictType): |
1751 if not isinstance(element_class, DictType): |
1754 if isinstance(element_class[0], (StringType, UnicodeType)): |
1752 if isinstance(element_class[0], (StringType, UnicodeType)): |
1758 element_with_parent_class = element_class.get(parent_tag, default) |
1756 element_with_parent_class = element_class.get(parent_tag, default) |
1759 if isinstance(element_with_parent_class, (StringType, UnicodeType)): |
1757 if isinstance(element_with_parent_class, (StringType, UnicodeType)): |
1760 return self.GetElementClass(element_with_parent_class, default=default) |
1758 return self.GetElementClass(element_with_parent_class, default=default) |
1761 return element_with_parent_class |
1759 return element_with_parent_class |
1762 |
1760 |
|
1761 def SetLookupResult(self, element, element_class): |
|
1762 """ |
|
1763 Set lookup result for the next 'lookup' callback made by lxml backend. |
|
1764 Lookup result is used only if element matches with tag's name submited to 'lookup'. |
|
1765 This is done, because there is no way to submit extra search parameters for |
|
1766 etree.PythonElementClassLookup.lookup() from etree.XMLParser.makeelement() |
|
1767 It's valid only for a signle 'lookup' call. |
|
1768 |
|
1769 :param element: |
|
1770 element's tag name |
|
1771 :param element_class: |
|
1772 element class that should be returned on |
|
1773 match in the next 'lookup' call. |
|
1774 :return: |
|
1775 Nothing |
|
1776 """ |
|
1777 self.ElementTag = element |
|
1778 self.ElementClass = element_class |
|
1779 |
|
1780 def ResetLookupResult(self): |
|
1781 """Reset lookup result, so it don't influence next lookups""" |
|
1782 self.ElementTag = None |
|
1783 self.ElementClass = None |
|
1784 |
|
1785 def GetLookupResult(self, element): |
|
1786 """Returns previously set SetLookupResult() lookup result""" |
|
1787 element_class = None |
|
1788 if self.ElementTag is not None and self.ElementTag == element.tag: |
|
1789 element_class = self.ElementClass |
|
1790 self.ResetLookupResult() |
|
1791 return element_class |
|
1792 |
1763 def lookup(self, document, element): |
1793 def lookup(self, document, element): |
|
1794 """ |
|
1795 Lookup for element class for given element tag. |
|
1796 If return None from this method, the fallback is called. |
|
1797 |
|
1798 :param document: |
|
1799 opaque document instance that contains the Element |
|
1800 :param element: |
|
1801 lightweight Element proxy implementation that is only valid during the lookup. |
|
1802 Do not try to keep a reference to it. |
|
1803 Once the lookup is done, the proxy will be invalid. |
|
1804 :return: |
|
1805 Returns element class corresponding to given element. |
|
1806 """ |
|
1807 element_class = self.GetLookupResult(element) |
|
1808 if element_class is not None: |
|
1809 return element_class |
|
1810 |
1764 parent = element.getparent() |
1811 parent = element.getparent() |
1765 element_class = self.GetElementClass( |
1812 element_class = self.GetElementClass( |
1766 element.tag, parent.tag if parent is not None else None) |
1813 element.tag, parent.tag if parent is not None else None) |
1767 if isinstance(element_class, ListType): |
1814 if isinstance(element_class, ListType): |
1768 children = "".join([ |
1815 children = "".join([ |
1776 return element_class[0] |
1823 return element_class[0] |
1777 return element_class |
1824 return element_class |
1778 |
1825 |
1779 |
1826 |
1780 class XMLClassParser(etree.XMLParser): |
1827 class XMLClassParser(etree.XMLParser): |
1781 |
1828 def __init__(self, *args, **kwargs): |
1782 def __init__(self, namespaces, default_namespace_format, base_class, xsd_schema, *args, **kwargs): |
|
1783 etree.XMLParser.__init__(self, *args, **kwargs) |
1829 etree.XMLParser.__init__(self, *args, **kwargs) |
|
1830 |
|
1831 def initMembers(self, namespaces, default_namespace_format, base_class, xsd_schema): |
1784 self.DefaultNamespaceFormat = default_namespace_format |
1832 self.DefaultNamespaceFormat = default_namespace_format |
1785 self.NSMAP = namespaces |
1833 self.NSMAP = namespaces |
1786 targetNamespace = etree.QName(default_namespace_format % "d").namespace |
1834 targetNamespace = etree.QName(default_namespace_format % "d").namespace |
1787 if targetNamespace is not None: |
1835 if targetNamespace is not None: |
1788 self.RootNSMAP = { |
1836 self.RootNSMAP = { |
1825 self.DefaultNamespaceFormat % parent_tag |
1873 self.DefaultNamespaceFormat % parent_tag |
1826 if parent_tag is not None else parent_tag, |
1874 if parent_tag is not None else parent_tag, |
1827 None) |
1875 None) |
1828 |
1876 |
1829 def CreateElement(self, element_tag, parent_tag=None, class_idx=None): |
1877 def CreateElement(self, element_tag, parent_tag=None, class_idx=None): |
|
1878 """ |
|
1879 Create XML element based on elements and parent's tag names. |
|
1880 |
|
1881 :param element_tag: |
|
1882 element's tag name |
|
1883 :param parent_tag: |
|
1884 optional parent's tag name. Default value is None. |
|
1885 :param class_idx: |
|
1886 optional index of class in list of founded classes |
|
1887 with same element and parent. Default value is None. |
|
1888 :return: |
|
1889 created XML element |
|
1890 (subclass of lxml.etree._Element created by class factory) |
|
1891 """ |
1830 element_class = self.GetElementClass(element_tag, parent_tag) |
1892 element_class = self.GetElementClass(element_tag, parent_tag) |
1831 if isinstance(element_class, ListType): |
1893 if isinstance(element_class, ListType): |
1832 if class_idx is not None and class_idx < len(element_class): |
1894 if class_idx is not None and class_idx < len(element_class): |
1833 new_element = element_class[class_idx]() |
1895 element_class = element_class[class_idx] |
1834 else: |
1896 else: |
1835 raise ValueError("No corresponding class found!") |
1897 raise ValueError("No corresponding class found!") |
1836 else: |
1898 return self.CreateElementFromClass(element_class, element_tag) |
1837 new_element = element_class() |
1899 |
|
1900 def CreateElementFromClass(self, element_class, element_tag=None): |
|
1901 """ |
|
1902 Create XML element instance of submitted element's class. |
|
1903 Submitted class should be subclass of lxml.etree._Element. |
|
1904 |
|
1905 element_class shouldn't be used to create XML element |
|
1906 directly using element_class(), because lxml backend |
|
1907 should be aware what class handles what xml element, |
|
1908 otherwise default lxml.etree._Element will be used. |
|
1909 |
|
1910 :param element_class: |
|
1911 element class |
|
1912 :param element_tag: |
|
1913 optional element's tag name. |
|
1914 If omitted it's calculated from element_class instance. |
|
1915 :return: |
|
1916 created XML element |
|
1917 (subclass of lxml.etree._Element created by class factory) |
|
1918 """ |
|
1919 if element_tag is None: |
|
1920 element_tag = element_class().tag |
|
1921 etag = self.DefaultNamespaceFormat % element_tag |
|
1922 self.ClassLookup.SetLookupResult(etag, element_class) |
|
1923 new_element = self.makeelement(etag) |
|
1924 self.ClassLookup.ResetLookupResult() |
1838 DefaultElementClass.__setattr__(new_element, "tag", self.DefaultNamespaceFormat % element_tag) |
1925 DefaultElementClass.__setattr__(new_element, "tag", self.DefaultNamespaceFormat % element_tag) |
1839 new_element._init_() |
1926 new_element._init_() |
1840 return new_element |
1927 return new_element |
1841 |
1928 |
1842 |
1929 |
1843 def GenerateParser(factory, xsdstring): |
1930 def GenerateParser(factory, xsdstring): |
1844 """ |
1931 """ |
1845 This function generate a xml parser from a class factory |
1932 This function generate a xml parser from a class factory |
1846 """ |
1933 """ |
1847 |
1934 |
|
1935 parser = XMLClassParser(strip_cdata=False, remove_blank_text=True) |
|
1936 factory.Parser = parser |
|
1937 |
1848 ComputedClasses = factory.CreateClasses() |
1938 ComputedClasses = factory.CreateClasses() |
1849 |
|
1850 if factory.FileName is not None: |
1939 if factory.FileName is not None: |
1851 ComputedClasses = ComputedClasses[factory.FileName] |
1940 ComputedClasses = ComputedClasses[factory.FileName] |
1852 BaseClass = [(name, XSDclass) for name, XSDclass in ComputedClasses.items() if XSDclass.IsBaseClass] |
1941 BaseClass = [(name, XSDclass) for name, XSDclass in ComputedClasses.items() if XSDclass.IsBaseClass] |
1853 |
1942 |
1854 parser = XMLClassParser( |
1943 parser.initMembers( |
1855 factory.NSMAP, |
1944 factory.NSMAP, |
1856 factory.etreeNamespaceFormat, |
1945 factory.etreeNamespaceFormat, |
1857 BaseClass[0] if len(BaseClass) == 1 else None, |
1946 BaseClass[0] if len(BaseClass) == 1 else None, |
1858 etree.XMLSchema(etree.fromstring(xsdstring)), |
1947 etree.XMLSchema(etree.fromstring(xsdstring))) |
1859 strip_cdata=False, remove_blank_text=True) |
1948 |
1860 class_lookup = XMLElementClassLookUp(factory.ComputedClassesLookUp) |
1949 class_lookup = XMLElementClassLookUp(factory.ComputedClassesLookUp) |
1861 parser.set_element_class_lookup(class_lookup) |
1950 parser.set_element_class_lookup(class_lookup) |
1862 |
1951 |
1863 return parser |
1952 return parser |