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

时间:2011-04-04 14:33:07

标签: python soap attributes namespaces suds

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

Service ( DPWSService ) tns="http://ejb.revitalization.services.ndg/"
Prefixes (1)
ns0 = "http://ejb.revitalization.services.ndg/"
Ports (1):
(DPWSPort)
Methods (13):
addTimer(request request, )
deleteProvider(request request, )
deleteTimer(request request, )
doHarvest(request request, )
doIngest(request request, )
doNewUpdateProvider(request request, )
getHarvestHistory(GetHistoryRequest request, )
getIngestHistory(GetHistoryRequest request, )
getList(GetListType request, )
getListNames()
getProviderDetails(request request, )
getProviderStatistic(request request, )
getStatusProcess(request request, )
Types (63):
AddTimerResponse
CSWProviderDetailsType
ConfirmationType
ContactType
DataRangeType
DeleteProviderResponse
DeleteTimerResponse
DoHarvestResponse
DoIngestResponse
DoNewUpdateProviderResponse
EmailContactType
GetHarvestHistoryResponse
GetHistoryRequest
GetIngestHistoryResponse
GetListNamesResponse
GetListResponse
GetListType
GetProcessStatusResponse
GetProviderDetailsResponse
GetProviderStatisticResponse
HarvestHistoryType
HarvestProviderType
HarvestType
IngestHistoryType
ListNames
OAIProviderDetailsType
ProcessIDType
ProviderCommonType
ProviderContactType
ProviderDetail
ProviderDetailsType
ProviderIDType
ProviderStatistic
ResponseType
TimerInfoCommonType
TimerInfoDetail
TimerInfoLogDetail
addTimer
addTimerResponse
deleteProvider
deleteProviderResponse
deleteTimer
deleteTimerResponse
doHarvest
doHarvestResponse
doIngest
doIngestResponse
doNewUpdateProvider
doNewUpdateProviderResponse
getHarvestHistory
getHarvestHistoryResponse
getIngestHistory
getIngestHistoryResponse
getList
getListNames
getListNamesResponse
getListResponse
getProviderDetails
getProviderDetailsResponse
getProviderStatistic
getProviderStatisticResponse
getStatusProcess
getStatusProcessResponse

我需要发送一个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>

也就是说,我需要在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>

也就是说,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)

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)

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)

但我得到了相同的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>

<xs:complexType name="ProcessIDType">
    <xs:sequence/>
    <xs:attribute ref="tns:id" use="required"/>
    <xs:attribute ref="tns:status"/>
</xs:complexType>

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

问题是,如何强制命名空间前缀到我的id attibute?

感谢Gandi

因此解决方案是:

将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)

2 个答案:

答案 0 :(得分:4)

您正在寻找的是suds documentation,称为MessagePlugin。编组选项允许您在发送之前更改您的消息。您需要将其作为插件添加到客户端中:

self.client = Client(url, plugins=[MyPlugin()])

在编组方法中搜索context.envelope子项。 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

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

我上周坐在这里,所以可能会为你节省一些时间:)写下你有什么问题时,我会尝试在那里更具体。

答案 1 :(得分:0)

不确定最佳解决方案但我在通过haufe.sharepoint模块(在PyPI上)与Sharepoint交谈时遇到了类似的问题。我最后修补了suds的send(),以便根据我的需要修改名称空间。您可以检查模块的patches.py文件中的代码。