Package: paxb
Python Architecture for XML Bindingpaxbis a library that provides an API for mapping between XML documents and Python objects.paxblibrary implements the following functionality:Deserialize XML documents to Python objectsValidate deserialized dataAccess and update Python object fieldsSerialize Python objects to XML documentspaxbprovides an efficient way of mapping between an XML document and a Python object. Usingpaxbdevelopers can write less boilerplate code emphasizing on application domain logic.Sincepaxbbased onattrslibrarypaxbandattrsAPI can be mixed together.InstallationYou can install paxb with pip:$pipinstallpaxbRequirementsattrsDocumentationDocumentation is available atRead the Docs.Quick startSuppose you have an xml documentuser.xml:<?xml version="1.0" encoding="utf-8"?><doc:envelopexmlns="http://www.test.org"xmlns:doc="http://www.test1.org"><doc:username="Alex"surname="Ivanov"age="26"><doc:birthdateyear="1992"month="06"day="14"/><doc:contacts><doc:phone>+79204563539</doc:phone><doc:email>alex@gmail.com</doc:email><doc:email>alex@mail.ru</doc:email></doc:contacts><doc:documents><doc:passportseries="3127"number="836815"/></doc:documents><data:occupationsxmlns:data="http://www.test2.org"><data:occupationtitle="yandex"><data:address>Moscow</data:address><data:employees>8854</data:employees></data:occupation><data:occupationtitle="skbkontur"><data:address>Yekaterinburg</data:address><data:employees>7742</data:employees></data:occupation></data:occupations></doc:user></doc:envelope>To deserialize the document you could usexmllibrary api to parse
the document and then access and modify the parsed xml DOM manually. Such an imperative code has a lot of boilerplate
operations that takes a lot of time and can lead to bugs. Instead you can usepaxbapi to write a declarative
style code. All you need to describe field mappings and types,paxbwill serialize and deserialize data for you:importjsonimportrefromdatetimeimportdateimportattrimportpaxbaspb@pb.model(name='occupation',ns='data',ns_map={'data':'http://www.test2.org'})classOccupation:title=pb.attr()address=pb.field()employees=pb.field(converter=int)@pb.model(name='user',ns='doc',ns_map={'doc':'http://www.test1.org'})classUser:name=pb.attr()surname=pb.attr()age=pb.attr(converter=int)birth_year=pb.wrap('birthdate',pb.attr('year',converter=int))birth_month=pb.wrap('birthdate',pb.attr('month',converter=int))birth_day=pb.wrap('birthdate',pb.attr('day',converter=int))@propertydefbirthdate(self):returndate(year=self.birth_year,month=self.birth_month,day=self.birth_day)@birthdate.setterdefbirthdate(self,value):self.birth_year=value.yearself.birth_month=value.monthself.birth_day=value.dayphone=pb.wrap('contacts',pb.field())emails=pb.wrap('contacts',pb.as_list(pb.field(name='email')))passport_series=pb.wrap('documents/passport',pb.attr('series'))passport_number=pb.wrap('documents/passport',pb.attr('number'))occupations=pb.wrap('occupations',pb.lst(pb.nested(Occupation)),ns='data',ns_map={'data':'http://www.test2.org'})citizenship=pb.field(default='RU')@phone.validatordefcheck(self,attribute,value):ifnotre.match(r'\+\d{11,13}',value):raiseValueError("phone number is incorrect")withopen('user.xml')asfile:xml=file.read()Then the deserialized object can be modified and serialized back to xml document or converted to json format:try:user=pb.from_xml(User,xml,envelope='doc:envelope',ns_map={'doc':'http://www.test1.org'})user.birthdate=user.birthdate.replace(year=1993)withopen('user.json')asfile:json.dump(attr.asdict(user),file)except(pb.exc.DeserializationError,ValueError)ase:print(f"deserialization error:{e}")user.json:{"age":26,"birth_day":14,"birth_month":6,"birth_year":1993,"citizenship":"RU","emails":["alex@gmail.com","alex@mail.ru"],"name":"Alexey","occupations":[{"address":"Moscow","employees":8854,"title":"yandex"},{"address":"Yekaterinburg","employees":7742,"title":"skbkontur"}],"passport_number":"836815","passport_series":"3127","phone":"+79204563539","surname":"Ivanov"}