解析SOAP通知

2024-09-30 05:25:15 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一个设备,它定期向我的计算机上运行的HTTP服务器发送SOAP通知。通知如下所示:

<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
    <SOAP-ENV:Body>
        <Notify>
            <DeviceNotification message= "
                    <NotificationEvent NotificationType="Location">
                            <ComputerLocation changedOn="1369757031051">
                            </ComputerLocation>
                    </NotificationEvent>
                "/>
        </Notify>
    </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

它是一个SOAP信封,包含一个DeviceNotification类型实例的XML表示。在

我真的不知道如何处理这些通知(好像我的程序是一个服务器?客户?)。通知看起来更像是对命令的响应,但实际上我没有调用任何远程服务(发送通知的机器有一个web界面,我在其中输入“通知的目的地:this ip,this port”并开始发送它们),我也不确定通知中的SOAP是否完全正确。在

我试过几个SOAP库之类的。。。我认为我能做到的最接近的事情是使用spyne(或者可能只是一个海市蜃楼,我认为这是因为它输出的东西比其他的librer要多)

^{pr2}$

但从未调用Notify函数。我得到:

192.168.1.33 - - [28/May/2013 21:16:52] "POST / HTTP/1.1" 404 130
DEBUG:spyne.server.wsgi:Method name: '{}'
DEBUG:spyne.protocol.http:  header : {'soapaction': ['Notify'], 'host': ['niuyorker.jome:7171'], 'user_agent': ['Jakarta Commons-HttpClient/3.1']

这是我得到的最接近的东西。那个SOAP消息正确吗?如果是,以及这应该被视为对服务器(我的服务器)的请求还是响应(因此,我的应用程序将是一个客户端)。如果有人知道在哪里找到Python和SOAP的例子比加两个数字或多次打“Hello”要复杂一点,这也会有帮助?在

我想我可以一直使用lxml来解析整个SOAP消息,但是如果可能的话,我想做得更“专业”。以防万一你没注意到:我对SOAP服务完全是新手!:)

提前谢谢你!在

更新:

看起来消息部分实际上应该是转义XML,这。。。好。。。这是我从一开始就得到的,但是(我是新手)我逃过了,所以在这个问题上它看起来更漂亮。真正的是:

 <soap-env:envelope xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/">
 <soap-env:body>
  <notify>
   <notification message='&lt;NotificationEvent NotificationType="Location"&gt;&lt;DeviceLocation changedOn="1369074622065"&gt;&lt;/DeviceLocation&gt;&lt;/NotificationEvent&gt;'>
   </notification>
  </notify>
 </soap-env:body>
</soap-env:envelope>

我有WSDL。使用suds我已经能够创建'ComputerLocation'类型的实例,类似于:

>>> from suds.client import Client
>>> url="file:///tmp/service.wsdl"
>>> c=Client(url)
>>> c.factory.create('DeviceLocation')
(DeviceLocation){
   _changedOn = ""
 }

但这几乎就是我能做的。在

老实说,我还是不知道我需要服务器还是客户端。。。在


Tags: ltgt服务器envhttpnotifysoapenvelope
2条回答

您提供的XML完全是胡说八道。我相信您不会找到任何能够处理这些问题的XML解析器。为了使XML格式良好,DeviceNotification元素的message属性中的所有内容都需要转义。在

首先,属性值中不能有左尖括号。这显然违反了格式约束:http://www.w3.org/TR/REC-xml/#CleanAttrVals

即使你已经过去了,当属性值已经用双引号括起来时,显然不能在属性中使用双引号。在解析器看来,NotificationType属性的左引号是message属性的右引号。在

坦白地说,我认为您能做的最好的就是尝试用某种正则表达式从中提取数据。它不是XML,因此也不是SOAP。在

更新

随着问题的更新,现在很明显,XML的一些可怕之处只是一个格式问题,所以我上面所说的并不适用。不过,在属性中嵌入XML的概念仍然是荒谬的。在

在回答这个问题时,你是一个服务器还是一个客户机,从技术上讲,你是客户机。但是,由于这是一种通知模式,所以您是消息的接收者而不是发送者(对于客户端来说,这通常是这样)。在

通常对于这种情况,我希望您向服务器发送一条消息,请求通知并提供接收这些通知的端点。在本例中,您已经通过一个单独的web界面完成了所有这些。在

因此,剩下的就是让你接收消息,在这个角色上你更像是一个服务器。我可能错了,但我认为您应该使用SOAP库的服务器功能。在

您使用的是in_protocol=HttpRpc,而不是in_protocol=Soap11。在

^{} protocol简单地定义为:

The so-called ReST-ish HttpRpc protocol implementation.

虽然还不完全清楚这意味着什么,但可以肯定的是,不会试图解析soap1.1消息来查找命令,因为这离REST-ish还不远。在


克服了这一点,并给出了更新的(正确的)示例:

它被解析为有效的XML,并且位于有效的soap1.1信封中。在

但它仍然不是好肥皂。主体的内容没有名称空间,也不是带参数的结构化对象。事实上,整个内容是一个通用的XML树,实际的内容是另一个通用XML树,它作为外部树中节点的属性以转义形式存储。在

从您的一个示例的外观来看,我猜URL路径总是/,而SOAP结构始终只是SOAP信封中的一个Notify。当然,如果您对框架进行了足够的斗争,您可能可以让它在Notify上分派,但是无论如何,您的所有消息都将在同一个位置结束,所以…为什么要麻烦呢?如果有的话,您可能希望分派的对象是嵌入XML中的内容,比如NotificationType。在

如果这些猜测是正确的,那么就选择您知道如何使用的最熟悉的web服务器,您甚至不需要WSGI;如果您愿意的话,只需为http.server.HTTPServer编写一个简单的处理程序,并将每个消息路由到同一个代码,这只需进行足够的解析,就可以到达NotificationEvent对象并从中进行分派。像这样:

from xml.etree import ElementTree as ET

def handle_location(nevent):
    clocation = nevent.find('ComputerLocation')
    changed_on = clocation.attrib['changedOn']
    location = clocation.text
    # do something with this info

def handle_other_thing(nevent):
    # whatever

handlers = {'Location': handle_location,
            'OtherThing': handle_other_thing }

et = ET.fromstring(body)
for notification in et.iter('notification'):
    message = ET.fromstring(notification.attrib['message'])
    for nevent in message.iter('NotificationEvent'):
        ntype = nevent.attrib['NotificationType']
        handlers[ntype](nevent)

听起来您可能在NotificationEvent中为最低级别的字段提供了WSDL,因此一旦到达该级别,您就可以使用suds来代替手动解析etree,前提是这样可以使您的生活更轻松或使代码更灵活。在

当然,您还需要添加一些错误处理。在

相关问题 更多 >

    热门问题