如何在使用 suds 创建的 SOAP 请求中的属性上强制使用命名空间前缀

nmt*_*ken 2 python attributes soap namespaces suds

我正在使用 python suds(版本:0.3.9 GA build:R659-20100219)与具有以下结构的 SOAP 服务交互:

服务 (DPWSService) tns="http://ejb.revitalization.services.ndg/"
前缀 (1)
ns0 = "http://ejb.revitalization.services.ndg/"
端口 (1):
(DPWS端口)
方法(13):
addTimer(请求请求,)
deleteProvider(请求请求,)
deleteTimer(请求请求,)
doHarvest(请求请求,)
doIngest(请求请求,)
doNewUpdateProvider(请求请求,)
getHarvestHistory(GetHistoryRequest 请求, )
getIngestHistory(GetHistoryRequest 请求,)
getList(GetListType 请求,)
获取列表名称()
getProviderDetails(请求请求,)
getProviderStatistic(请求请求,)
getStatusProcess(请求请求,)
类型 (63):
添加定时器响应
CSWProviderDetailsType
确认类型
联系人类型
数据范围类型
删除提供者响应
删除定时器响应
收获响应
摄取响应
DoNewUpdateProviderResponse
电子邮件联系人类型
获取HarvestHistoryResponse
获取历史请求
获取摄取历史响应
获取列表名称响应
获取列表响应
获取列表类型
获取进程状态响应
获取提供者详细信息响应
获取提供者统计响应
收获历史类型
HarvestProvider 类型
收获类型
摄取历史类型
列表名称
OAI提供者详细信息类型
进程ID类型
ProviderCommonType
ProviderContactType
提供者详细信息
提供者详细信息类型
提供者ID类型
提供者统计
响应类型
定时器信息通用类型
定时器信息详细信息
定时器信息日志详细信息
添加定时器
添加定时器响应
删除提供者
删除提供者响应
删除定时器
删除定时器响应
doHarvest
doHarvestResponse
做摄取
做摄取响应
doNewUpdateProvider
doNewUpdateProviderResponse
获取收获历史
getHarvestHistoryResponse
获取历史记录
getIngestHistoryResponse
获取列表
获取列表名称
获取列表名称响应
获取列表响应
获取提供者详细信息
获取提供者详细信息响应
获取提供者统计信息
获取提供者统计响应
获取状态进程
获取状态处理响应

我需要发送一个结构如下的 SOAP 请求:

<SOAP-ENV:Envelope xmlns:ns0="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://
ejb.revitalization.services.ndg/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Header/>
<ns0:Body>
<ns1:doIngest>
<request>
<ns1:ProcessID ns1:id="1430"/>
<ns1:EmailReportID>1031</ns1:EmailReportID>
</request>
</ns1:doIngest>
</ns0:Body>
</SOAP-ENV:Envelope>
Run Code Online (Sandbox Code Playgroud)

也就是说,我需要在 id 属性前面附加目标命名空间。如果我不请求失败:(

我尝试了几种方法来创建我的 doIngest 请求对象,但我只能创建一个如下所示的请求:

<SOAP-ENV:Envelope xmlns:ns0="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://ejb.revitalization.services.ndg/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Header/>
<ns0:Body>
<ns1:doIngest>
<request>
<ns1:ProcessID id="1441"/>
<ns1:EmailReportID>1031</ns1:EmailReportID>
</request>
</ns1:doIngest>
</ns0:Body>
</SOAP-ENV:Envelope>
Run Code Online (Sandbox Code Playgroud)

也就是说,在 id 属性上没有目标命名空间前缀。

我尝试过以下变体:

request = wsClient.factory.create('doIngest.request')
request.EmailReportID = "1031"
request.ProcessID = wsClient.factory.create('ProcessIDType')
request.ProcessID._id= "1430"
result=wsClient.service.doIngest(request)
Run Code Online (Sandbox Code Playgroud)

和:

request = wsClient.factory.create('{http://ejb.revitalization.services.ndg/}doIngest.request')
request.EmailReportID = "1031"
request.ProcessID = wsClient.factory.create('{http://ejb.revitalization.services.ndg/}ProcessIDType')
request.ProcessID._id="1430"
result=wsClient.service.doIngest(request)
Run Code Online (Sandbox Code Playgroud)

和:

request = wsClient.factory.create('doIngest.request')
request.EmailReportID = emailIDs
request.ProcessID = wsClient.factory.create('ProcessIDType')
request.ProcessID._id = wsClient.factory.resolver.qualify('{http://ejb.revitalization.services.ndg/}_id')
request.ProcessID._id=procID
result=wsClient.service.doIngest(request)
Run Code Online (Sandbox Code Playgroud)

但我收到了相同的 SOAP 请求

WSDL 告诉我:

<xs:complexType name="doIngest">
    <xs:sequence>
        <xs:element form="unqualified" minOccurs="0" name="request">
            <xs:complexType>
                <xs:sequence>
                    <xs:element minOccurs="0" name="ProcessID" type="tns:ProcessIDType"/>
                    <xs:element maxOccurs="unbounded" minOccurs="0" name="EmailReportID" type="xs:int"/>
                </xs:sequence>
            </xs:complexType>
        </xs:element>
    </xs:sequence>
</xs:complexType>
Run Code Online (Sandbox Code Playgroud)

<xs:complexType name="ProcessIDType">
    <xs:sequence/>
    <xs:attribute ref="tns:id" use="required"/>
    <xs:attribute ref="tns:status"/>
</xs:complexType>
Run Code Online (Sandbox Code Playgroud)

这表明 id 确实需要命名空间前缀。

因此,问题是,如何将命名空间前缀强制添加到我的 id 属性上?

感谢甘地

因此,解决方案是:

将 Suds 更新为 0.4(因为 MessagePlugin 在版本:0.3.9 中不可用)

然后:

class MyPlugin(MessagePlugin):
    def marshalled(self, context):
        ProcIDnode = context.envelope.getChild('Body').getChild('doIngest').getChild('request')[0]
        #Get the value of the id attribute  
        ProcIDattVal = ProcIDnode.get('id')
        #Remove the errant id, used as a tidy-up stage
        ProcIDnode.unset('id')
        #Get the namespace prefix for the target namespace 
        ProcIDnspref = ProcIDnode.findPrefix('http://ejb.revitalization.services.ndg/')
        #Create the new attribute name with namespace prefix applied
        newProcIDattname = ProcIDnspref + ':id'
        #Insert the new attribute.
        ProcIDnode.set(newProcIDattname,ProcIDattVal)
Run Code Online (Sandbox Code Playgroud)

Gan*_*ndi 5

您要查找的内容在suds 文档中,称为 MessagePlugin。marshalled 选项允许您在发送之前更改您的消息。您需要将它作为插件添加到您的客户端中:

self.client = Client(url, plugins=[MyPlugin()])
Run Code Online (Sandbox Code Playgroud)

在编组方法中搜索 context.envelope childs。python 的 vars() 函数在这个地方非常有用。在我看来,它应该对你来说是这样的:

from suds.plugin import MessagePlugin
class MyPlugin(MessagePlugin):
    def marshalled(self, context):
        foo = context.envelope.getChild('Body').getChild...getChild(and so on)[0]
        foo.nsprefix = # or something like this
Run Code Online (Sandbox Code Playgroud)

对于这个“类似这部分的东西”,您需要调试您的请求(我推荐客户端和传输调试)并查找您的实体的变量。我只是不记得它是怎么称呼的。

我上周坐在这里,所以它可能会为你节省一些时间:) 当你有任何问题时写信,我会尽量在那里更具体。