Неверный XML, созданный SUDS

Я пытаюсь общаться с веб-службой SOAP, используя SUDS и Python. После большого количества возни с изучением Python (да, я новичок в этом) и разработкой, как использовать SUDS, я столкнулся с проблемой.

Подпись веб-метода, который я вызываю, согласно suds,

(FWTCaseCreate){
ClassificationEventCode = None
Priority = None
Title = None
Description = None
Queue = None
DueDate = None
AssociatedObject = 
  (FWTObjectBriefDetails){
     ObjectID = 
        (FWTObjectID){
           ObjectType = None
           ObjectReference[] = <empty>
        }
     ObjectDescription = None
     Details = None
     Category = None
  }
Form = 
  (FWTCaseForm){
     FormField[] = <empty>
     FormName = None
     FormKey = None
  }
Internal = None
InteractionID = None
XCoord = None
YCoord = None
}

Поэтому я использую SUDS для создания нужных мне классов и отправляю их в метод. Однако я получаю ошибку. Поэтому я включил вход в систему и вижу, что отправляемый XML-файл неверен, что вызывает ошибку десериализации. Пакет SOAP выглядит следующим образом

<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:ns0="http://www.CRM.com/wsdl/FLTypes"    xmlns:ns1="http://schemas.xmlsoap.org/soap/envelope/" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Header>
   <wsse:Security>
      <wsse:BinarySecurityToken>eaadf1ddff99a8</wsse:BinarySecurityToken>
   </wsse:Security>
</SOAP-ENV:Header>
<ns1:Body>
   <ns0:FWTCaseCreate>
      <ClassificationEventCode>
         <ClassificationEventCode>2000023</ClassificationEventCode>
         <Priority>1</Priority>
         <Title>testing</Title>
         <Description>testing</Description>
         <Queue/>
         <Internal>True</Internal>
         <XCoord>356570</XCoord>
         <YCoord>168708</YCoord>
      </ClassificationEventCode>
   </ns0:FWTCaseCreate>
</ns1:Body>

Как видите, вокруг всех остальных элементов есть элемент ClassificationEventCode, его там быть не должно. Если я вырезал и вставил этот xml в SOAPUI и сначала удалил этот элемент, а затем опубликовал его непосредственно в веб-сервисе, он успешно работает.

Вот код, который я использую, чтобы сделать звонок

client = Client(url)

#Add a header for the security
ssnns = ('wsse', 'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd')

ssn = Element('BinarySecurityToken', ns=ssnns).setText(binaryKey)

ssn1 = Element('Security',ns=ssnns)

ssn1.append(ssn)

client.set_options(soapheaders=ssn1) 

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

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

newCase.ClassificationEventCode = classEventCode
newCase.Priority = 1
#optional
newCase.AssociatedObject = None
#optional
newCase.Form = None
#optional
newCase.Internal = None
#optional
newCase.InteractionID =  None
#optional
newCase.DueDate = None
#optional
newCase.Queue = None

newCase.Title = 'Title'

newCase.Description = 'description'

newCase.XCoord = '356570'

newCase.YCoord = '168708'

caseID = client.service.createCase(newCase)

У кого-нибудь есть идеи, почему это происходит? Я думаю, SUDS думает, что это должно быть там на основе WSDL.

Благодарю.

5 ответов

Решение

У меня была точно такая же проблема. Последовательность параметров в моем запросе SOAP заключена в элемент с тем же именем, что и первый параметр. например

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

Я проверил WSDL, чтобы убедиться, что с ним нет проблем.

Кажется, проблема в том, что я создал объект CreationReq, используя метод client.factory.create. Проверка клиента путем печати показывает, что метод, который я вызываю, не принимает этот объект в качестве параметра. Скорее, это займет список именованных аргументов.

Итак, мой код был:

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

Теперь есть:

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

Если вы создаете клиента для своих служб suds, вы можете увидеть некоторые атрибуты, чтобы определить, какие объекты необходимо передать в вызов службы.

Например:

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

Это должно показать вам префиксы, порты с методами и типами. Для своего кода вы должны увидеть, что нужно передать в вызове сервиса для createCase. Несмотря на то, что WSDL может определять метод как требующий "FWTCaseCreate", suds может выбирать определение для createCase, чтобы ему требовались ClassificationEventCode, Priority, Title type и т. Д.

Поэтому вы не захотите делать: (который передает newCase для первого аргумента, помещая все детали под этим тегом)

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

Но вместо этого вызывайте сервис следующим образом: (на основе определения сервиса)

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

Или, может быть:

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

Передача в список аргументов, которые необходимы для вызова службы.

Я не знаю, почему определение вызова службы неправильно разрешено как то, что оно есть, но передача правильного объекта не расширяется автоматически до нужного списка нужных аргументов. Возможно, чтение источника suds ( http://jortel.fedorapeople.org/suds/doc/) поможет обнародовать ответ.

Вы создали элемент дважды. Удали это:

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

И измени это:

newcase.ClassificationEventCode = 2000023

Это должно удалить этот дополнительный тег.

Вы собираетесь использовать это в качестве файла конфигурации или для хранения информации. Или это для отправки данных через Интернет?

Хорошо, тогда, если это так, то почему бы не использовать json или json-rpc, они, как говорят, намного быстрее, легче разбираются и намного легче читаются. XML является гибким типом данных, и я лично не могу ждать, пока он умрет, если вы ищете отправку данных, то стоит использовать json.

Я нашел эту ветку в поисках решения той же проблемы. До сих пор я исследовал, что это происходит только тогда, когда вы передаете объект, созданный на заводе, непосредственно методу сервиса. И только с типами данных wsdl, использующими расширение (наследование).

Есть больше решений, о которых я мог бы подумать.

  • вообще не используйте фабрику для типа верхнего уровня.
  • написать плагин suds, изменяющий xml после генерации
  • переписать wsdl, чтобы не использовать наследование (расширение тега)
  • изменить тип объекта перед переходом в сервисный метод

Я выбрал последний, так как это самый простой способ. Итак, есть код.

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

Используйте как это.

data = client.factory.create('wsdl_data_type')
# now fill with values and then
data = sudsToDict(data)
client.service.some_method(**data)
Другие вопросы по тегам