Package: xml-serializer
XML SerializerAllows you to convert XML to python dict (with python objects) using a schema.ExamplesWe have next xml data (profiles.xml)<?xml version="1.0" encoding="UTF-8"?><payload><MyProfile><recordid="1"nickname="eff1c"admin="true"><poststopic="something"><postname="test post"description="It's my test post."/><postname="python xml_serializer"description="It's very useful module!"/></posts></record></MyProfile></payload>And we want to turn it into{"payload":{"my_profile":{"record":{"id":1,"nickname":"eff1c","admin":True,"posts":{"topic":"something","post":[{"name":"test post","description":"It's my test post."},{"name":"python xml_serializer","description":"It's very useful module!",},],},}}}}We will write next schemafromxml_serializerimportTag,TagAttrfromxml_serializer.converter_typesimportInteger,String,Booleanprofiles_schema={Tag("payload"):{Tag("MyProfile","my_profile"):{Tag("record"):{TagAttr("id"):Integer(nullable=False),TagAttr("nickname"):String(nullable=False),TagAttr("admin"):Boolean(),Tag("posts"):{TagAttr("topic"):String(nullable=False),Tag("post"):[{TagAttr("name"):String(),TagAttr("description"):String()}]}}}}Get etree element (tag)fromxml.etreeimportElementTreeasetreetree=etree.parse("profiles.xml")root=tree.getroot()# you can use root tag or find any elsemain_tag=root.find("payload")And call the method to pass them tofromxml_serializerimportxml_serializeresponse=xml_serialize(profiles_schema,main_tag)SchemaTag/TagAttrIn order to serialize data, you need to describe the scheme of its structure.To do this, we create a python dict with Tag/TagAttr object keys.The value for Tag is a set of TagAttr-s or Tag.
I think it's clear that TagAttr is an attribute of the current tag, and Tag is actually a nested tag.fromxml_serializerimportTag,TagAttrfromxml_serializer.converter_typesimportStringschema={Tag("posts"):{TagAttr("topic"):String(nullable=False),Tag("post"):[{TagAttr("name"):String(),TagAttr("description"):String()}]}}Both Tag and TagAttr have 2 parameters: field_name and name.field_name- it is name in xml.name- it is our custom name with which the object will return to us after serialization (by default- field_name).Field data typesTo convert TagAttr values, we use data types:String,Integer,Float,Boolean,NestedType.String,Integer,Float,Booleanare similar to common data types (as in python).
All of them have thenullableparameter (Trueby default).When set toFalse, if the tag does not have this attribute in the input data, an error will be raisedNestedTypeIt is a data type that allows you to intercept serialization in the middle of a schema and
process the resulting data according to your needs.In order to use it, we have to describe the nested schema separately
and create a function that will process the data received from it.NestedType has 2 attributes for it:schemaanddata_handling_functionfromxml_serializerimportTag,TagAttrfromxml_serializer.converter_typesimportBoolean,String,NestedTypeposts_schema={Tag("post","posts"):[{TagAttr("name"):String(),TagAttr("description"):String()}]}defget_post_names(data):posts=data["posts"]return[post["name"]forpostinposts]schema_with_nesting={Tag("record"):{TagAttr("admin"):Boolean(),Tag("posts","post_names"):NestedType(posts_schema,get_post_names)}}In this example, we return only a list of post-s names to the posts tag, discarding all the information we don't need.
This way, NestedType allows you to modify the output data schema without unnecessary iterations.Custom typeYou can create your own field data types. UseAbstractTypefor it.fromxml_serializer.abstract_typeimportAbstractTypeclassBoolean(AbstractType):defconvert_method(self,value):returnTrueifvalue.lower()=="true"elseFalse