Python SUDS Ошибка

Я пытаюсь преобразовать PHP-скрипт в python, но не могу понять, почему следующее не работает.

Результаты, возвращаемые запросом службы SOAP:

Suds ( https://fedorahosted.org/suds/ )  version: 0.4 GA  build: R699-20100913

Service ( ExternalQueryNameAvailabilityService ) tns="http://asic.gov.au/wsdl/name/availability/external"
Prefixes (6)
  ns0 = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
  ns1 = "http://www.w3.org/2005/05/xmlmime"
  ns2 = "uri:business.document.header.types.asic.gov.au"
  ns3 = "uri:external.query.name.availability.asic.gov.au"
  ns4 = "uri:fss.types.asic.gov.au"
  ns5 = "uri:types.asic.gov.au"
Ports (1):
  (ExternalQueryNameAvailabilityPort)
     Methods (1):
        externalQueryNameAvailability(ns2:businessDocumentHeaderType businessDocumentHeader, ns3:requestDataType businessDocumentBody, )
     Types (113):
        ns0:AttributedDateTime
        ns0:AttributedURI
        ns0:TimestampType
        ns5:abnApplicationReferenceNumberType
        ns5:abnType
        ns5:accountIdentifierType
        ns5:actionType
        ns5:addressType
        ns5:addressTypeType
        ns5:agentNameType
        ns5:agentType
        ns5:amountSignedType
        ns5:amountType
        ns5:applicationStatusType
        ns4:ascotDocumentNoType
        ns5:asicNumericIdType
        ns4:asicPaymentDetailsType
        ns5:asicSignatoryType
        ns2:attachmentType
        ns2:attachmentsType
        ns1:base64Binary
        ns5:birthDetailsType
        ns5:bnReferenceNumberType
        ns5:browserIdentifierType
        ns2:businessDocumentHeaderType
        ns2:businessDocumentRequestHeaderType
        ns5:businessNameIdentifierType
        ns5:codeType
        ns5:creditCardType
        ns4:customerReferenceNumberType
        ns4:debtorType
        ns5:descriptionType
        ns5:distinguishedNameType
        ns5:distinguishedWordType
        ns5:documentIdentifierType
        ns5:documentNoType
        ns5:emailType
        ns5:entityType
        ns5:exceptionListType
        ns5:exceptionType
        ns4:feeType
        ns4:feeWithAmountType
        ns4:feesType
        ns5:flagType
        ns4:fssAccountType
        ns4:fssCustomerType
        ns4:fssItemType
        ns4:fssSimpleAccountType
        ns4:fssTransactionType
        ns2:genericResultType
        ns1:hexBinary
        ns5:inboxIdentifierType
        ns5:intervalStatusType
        ns4:invoiceType
        ns5:itemSearchScopeType
        ns5:itemSummaryType
        ns5:itemTypeType
        ns5:keyType
        ns4:ledgerType
        ns5:lodgementIdentifierType
        ns2:messageEventType
        ns2:messageEventsType
        ns5:messageIdentifierType
        ns2:messageTimestampType
        ns2:messageTimestampsType
        ns5:nameAvailabilityType
        ns5:nameResultType
        ns5:nameResultWithObjectionsType
        ns5:nameType
        ns5:nniNameType
        ns5:nniNumberType
        ns5:objectionType
        ns5:organisationIdentifierType
        ns5:organisationNamePlusIdType
        ns5:originatingChannelType
        ns5:originatingServiceType
        ns5:outboundItemIdentifierType
        ns4:paymentDetailsType
        ns4:paymentMethodType
        ns5:paymentType
        ns5:personNameBirthType
        ns5:personNameType
        ns5:personNameWithRoleType
        ns4:priceType
        ns3:queryNameAvailabilityReplyType
        ns3:queryNameAvailabilityRequestType
        ns5:realmIdentifierType
        ns5:realmQualifierType
        ns4:receiptType
        ns5:referenceNoType
        ns5:rejectedType
        ns3:replyDataType
        ns5:replyType
        ns3:requestDataType
        ns5:requestFailedType
        ns5:requestRejectedType
        ns5:requestType
        ns5:resultType
        ns5:signatoryType
        ns5:soapSoftwareIdentifierType
        ns2:softwareInformationType
        ns5:standardHeaderType
        ns5:standardMessageHeaderType
        ns5:stateTerritoryCodeType
        ns5:statusType
        ns5:streetType
        ns4:suffixType
        ns0:tTimestampFault
        ns5:telephoneNumberType
        ns5:textType
        ns4:transactionType
        ns4:transactionsType
        ns5:trueType

При попытке выполнить следующее:

con = connect('ExternalQueryNameAvailabilityPort', test, {'Content-Type': 'application/soap+xml'})
q_header = con.factory.create('ns2:businessDocumentHeaderType')
q_header.messageType = 'queryNameAvailability'
q_header.messageVersion = '2'
q_header.messageReferenceNumber = '100'
q_header.senderType = 'REGA'
q_header.senderId = '192'
q_body = con.factory.create('ns3:businessDocumentBody')
q_body.proposedName = 'Xtramedia.net PTY LTD'   
q_body.companyNameAvailabilityCheck = 'true'
q_body.bnNameAvailabilityCheck = 'true'
result = con.service.externalQueryNameAvailability(q_header, q_body)

Я получаю следующую ошибку:

DEBUG:suds.client:http failed:
<?xml version='1.0' encoding='UTF-8'?>
  <S:Envelope xmlns:S="http://www.w3.org/2003/05/soap-envelope">
   <S:Body>
    <S:Fault xmlns:ns4="http://schemas.xmlsoap.org/soap/envelope/">
     <S:Code>
      <S:Value>S:Receiver</S:V6alue>
     </S:Code>
     <S:Reason>
      <S:Text xml:lang="en">org.xml.sax.SAXParseException: cvc-complex-type.2.4.a: Invalid content was found starting with element 'ns1:businessDocumentHeader'. One of '{"uri:business.document.header.types.asic.gov.au":businessDocumentHeader}' is expected
      </S:Text>
     </S:Reason>
    </S:Fault>
   </S:Body>
  </S:Envelope> 

Любые идеи, почему он будет жаловаться на этот элемент? - Я попытался удалить часть "nsX" объявления элемента, но тоже самое.

ОБНОВЛЕНИЕ: следующее - то, что генерирует PHP Script и является успешным;

    <?xml version="1.0" encoding="UTF-8"?>
<env:Envelope xmlns:env="http://www.w3.org/2003/05/soap-envelope" xmlns:ns1="uri:business.document.header.types.asic.gov.au" xmlns:ns2="uri:external.query.name.availability.asic.gov.au">
    <env:Body>
     <ns2:request>
      <ns1:businessDocumentHeader>
        <ns1:messageType>queryNameAvailability</ns1:messageType>
        <ns1:messageReferenceNumber>1</ns1:messageReferenceNumber>
        <ns1:messageVersion>2</ns1:messageVersion>
        <ns1:senderId>192</ns1:senderId>
        <ns1:senderType>REGA</ns1:senderType>
      </ns1:businessDocumentHeader>
      <ns2:businessDocumentBody>
        <ns2:proposedName>TEST</ns2:proposedName>
        <ns2:bnNameAvailabilityCheck>true</ns2:bnNameAvailabilityCheck>
      </ns2:businessDocumentBody>
    </ns2:request>
   </env:Body>
  </env:Envelope>

У кого-нибудь есть идеи?

ОБНОВЛЕНИЕ 2: я должен был установить последнюю версию SUDS, чтобы это работало. - Спасибо всем за ваши ответы очень ценится.

Ура, Бен

2 ответа

Решение

Обновление (после вывода примера PHP)

Непонятно почему suds использования {uri:external.query.name.availability.asic.gov.au}вместо {uri:business.document.header.types.asic.gov.au} за businessDocumentHeader элемент.

Быстрый и грязный способ исправить это использовать suds.plugin например:

from suds.plugin import MessagePlugin

class NsHeaderPlugin(MessagePlugin):
    def sending(self, context):
        context.envelope = context.envelope.replace('ns1:businessDocumentHeader',
                                                    'ns0:businessDocumentHeader')

Или же

class NsHeaderPlugin(MessagePlugin):
    def marshalled(self, context):
        hdr = context.envelope.childAtPath('Body/request/businessDocumentHeader')
        hdr.setPrefix('hdr', 'uri:business.document.header.types.asic.gov.au')

Второй аргумент должен быть ns3:requestDataTypeне ns3:businessDocumentBody как вы указали.

Общий поток кода:

from suds.client import Client # pip install suds

#XXX: change envelope namespace
from suds.bindings import binding
binding.envns = (binding.envns[0], 'http://www.w3.org/2003/05/soap-envelope')
del binding

# change content type
headers = {'Content-Type': 'application/soap+xml; charset="UTF-8"'}
client = Client(wsdl_url, headers=headers, plugins=[NsHeaderPlugin()])

header = client.factory.create('{uri:business.document.header.types.asic.gov.au}'
                               'businessDocumentHeaderType')
header.messageType = "queryNameAvailability"
header.messageReferenceNumber = 1
header.messageVersion = 2
header.senderId = 192
header.senderType = "REGA"

body = client.factory.create('{uri:external.query.name.availability.asic.gov.au}'
                             'requestDataType')
body.proposedName = 'TEST'
body.bnNameAvailabilityCheck = 'true' 

# make the call
result = client.service.externalQueryNameAvailability(header, body)
print result # for debugging, to find out what attributes are available

Я не вижу неопределенных пространств имен, так что кажется ImportDoctor не нужно в вашем случае. Но, например, если бы были xs:string тип используется и 'http://schemas.xmlsoap.org/soap/encoding/' не упоминается, тогда вы можете исправить схему wsdl:

from suds.xsd.doctor import Import, ImportDoctor

imp = Import('http://schemas.xmlsoap.org/soap/encoding/')
# add namespaces where the type is used (call `imp.filter.add` multiple times)
imp.filter.add("http://asic.gov.au/wsdl/name/availability/external") 
doctor = ImportDoctor(imp)

client = Client(wsdl_url, doctor=doctor)

Ошибка в значительной степени говорит вам, где именно вам нужно искать:

      <S:Text xml:lang="en">org.xml.sax.SAXParseException: cvc-complex-type.2.4.a: Invalid content was found starting with element 'ns1:businessDocumentHeader'. One of '{"uri:business.document.header.types.asic.gov.au":businessDocumentHeader}' is expected

ns1 ссылается на URL http://www.w3.org/2005/05/xmlmime. Если вы посетите это в своем браузере, то увидите, что в этом нет ничего особенного. Это также исключает ns1 верно.

поскольку ns1:businessDocumentHeader даже нет в списке типов, определенных WSDL, возможно, вам придется использовать ImportDoctor, В прошлом я сталкивался с подобной проблемой в моем личном проекте, где WSDL неправильно импортировал типы.

Извините, этот ответ не является окончательным, но очень трудно определить точное исправление, так как я не вижу ваш WSDL. Попробуйте поработать с документами для ImportDoctor и посмотрим, не поможет ли это

Попробуйте начать с этого:

from suds.xsd.doctor import Import, ImportDoctor
imp = Import("http://www.w3.org/2005/05/xmlmime")
imp.filter.add("uri:business.document.header.types.asic.gov.au")
doctor = ImportDoctor(imp)

А потом пройти doctor=doctor в конструктор клиента.

Другие вопросы по тегам