def render(self, parent, value, xsd_type=None, render_path=None): """Serialize the given value lxml.Element subelements on the parent element. :type parent: lxml.etree._Element :type value: Union[list, dict, zeep.xsd.valueobjects.CompoundValue] :type xsd_type: zeep.xsd.types.base.Type :param render_path: list """ if not render_path: render_path = [self.name] if not self.elements_nested and not self.attributes: return # TODO: Implement test case for this if value is None: value = {} if isinstance(value, ArrayValue): value = value.as_value_object() # Render attributes for name, attribute in self.attributes: attr_value = value[name] if name in value else NotSet child_path = render_path + [name] attribute.render(parent, attr_value, child_path) if (len(self.elements_nested) == 1 and isinstance(value, self.accepted_types) and not isinstance(value, (list, dict, CompoundValue))): element = self.elements_nested[0][1] element.type.render(parent, value, None, child_path) return # Render sub elements for name, element in self.elements_nested: if isinstance(element, Element) or element.accepts_multiple: element_value = value[name] if name in value else NotSet child_path = render_path + [name] else: element_value = value child_path = list(render_path) # We want to explicitly skip this sub-element if element_value is SkipValue: continue if isinstance(element, Element): element.type.render(parent, element_value, None, child_path) else: element.render(parent, element_value, child_path) if xsd_type: if xsd_type._xsd_name: parent.set(xsi_ns("type"), xsd_type._xsd_name) if xsd_type.qname: parent.set(xsi_ns("type"), xsd_type.qname)
def render(self, parent, value, xsd_type=None, render_path=None): if isinstance(value, AnyObject): if value.xsd_type is None: parent.set(xsi_ns("nil"), "true") else: value.xsd_type.render(parent, value.value, None, render_path) parent.set(xsi_ns("type"), value.xsd_type.qname) elif hasattr(value, "_xsd_elm"): value._xsd_elm.render(parent, value, render_path) parent.set(xsi_ns("type"), value._xsd_elm.qname) else: parent.text = self.xmlvalue(value)
def parse(self, xmlelement, schema, allow_none=False, context=None): """Process the given xmlelement. If it has an xsi:type attribute then use that for further processing. This should only be done for subtypes of the defined type but for now we just accept everything. This is the entrypoint for parsing an xml document. :param xmlelement: The XML element to parse :type xmlelements: lxml.etree._Element :param schema: The parent XML schema :type schema: zeep.xsd.Schema :param allow_none: Allow none :type allow_none: bool :param context: Optional parsing context (for inline schemas) :type context: zeep.xsd.context.XmlParserContext :return: dict or None """ context = context or XmlParserContext() instance_type = qname_attr(xmlelement, xsi_ns("type")) xsd_type = None if instance_type: xsd_type = schema.get_type(instance_type, fail_silently=True) xsd_type = xsd_type or self.type return xsd_type.parse_xmlelement( xmlelement, schema, allow_none=allow_none, context=context, schema_type=self.type, )
def parse(self, xmlelement, schema, context=None): if self.process_contents == "skip": return xmlelement # If a schema was passed inline then check for a matching one qname = etree.QName(xmlelement.tag) if context and context.schemas: for context_schema in context.schemas: if context_schema.documents.has_schema_document_for_ns(qname.namespace): schema = context_schema break else: # Try to parse the any result by iterating all the schemas for context_schema in context.schemas: try: data = context_schema.deserialize(list(xmlelement)[0]) return data except LookupError: continue # Lookup type via xsi:type attribute xsd_type = qname_attr(xmlelement, xsi_ns("type")) if xsd_type is not None: xsd_type = schema.get_type(xsd_type) return xsd_type.parse_xmlelement(xmlelement, schema, context=context) # Check if a restrict is used if self.restrict: return self.restrict.parse_xmlelement(xmlelement, schema, context=context) try: element = schema.get_element(xmlelement.tag) return element.parse(xmlelement, schema, context=context) except (exceptions.NamespaceError, exceptions.LookupError): return xmlelement
def _render_value_item(self, parent, value, render_path): """Render the value on the parent lxml.Element""" if value is Nil: elm = etree.SubElement(parent, self.qname) elm.set(xsi_ns("nil"), "true") return if value is None or value is NotSet: if self.is_optional: return elm = etree.SubElement(parent, self.qname) if self.nillable: elm.set(xsi_ns("nil"), "true") return node = etree.SubElement(parent, self.qname) xsd_type = getattr(value, "_xsd_type", self.type) if xsd_type != self.type: return value._xsd_type.render(node, value, xsd_type, render_path) return self.type.render(node, value, None, render_path)
def render(self, parent, value, render_path=None): assert parent is not None self.validate(value, render_path) if self.accepts_multiple and isinstance(value, list): from core.utilities.soap.xsd import AnySimpleType if isinstance(self.restrict, AnySimpleType): for val in value: node = etree.SubElement(parent, "item") node.set(xsi_ns("type"), self.restrict.qname) self._render_value_item(node, val, render_path) elif self.restrict: for val in value: node = etree.SubElement(parent, self.restrict.name) # node.set(xsi_ns('type'), self.restrict.qname) self._render_value_item(node, val, render_path) else: for val in value: self._render_value_item(parent, val, render_path) else: self._render_value_item(parent, value, render_path)
def parse_xmlelement(self, xmlelement, schema=None, allow_none=True, context=None, schema_type=None): """Consume matching xmlelements and call parse() on each :param xmlelement: XML element objects :type xmlelement: lxml.etree._Element :param schema: The parent XML schema :type schema: zeep.xsd.Schema :param allow_none: Allow none :type allow_none: bool :param context: Optional parsing context (for inline schemas) :type context: zeep.xsd.context.XmlParserContext :param schema_type: The original type (not overriden via xsi:type) :type schema_type: zeep.xsd.types.base.Type :rtype: dict or None """ xsi_type = qname_attr(xmlelement, xsi_ns("type")) xsi_nil = xmlelement.get(xsi_ns("nil")) children = list(xmlelement) # Handle xsi:nil attribute if xsi_nil == "true": return None # Check if a xsi:type is defined and try to parse the xml according # to that type. if xsi_type and schema: xsd_type = schema.get_type(xsi_type, fail_silently=True) # If we were unable to resolve a type for the xsi:type (due to # buggy soap servers) then we just return the text or lxml element. if not xsd_type: logger.debug( "Unable to resolve type for %r, returning raw data", xsi_type.text) if xmlelement.text: return xmlelement.text return children # If the xsd_type is xsd:anyType then we will recurs so ignore # that. if isinstance(xsd_type, self.__class__): return xmlelement.text or None return xsd_type.parse_xmlelement(xmlelement, schema, context=context) # If no xsi:type is set and the element has children then there is # not much we can do. Just return the children elif children: return children elif xmlelement.text is not None: return self.pythonvalue(xmlelement.text) return None