How do I force a namespace prefix on an attibute in a SOAP request created using suds
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.
精彩评论