私はその間に解決策を見つけました。うまくいけば、これは他の誰かに役立ちます。このソリューションは、ドット名前空間呼び出しからネストされたディクショナリ オブジェクトを作成し、それを XML に変換します。
from xml.dom.minidom import Document
import copy
import re
from collections import OrderedDict
class d2x:
''' Converts Dictionary to XML '''
def __init__(self, structure):
self.doc = Document()
if len(structure) == 1:
rootName = str(structure.keys()[0])
self.root = self.doc.createElement(rootName)
self.doc.appendChild(self.root)
self.build(self.root, structure[rootName])
def build(self, father, structure):
if type(structure) == dict:
for k in structure:
tag = self.doc.createElement(k)
father.appendChild(tag)
self.build(tag, structure[k])
elif type(structure) == OrderedDict:
for k in structure:
tag = self.doc.createElement(k)
father.appendChild(tag)
self.build(tag, structure[k])
elif type(structure) == list:
grandFather = father.parentNode
tagName = father.tagName
grandFather.removeChild(father)
for l in structure:
tag = self.doc.createElement(tagName)
self.build(tag, l)
grandFather.appendChild(tag)
else:
data = str(structure)
tag = self.doc.createTextNode(data)
father.appendChild(tag)
def display(self):
# I render from the root instead of doc to get rid of the XML header
#return self.root.toprettyxml(indent=" ")
return self.root.toxml()
class SolaceNode:
''' a sub dictionary builder '''
def __init__(self):
self.__dict__ = OrderedDict()
def __getattr__(self, name):
name = re.sub("_", "-", name)
try:
return self.__dict__[name]
except:
self.__dict__[name] = SolaceNode()
return self.__dict__[name]
def __str__(self):
return str(self.__dict__)
def __repr__(self):
return str(self.__dict__)
def __call__(self, *args, **kwargs):
return self.__dict__
def __setattr__(self, name, value):
name = re.sub("_", "-", name)
self.__dict__[name] = value
class SolaceXMLBuilder(object):
''' main dictionary builder
Any dot-name-space like calling of a instance of SolaceXMLBuilder will create
nested dictionary keys. These are converted to XML whenever the instance
representation is called ( __repr__ )
Example
a=SolaceXMLBuilder()
a.foo.bar.baz=2
str(a)
'<rpc semp-version="soltr/5_5">\n<foo><bar><baz>2</baz></bar></foo></rpc>'
'''
def __init__(self):
self.__dict__ = OrderedDict()
self.__setattr__ = None
def __getattr__(self, name):
name = re.sub("_", "-", name)
try:
return self.__dict__[name]
except:
self.__dict__[name] = SolaceNode()
return self.__dict__[name]
def __repr__(self):
# Show XML
myxml = d2x(eval(str(self.__dict__)))
# I had to conjur up my own header cause solace doesnt like </rpc> to have attribs
#return str('<rpc semp-version="soltr/5_5">\n%s</rpc>' % myxml.display())
return str('<rpc semp-version="soltr/5_5">\n%s</rpc>' % myxml.display())
def __call__(self, *args, **kwargs):
return self.__dict__
# def __setattr__(self, name, value):
# raise Exception('no you cant create assignments here, only on sub-elements')
if __name__ == '__main__':
x = SolaceXMLBuilder()
x.create.message_vpn.vpn_name='NEWVPN'
print(x)
# <?xml version="1.0" ?>
# <rpc semp-version="soltr/5_5">
# <create>
# <message-vpn>
# <vpn-name>
# NEWVPN
# </vpn-name>
# </message-vpn>
# </create>
# </rpc semp-version="soltr/5_5">
x=SolaceXMLBuilder()
x.message_vpn.vpn_name='NEWVPN'
x.message_vpn.no.feature_X
print(x)
# <?xml version="1.0" ?>
# <rpc semp-version="soltr/5_5">
# <message-vpn>
# <vpn-name>
# NEWVPN
# </vpn-name>
# <no>
# <feature-X/>
# </no>
# </message-vpn>
# </rpc semp-version="soltr/5_5">
# >>> client = SolaceAPI('pt1')
# >>> xml = SolaceXMLBuilder()
# >>> xml.create.message_vpn.vpn_name='NEWVPN'
# >>> client.rpc(str(xml))
# {u'rpc-reply': {u'execute-result': {u'@code': u'ok'}, u'@semp-version': u'soltr/5_5'}}