Неправильный 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>

As you can see there is a 'ClassificationEventCode' element around all the other elements, this should not be there. If I cut and paste this xml into SOAPUI and first remove this element and then post it directly to the web service it works successfully.

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

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.

Спасибо.


person itworkedonmachine    schedule 10.05.2010    source источник
comment
Думаю, нам нужен пример кода, который вы используете для создания этой структуры. Скорее всего, вы неправильно его настраиваете, что сбивает с толку SUDS.   -  person Simon Callan    schedule 10.05.2010
comment
Хорошо, теперь код добавлен   -  person itworkedonmachine    schedule 10.05.2010


Ответы (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)
person Robin Elvin    schedule 12.08.2010
comment
У меня такая же проблема. Это решение сработало для меня. Я до сих пор не знаю, почему, но, по крайней мере, это работает :) - person Kai; 23.11.2010

Если вы создаете клиент для своих служб 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 и т. д.

Поэтому вы не хотели бы делать: (который проходит в 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/ ) поможет разгласить ответ.

person mgav    schedule 16.07.2012

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

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

person Taos    schedule 10.05.2010
comment
Это для отправки данных через Интернет. - person itworkedonmachine; 10.05.2010
comment
Я согласен с тем, что XML ужасен, но веб-служба SOAP предоставляется сторонним поставщиком, и поэтому я не могу контролировать, как они внедряют интерфейс в свой продукт. Как я могу использовать JSON-rpc для вызова веб-службы SOAP? - person itworkedonmachine; 10.05.2010
comment
Что должна делать ваша программа и какой сторонний поставщик, если ваш сторонний поставщик поддерживает мыло, он, вероятно, будет поддерживать поддержку json. - person Taos; 10.05.2010
comment
Я боюсь, что он не поддерживает JSON, поэтому SOAP — единственный поддерживаемый способ взаимодействия с ним. - person itworkedonmachine; 10.05.2010

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

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

И измените это:

newcase.ClassificationEventCode = 2000023

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

person chrisg    schedule 12.05.2010
comment
Это не имеет никакого значения. Команда classEventCode = client.factory.create('ns1:FWTEventCode') просто создает новый объект на основе wsdl, который я затем назначаю объекту, который я передаю веб-методу. Но это не добавление его дважды. Спасибо за предложение. - person itworkedonmachine; 12.05.2010
comment
@Abbott - мне не на чем это проверить, но прочитайте этот документ jortel.fedorapeople.org/suds/doc/, может быть полезна опция отсоединения. Хотя не уверен, возможно, вы уже читали это. - person chrisg; 18.05.2010

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

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

  • вообще не используйте factory для типа верхнего уровня.
  • написать плагин 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)
person gjask    schedule 02.10.2014