Package: pysxm
pysxmis a simple and extensible xml python marshaller.
It comes with two simple and basic types:SimpleTypeComplexTypeIt supports py2 and py3 and useslxml.objectifyunder the hood.InstallationpipinstallpysxmQuickstartIn[1]:frompysxmimportComplexTypeIn[2]:classPerson(ComplexType):...:attrib={'description':'a random person'}...:def__init__(self,fname,lname):...:self.fname=fname...:self.lname=lname...:In[3]:person=Person('token','black')In[4]:print(person)<personxmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"description="a random person"><lname>black</lname><fname>token</fname></person>Let’s say, we want a differenttagfor our object.
An attributetagnameor_tagnamecan be set to define thexml tag nameof the object.In[5]:classPerson(ComplexType):...:attrib={'description':'a random person'}...:tagname='student'...:def__init__(self,fname,lname):...:self.fname=fname...:self.lname=lname...:In[6]:person=Person('token','black')In[7]:print(person)<studentxmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"description="a random person"><lname>black</lname><fname>token</fname></student>Asequenceor_sequence(tuple or list) attribute can be set to decide of theorderor thepresenceof an subelement in the xml.In[8]:classPerson(ComplexType):...:attrib={'description':'a random person'}...:tagname='student'...:_sequence=('city','fname')...:...:def__init__(self,fname,lname,city):...:self.fname=fname...:self.lname=lname...:self.city=city...:In[9]:person=Person('token','black','south park')In[10]:print(person)<studentxmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"description="a random person"><city>southpark</city><fname>token</fname></student>Let’s add anamespaceto our object.In[11]:classPerson(ComplexType):...:attrib={'description':'a random south park character'}...:nsmap={'sp':'http://southpark/xml/'}...:...:def__init__(self,fname,lname,city):...:self.fname=fname...:self.lname=lname...:self.city=city...:In[12]:person=Person('token','black','south park')In[13]:print(person)<sp:personxmlns:sp="http://southpark/xml/"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"description="a random south park character"><sp:lname>black</sp:lname><sp:city>southpark</sp:city><sp:fname>token</sp:fname></sp:person>Let’s make sure that aperson’s group is eithercoonorgoth.
To do so, we can inherit fromSimpleTypeobject and define a restriction by overridingcheck_restriction(self, value)method.In[7]:frompysxmimportComplexType,SimpleTypeIn[8]:classGroup(SimpleType):...:allowed_groups=('coon','goth')...:defcheck_restriction(self,value):...:ifvaluenotinself.allowed_groups:...:raiseValueError('<%s> value%snot in%s'%(self.tagname,value,self.allowed_groups))...:In[9]:classPerson(ComplexType):...:def__init__(self,fname,lname,group):...:self.fname=fname...:self.lname=lname...:self.group=Group(group)...:In[10]:Person('token','black','boys')...<ipython-input-8-116b49042116>incheck_restriction(self,value)3defcheck_restriction(self,value):4ifvaluenotinself.allowed_groups:---->5raiseValueError('<%s> value%snot in%s'%(self.tagname,value,self.allowed_groups))6ValueError:<group>valueboysnotin('coon','goth')In[11]:print(Person('token','black','goth'))<personxmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><lname>black</lname><group>goth</group><fname>token</fname></person>Note:ComplexTypecan haveComplexTypeandSimpleTypeas attributefrompysxmimportComplexType,SimpleTypeclassAdultAge(SimpleType):tagname='age'attrib={'minvalue':'18','maxvalue':'100'}defcheck_restriction(self,value):ifint(value)<18:raiseValueError("<%s> '%d' < 18"%(self.tagname,value))classCredentials(ComplexType):def__init__(self,login,password):self.login=loginself.password=passwordclassPerson(ComplexType):def__init__(self,fname,lname,credentials,age):self.fname=fnameself.lname=lnameself.credentials=Credentials(credentials['login'],credentials['password'])self.age=AdultAge(age)In[3]:data={...:'fname':'token','lname':'black',...:'credentials':{'login':'t0ken','password':'l33tolite'},...:'age':'30'}In[4]:person=Person(**data)In[5]:print(person)<personxmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><lname>black</lname><credentials><login>t0ken</login><password>l33tolite</password></credentials><agemaxvalue="100"minvalue="18">30</age><fname>token</fname></person>In[6]:person.save('token.xml')Thesavemethod (object.save(<filename>)) allows you to save the xml result into a file.In[7]:cattoken.xml<personxmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><lname>black</lname><credentials><login>t0ken</login><password>l33tolite</password></credentials><agemaxvalue="100"minvalue="18">30</age><fname>token</fname></person>The ext modulePysxm comes with a couple of extended types. Those types are defined inpysxm.extmodule.DataComplexTypeThis is a simpleDataClassofComplexType. Here is how you can set one up:frompysxm.extimportDataComplexType,XSimpleTypeclassGame(DataComplexType):platform=XSimpleType('platform',['xboxone','xboxx'],lambdav,av:vinav)>>>game=Game(name='state of decay 2',editor='undead labs',platform='xboxone')>>>print(game)<game><name>stateofdecay2</name><platform>xboxone</platform><editor>undeadlabs</editor></game>XSimpleTypeIt gets tiresome to subclass aSimpleTypeeverytime you want to check a value. To overcome that,pysxmprovides adescriptorcalledXSimpleType:classXSimpleType(object):def__init__(name=None,restriction=None,checker=None,error_msg=None,**kwargs):'''name: it's the name of the attribute.
    restriction: self explanatory
    checker: the fucntion that checks the input value
    error_msg: message returned when checking fails
    kwargs: as tagname, attrib or nsmap
    '''Here is an example:classXboxGamer(ComplexType):platform=XSimpleType('platform',('xone','xbox360','xbox'),lambdav,av:vinav)score=XSimpleType('score',(4000,1000000),lambdav,av:int(av[0])<=int(v)<int(av[1]))lastlogin=XDateTimeType('lastlogin')def__init__(self,gamertag,platform,score,lastlogin):self.gamertag=gamertagself.platform=platformself.score=scoreself.lastlogin=lastloginIn[1]:print(gamer_data){'gamertag':'LokingHD','platform':'ps4','score':'22526','lastlogin':'2018-03-21'}In[2]:XboxGamer(**gamer_data)---------------------------------------------------------------------------ValueErrorTraceback(mostrecentcalllast)<ipython-input-2-61f95466da46>in<module>()---->1XboxGamer(**gamer_data)/home/josue/workspace/dev/pysxdb/pysxm/ext.pycincheck(self,instance,value)77ifnotself.checker(value,self.restriction_values):78raiseValueError('tagname <%s> value%sis invalid: expected (%s)'--->79%(instance.tagname,value,self.restriction_values))8081defcheck_restriction(self,instance,value):ValueError:tagname<xboxgamer>valueps4isinvalid:expected(('xone','xbox360','xbox'))In[3]:gamer_data['platform']='xone'In[4]:gamer=XboxGamer(**gamer_data)In[5]:print(gamer)<xboxgamerxmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><gamertag>LokingHD</gamertag><platform>xone</platform><score>22526</score><lastlogin>2018-03-21T00:00:00</lastlogin></xboxgamer>Most of the types defined inpysxm.extare descriptors and they’re subclassable.Voila :wink: