Incorrect XML produced by SUDS

萝らか妹 提交于 2019-12-05 21:56:31

I was getting exactly the same problem. The sequence of parameters in my SOAP request is being wrapped in an element with the same name as the first parameter. e.g.

....
   <ns0:Body>
      <ns1:CreationReq>
         <ReqType>
            <ReqType>1</ReqType>
            <Title>Mr</Title>
            ....
         </ReqType>
      </ns1:CreationReq>
   </ns0:Body>
....

I've checked the WSDL over to make sure there is no problem with it.

The problem it seems is because I created a CreationReq object using the client.factory.create method. Checking the client by printing it shows that the method I am calling does not take that object as a parameter. Rather it takes a list of named args.

So my code was:

req = client.factory.create('CreationReq')
req.ReqType = 1
req.Title = 'Mr'
resp = client.service.Create(req)

Now it is:

req = {}
req['ReqType'] = 1
req['Title'] = 'Mr'
resp = client.service.Create(**req)

If you create a client for your suds services, there are some attributes that you can see to determine which objects are needed to pass into the service call.

For example:

import suds
client = suds.Client(url)
for a in client.sd: #print the whole service definition
    print a

This should show you the prefixes, ports with methods, and types. For your code, you should be able to see what needs to be passed in the service call to createCase. Even though the WSDL may define the method as needing a 'FWTCaseCreate', suds may be picking up the definition for createCase to need ClassificationEventCode, Priority, Title types, etc.

Therefore you wouldn't want to do: (which passes in newCase for the first argument, putting all the details under that tag)

newCase = client.factory.create('ns1:FWTCaseCreate')
caseID = client.service.createCase(newCase)

But instead call the service like so: (based on the service definition)

newCase = client.factory.create('ns1:FWTCaseCreate')
caseID = client.service.createCase(newCase.ClassificationEventCode, newCase.Priority, ...)

Or maybe:

newCase = client.factory.create('ns1:FWTCaseCreate')
caseID = client.service.createCase(*[getattr(newCase,a) for a in newCase.__keylist__])

Passing in the list of args that are required for the service call.

I don't know why the service call definition is incorrectly resolved as being what it is, but passing in the correct object doesn't expand automatically to the correct argument list needed. Perhaps reading the suds source ( http://jortel.fedorapeople.org/suds/doc/ ) would help divulge the answer.

Are you going to be using this as a config file, or to store infomation. Or is this to send data across the web?

Okay then, if this is so then why not use json or json-rpc, they are said to be much faster, easier to parse and far easier to read. XML is a horible data type and I personally can't wait till it dies, if your looking for data sending it would be well worth using the json's.

Your creating the element twice. Remove this:

classEventCode = client.factory.create('ns1:FWTEventCode') 
classEventCode.value = 2000023 

And change this:

newcase.ClassificationEventCode = 2000023

This should remove that extra tag.

I've found this thread searching for the solution of the same problem. So far I've researched it happens only when you pass factory created object directly to service method. And only with wsdl data types using extension (inheritance).

There is more solutions I could think of.

  • don't use factory for top level type at all.
  • write suds plugin changing xml after generating
  • re-write wsdl to not use inheritance (extension tag)
  • change type of object before passing to service method

I've chose the last one, as it is easiest way. So there is the code.

def sudsToDict(data):
    return dict([(str(key),val) for key,val in data])

Use like this.

data = client.factory.create('wsdl_data_type')
# now fill with values and then
data = sudsToDict(data)
client.service.some_method(**data)
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!