开发者

How do I force a namespace prefix on an attibute in a SOAP request created using suds

开发者 https://www.devze.com 2023-02-22 02:56 出处:网络
I am using python suds (version: 0.3.9 GA build: R659-20100219) to interact with a SOAP service with the following structure:

I am using python suds (version: 0.3.9 GA build: R659-20100219) to interact with a SOAP service with the following structure:

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

I need to send a SOAP request with a structure like below:

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

That is, I need to append the target namespace in front of the id attribute. If I don't the request fails :(

I have tried several ways to create my doIngest request object, but I can only create a request like below:

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

That is, without the target namespace prefix on the id attribute.

I have tried variants of:

request = wsClient.factory.create('doIngest.request')
request.EmailReportID = "1031"
request.ProcessID = wsClient.factory.create('ProcessIDType')
request.ProcessID._id= "1430"
result=wsClient.service.doIngest(request)

and:

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)

and:

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)

but I get the same SOAP request

The WSDL tells me:

<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:eleme开发者_如何学Gont>
    </xs:sequence>
</xs:complexType>

and

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

which shows that the id does want the namespace prefix.

The question is therefore, how do I force the namespace prefix onto my id attibute?

Thanks to Gandi

Solution was therefore:

Update Suds to 0.4 (as MessagePlugin was not available in version: 0.3.9)

then:

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)


What you're looking for is in suds documentation and is called a MessagePlugin. The marshalled option allows you to change you're message before being sent. You need to add it into your client as a plugin:

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

In marshalled method search for context.envelope childs. The python's vars() function is very useful in this place. As I think, It should like something like this for you:

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

For this "something like this part" you need to debug your request (I recomend client and transport debug) and look for a vars of your entity. I just don't remember how it's called.

I was sitting at this for last week, so might it'll save some time for you :) Write when you'll have any questions, I'll try to be more specific there.


Not sure about the best solution but I came across similar issues while talking to Sharepoint through my haufe.sharepoint module (on PyPI). I ended up monkey-patching the send() of suds in order to modify the namespaces according to my needs. You may check the code in the patches.py file of the module.

0

精彩评论

暂无评论...
验证码 换一张
取 消