1

我有一个我正在自动化管理的 Solace JMS 消息框,并且该设备使用许多非常小的 XML 帖子进行配置。由于该设备在其 XML 规范中有非常多的命令,因此我需要一种创建任意 XML 请求的方法。

XML 看起来像:

<rpc semp-version="soltr/5_5">
<create>
<message-vpn>
<vpn-name>developer.testvpn</vpn-name>
</message-vpn>
</create>
</rpc>

第二次调用更改设置可能如下所示:

<rpc semp-version="soltr/5_5">
<message-vpn>
<vpn-name>developer.testvpn</vpn-name>
<export-policy>
<no>
<export-subscriptions/>
</no>
</export-policy>
</message-vpn>
</rpc>

由于 XML 规范中有许多命令,我正在寻找一种方法来从点名称空间之类的东西中自由地创建它们。例如:

mycall = SolaceXML()
mycall.create.message_vpn.vpn_name="developer.testvpn"
mycall.message_vpn.vpn_name='developer.testvpn'
mycall.message_vpn.export_policy.no.export_subscription

更新 我在下面发布了我的解决方案。它不像我想要的那么小,但它对我有用。

ķ

4

1 回答 1

0

与此同时,我找到了解决方案。希望这对其他人有帮助。此解决方案从点名称空间调用构建嵌套字典对象,然后将其转换为 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'}}
于 2012-11-30T14:42:30.327 回答