--- a/xmlclass/xmlclass.py Fri Aug 24 13:25:05 2018 +0300
+++ b/xmlclass/xmlclass.py Fri Aug 24 13:41:43 2018 +0300
@@ -618,8 +618,9 @@
element_name = factory.etreeNamespaceFormat % infos["name"]
if infos["elmt_type"]["type"] == SIMPLETYPE:
- value = etree.Element(element_name)
+ value = factory.Parser.makeelement(element_name) value.text = (infos["elmt_type"]["generate"](infos["elmt_type"]["initial"]()))
@@ -776,6 +777,7 @@
self.SchemaNamespace = None
self.TargetNamespace = None
self.etreeNamespaceFormat = "%s"
self.CurrentCompilations = []
@@ -1162,7 +1164,6 @@
classmembers["get%s" % elmtname] = generateGetMethod(elmtname)
classmembers["_init_"] = generateInitMethod(self, classinfos)
- classmembers["_tmp_initial_"] = None
classmembers["StructurePattern"] = GetStructurePattern(classinfos)
classmembers["getElementAttributes"] = generateGetElementAttributes(self, classinfos)
classmembers["getElementInfos"] = generateGetElementInfos(self, classinfos)
@@ -1174,9 +1175,8 @@
"type": COMPILEDCOMPLEXTYPE,
- "initial": generateClassCreateFunction(class_definition),
+ "initial": generateClassCreateFunction(self, class_definition),
if self.FileName is not None:
self.ComputedClasses[self.FileName][classname] = class_definition
@@ -1269,12 +1269,12 @@
raise ValueError("XSD structure not yet supported!")
-def generateClassCreateFunction(class_definition):
+def generateClassCreateFunction(factory, class_definition): Method that generate the method for creating a class instance
def classCreatefunction():
- return class_definition()
+ return factory.Parser.CreateElementFromClass(class_definition) return classCreatefunction
@@ -1387,7 +1387,7 @@
for element in reversed(value):
if element_infos["elmt_type"]["type"] == SIMPLETYPE:
- tmp_element = etree.Element(factory.etreeNamespaceFormat % name)
+ tmp_element = factory.Parser.makeelement(factory.etreeNamespaceFormat % name) tmp_element.text = element_infos["elmt_type"]["generate"](element)
self.insert(insertion_point, element)
@@ -1582,10 +1582,6 @@
if element["type"] != CHOICE:
initial = GetElementInitialValue(factory, element)
- # FIXME: this is looks like dirty hack to fix strange problem with initial[0]
- # changing its type after returning from _init_ method to lxml.etree._Element
- # As a result all methods generated by class factory are lost.
- object.__setattr__(self, "_tmp_initial_", initial)
map(self.append, initial)
@@ -1747,6 +1743,8 @@
def __init__(self, classes, *args, **kwargs):
etree.PythonElementClassLookup.__init__(self, *args, **kwargs)
self.LookUpClasses = classes
+ self.ElementClass = None def GetElementClass(self, element_tag, parent_tag=None, default=DefaultElementClass):
element_class = self.LookUpClasses.get(element_tag, (default, None))
@@ -1760,7 +1758,56 @@
return self.GetElementClass(element_with_parent_class, default=default)
return element_with_parent_class
+ def SetLookupResult(self, element, element_class): + Set lookup result for the next 'lookup' callback made by lxml backend. + Lookup result is used only if element matches with tag's name submited to 'lookup'. + This is done, because there is no way to submit extra search parameters for + etree.PythonElementClassLookup.lookup() from etree.XMLParser.makeelement() + It's valid only for a signle 'lookup' call. + element class that should be returned on + match in the next 'lookup' call. + self.ElementTag = element + self.ElementClass = element_class + def ResetLookupResult(self): + """Reset lookup result, so it don't influence next lookups""" + self.ElementClass = None + def GetLookupResult(self, element): + """Returns previously set SetLookupResult() lookup result""" + if self.ElementTag is not None and self.ElementTag == element.tag: + element_class = self.ElementClass + self.ResetLookupResult() def lookup(self, document, element):
+ Lookup for element class for given element tag. + If return None from this method, the fallback is called. + opaque document instance that contains the Element + lightweight Element proxy implementation that is only valid during the lookup. + Do not try to keep a reference to it. + Once the lookup is done, the proxy will be invalid. + Returns element class corresponding to given element. + element_class = self.GetLookupResult(element) + if element_class is not None: parent = element.getparent()
element_class = self.GetElementClass(
element.tag, parent.tag if parent is not None else None)
@@ -1778,9 +1825,10 @@
class XMLClassParser(etree.XMLParser):
+ def __init__(self, *args, **kwargs): + etree.XMLParser.__init__(self, *args, **kwargs) - def __init__(self, namespaces, default_namespace_format, base_class, xsd_schema, *args, **kwargs):
- etree.XMLParser.__init__(self, *args, **kwargs)
+ def initMembers(self, namespaces, default_namespace_format, base_class, xsd_schema): self.DefaultNamespaceFormat = default_namespace_format
targetNamespace = etree.QName(default_namespace_format % "d").namespace
@@ -1827,14 +1875,53 @@
def CreateElement(self, element_tag, parent_tag=None, class_idx=None):
+ Create XML element based on elements and parent's tag names. + optional parent's tag name. Default value is None. + optional index of class in list of founded classes + with same element and parent. Default value is None. + (subclass of lxml.etree._Element created by class factory) element_class = self.GetElementClass(element_tag, parent_tag)
if isinstance(element_class, ListType):
if class_idx is not None and class_idx < len(element_class):
- new_element = element_class[class_idx]()
+ element_class = element_class[class_idx] raise ValueError("No corresponding class found!")
- new_element = element_class()
+ return self.CreateElementFromClass(element_class, element_tag) + def CreateElementFromClass(self, element_class, element_tag=None): + Create XML element instance of submitted element's class. + Submitted class should be subclass of lxml.etree._Element. + element_class shouldn't be used to create XML element + directly using element_class(), because lxml backend + should be aware what class handles what xml element, + otherwise default lxml.etree._Element will be used. + optional element's tag name. + If omitted it's calculated from element_class instance. + (subclass of lxml.etree._Element created by class factory) + if element_tag is None: + element_tag = element_class().tag + etag = self.DefaultNamespaceFormat % element_tag + self.ClassLookup.SetLookupResult(etag, element_class) + new_element = self.makeelement(etag) + self.ClassLookup.ResetLookupResult() DefaultElementClass.__setattr__(new_element, "tag", self.DefaultNamespaceFormat % element_tag)
@@ -1845,18 +1932,20 @@
This function generate a xml parser from a class factory
+ parser = XMLClassParser(strip_cdata=False, remove_blank_text=True) + factory.Parser = parser ComputedClasses = factory.CreateClasses()
if factory.FileName is not None:
ComputedClasses = ComputedClasses[factory.FileName]
BaseClass = [(name, XSDclass) for name, XSDclass in ComputedClasses.items() if XSDclass.IsBaseClass]
- parser = XMLClassParser(
factory.etreeNamespaceFormat,
BaseClass[0] if len(BaseClass) == 1 else None,
- etree.XMLSchema(etree.fromstring(xsdstring)),
- strip_cdata=False, remove_blank_text=True)
+ etree.XMLSchema(etree.fromstring(xsdstring))) class_lookup = XMLElementClassLookUp(factory.ComputedClassesLookUp)
parser.set_element_class_lookup(class_lookup)