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: |
1171 setattr(class_definition, "__getattr__", generateGetattrMethod(self, class_definition, classinfos)) |
1173 setattr(class_definition, "__getattr__", generateGetattrMethod(self, class_definition, classinfos)) |
1172 setattr(class_definition, "__setattr__", generateSetattrMethod(self, class_definition, classinfos)) |
1174 setattr(class_definition, "__setattr__", generateSetattrMethod(self, class_definition, classinfos)) |
1173 class_infos = { |
1175 class_infos = { |
1174 "type": COMPILEDCOMPLEXTYPE, |
1176 "type": COMPILEDCOMPLEXTYPE, |
1175 "name": classname, |
1177 "name": classname, |
1176 "initial": generateClassCreateFunction(class_definition), |
1178 "initial": generateClassCreateFunction(self, class_definition), |
1177 } |
1179 } |
1178 |
|
1179 if self.FileName is not None: |
1180 if self.FileName is not None: |
1180 self.ComputedClasses[self.FileName][classname] = class_definition |
1181 self.ComputedClasses[self.FileName][classname] = class_definition |
1181 else: |
1182 else: |
1182 self.ComputedClasses[classname] = class_definition |
1183 self.ComputedClasses[classname] = class_definition |
1183 self.ComputedClassesInfos[classname] = class_infos |
1184 self.ComputedClassesInfos[classname] = class_infos |
1266 return re.compile(base_structure_pattern + "".join(elements) + "$") |
1267 return re.compile(base_structure_pattern + "".join(elements) + "$") |
1267 else: |
1268 else: |
1268 raise ValueError("XSD structure not yet supported!") |
1269 raise ValueError("XSD structure not yet supported!") |
1269 |
1270 |
1270 |
1271 |
1271 def generateClassCreateFunction(class_definition): |
1272 def generateClassCreateFunction(factory, class_definition): |
1272 """ |
1273 """ |
1273 Method that generate the method for creating a class instance |
1274 Method that generate the method for creating a class instance |
1274 """ |
1275 """ |
1275 def classCreatefunction(): |
1276 def classCreatefunction(): |
1276 return class_definition() |
1277 return factory.Parser.CreateElementFromClass(class_definition) |
1277 return classCreatefunction |
1278 return classCreatefunction |
1278 |
1279 |
1279 |
1280 |
1280 def generateGetattrMethod(factory, class_definition, classinfos): |
1281 def generateGetattrMethod(factory, class_definition, classinfos): |
1281 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"]) |
1384 if not isinstance(value, ListType): |
1385 if not isinstance(value, ListType): |
1385 value = [value] |
1386 value = [value] |
1386 |
1387 |
1387 for element in reversed(value): |
1388 for element in reversed(value): |
1388 if element_infos["elmt_type"]["type"] == SIMPLETYPE: |
1389 if element_infos["elmt_type"]["type"] == SIMPLETYPE: |
1389 tmp_element = etree.Element(factory.etreeNamespaceFormat % name) |
1390 tmp_element = factory.Parser.makeelement(factory.etreeNamespaceFormat % name) |
1390 tmp_element.text = element_infos["elmt_type"]["generate"](element) |
1391 tmp_element.text = element_infos["elmt_type"]["generate"](element) |
1391 element = tmp_element |
1392 element = tmp_element |
1392 self.insert(insertion_point, element) |
1393 self.insert(insertion_point, element) |
1393 |
1394 |
1394 elif "base" in classinfos: |
1395 elif "base" in classinfos: |
1740 class XMLElementClassLookUp(etree.PythonElementClassLookup): |
1741 class XMLElementClassLookUp(etree.PythonElementClassLookup): |
1741 |
1742 |
1742 def __init__(self, classes, *args, **kwargs): |
1743 def __init__(self, classes, *args, **kwargs): |
1743 etree.PythonElementClassLookup.__init__(self, *args, **kwargs) |
1744 etree.PythonElementClassLookup.__init__(self, *args, **kwargs) |
1744 self.LookUpClasses = classes |
1745 self.LookUpClasses = classes |
|
1746 self.ElementTag = None |
|
1747 self.ElementClass = None |
1745 |
1748 |
1746 def GetElementClass(self, element_tag, parent_tag=None, default=DefaultElementClass): |
1749 def GetElementClass(self, element_tag, parent_tag=None, default=DefaultElementClass): |
1747 element_class = self.LookUpClasses.get(element_tag, (default, None)) |
1750 element_class = self.LookUpClasses.get(element_tag, (default, None)) |
1748 if not isinstance(element_class, DictType): |
1751 if not isinstance(element_class, DictType): |
1749 if isinstance(element_class[0], (StringType, UnicodeType)): |
1752 if isinstance(element_class[0], (StringType, UnicodeType)): |
1753 element_with_parent_class = element_class.get(parent_tag, default) |
1756 element_with_parent_class = element_class.get(parent_tag, default) |
1754 if isinstance(element_with_parent_class, (StringType, UnicodeType)): |
1757 if isinstance(element_with_parent_class, (StringType, UnicodeType)): |
1755 return self.GetElementClass(element_with_parent_class, default=default) |
1758 return self.GetElementClass(element_with_parent_class, default=default) |
1756 return element_with_parent_class |
1759 return element_with_parent_class |
1757 |
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 |
1758 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 |
1759 parent = element.getparent() |
1811 parent = element.getparent() |
1760 element_class = self.GetElementClass( |
1812 element_class = self.GetElementClass( |
1761 element.tag, parent.tag if parent is not None else None) |
1813 element.tag, parent.tag if parent is not None else None) |
1762 if isinstance(element_class, ListType): |
1814 if isinstance(element_class, ListType): |
1763 children = "".join([ |
1815 children = "".join([ |
1771 return element_class[0] |
1823 return element_class[0] |
1772 return element_class |
1824 return element_class |
1773 |
1825 |
1774 |
1826 |
1775 class XMLClassParser(etree.XMLParser): |
1827 class XMLClassParser(etree.XMLParser): |
1776 |
1828 def __init__(self, *args, **kwargs): |
1777 def __init__(self, namespaces, default_namespace_format, base_class, xsd_schema, *args, **kwargs): |
|
1778 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): |
1779 self.DefaultNamespaceFormat = default_namespace_format |
1832 self.DefaultNamespaceFormat = default_namespace_format |
1780 self.NSMAP = namespaces |
1833 self.NSMAP = namespaces |
1781 targetNamespace = etree.QName(default_namespace_format % "d").namespace |
1834 targetNamespace = etree.QName(default_namespace_format % "d").namespace |
1782 if targetNamespace is not None: |
1835 if targetNamespace is not None: |
1783 self.RootNSMAP = { |
1836 self.RootNSMAP = { |
1820 self.DefaultNamespaceFormat % parent_tag |
1873 self.DefaultNamespaceFormat % parent_tag |
1821 if parent_tag is not None else parent_tag, |
1874 if parent_tag is not None else parent_tag, |
1822 None) |
1875 None) |
1823 |
1876 |
1824 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 """ |
1825 element_class = self.GetElementClass(element_tag, parent_tag) |
1892 element_class = self.GetElementClass(element_tag, parent_tag) |
1826 if isinstance(element_class, ListType): |
1893 if isinstance(element_class, ListType): |
1827 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): |
1828 new_element = element_class[class_idx]() |
1895 element_class = element_class[class_idx] |
1829 else: |
1896 else: |
1830 raise ValueError("No corresponding class found!") |
1897 raise ValueError("No corresponding class found!") |
1831 else: |
1898 return self.CreateElementFromClass(element_class, element_tag) |
1832 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() |
1833 DefaultElementClass.__setattr__(new_element, "tag", self.DefaultNamespaceFormat % element_tag) |
1925 DefaultElementClass.__setattr__(new_element, "tag", self.DefaultNamespaceFormat % element_tag) |
1834 new_element._init_() |
1926 new_element._init_() |
1835 return new_element |
1927 return new_element |
1836 |
1928 |
1837 |
1929 |
1838 def GenerateParser(factory, xsdstring): |
1930 def GenerateParser(factory, xsdstring): |
1839 """ |
1931 """ |
1840 This function generate a xml parser from a class factory |
1932 This function generate a xml parser from a class factory |
1841 """ |
1933 """ |
1842 |
1934 |
|
1935 parser = XMLClassParser(strip_cdata=False, remove_blank_text=True) |
|
1936 factory.Parser = parser |
|
1937 |
1843 ComputedClasses = factory.CreateClasses() |
1938 ComputedClasses = factory.CreateClasses() |
1844 |
|
1845 if factory.FileName is not None: |
1939 if factory.FileName is not None: |
1846 ComputedClasses = ComputedClasses[factory.FileName] |
1940 ComputedClasses = ComputedClasses[factory.FileName] |
1847 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] |
1848 |
1942 |
1849 parser = XMLClassParser( |
1943 parser.initMembers( |
1850 factory.NSMAP, |
1944 factory.NSMAP, |
1851 factory.etreeNamespaceFormat, |
1945 factory.etreeNamespaceFormat, |
1852 BaseClass[0] if len(BaseClass) == 1 else None, |
1946 BaseClass[0] if len(BaseClass) == 1 else None, |
1853 etree.XMLSchema(etree.fromstring(xsdstring)), |
1947 etree.XMLSchema(etree.fromstring(xsdstring))) |
1854 strip_cdata=False, remove_blank_text=True) |
1948 |
1855 class_lookup = XMLElementClassLookUp(factory.ComputedClassesLookUp) |
1949 class_lookup = XMLElementClassLookUp(factory.ComputedClassesLookUp) |
1856 parser.set_element_class_lookup(class_lookup) |
1950 parser.set_element_class_lookup(class_lookup) |
1857 |
1951 |
1858 return parser |
1952 return parser |