Reputation: 3475
I'm trying to convert a PHP script over to python but cannot for the life of me figure out why the following is not working.
Results returned from the SOAP service query:
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
When trying to execute the following:
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)
I get the following error:
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>
Any ideas why it would be complaining about that element? - I've tried removed the "nsX" part of the element declaration but same thing.
UPDATE: The following is what the PHP Script generates and is successfull;
<?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>
Anyone got any ideas?
UPDATE 2: I had to install the latest version of SUDS to get this working. - Thanks all for your answers much appreciated.
Cheers, Ben
Upvotes: 4
Views: 4017
Reputation: 414345
It is unclear why suds
uses {uri:external.query.name.availability.asic.gov.au}
instead of {uri:business.document.header.types.asic.gov.au}
for businessDocumentHeader
element.
The quick and dirty way to fix it is to use suds.plugin
e.g.:
from suds.plugin import MessagePlugin
class NsHeaderPlugin(MessagePlugin):
def sending(self, context):
context.envelope = context.envelope.replace('ns1:businessDocumentHeader',
'ns0:businessDocumentHeader')
Or
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')
The 2nd argument should be ns3:requestDataType
, not ns3:businessDocumentBody
as you specified.
The general code flow:
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
I don't see undefined namespaces so it seems ImportDoctor
is not necessary in your case. But, for example, if there were xs:string
type used and 'http://schemas.xmlsoap.org/soap/encoding/'
is not mentioned then you could fix the wsdl schema:
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)
Upvotes: 2
Reputation: 33716
The error pretty much tells you exactly where you need to look:
<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
references the URL http://www.w3.org/2005/05/xmlmime. If visit that in your browser, you can see that there isn't much to it. That further rules out that ns1
is correct.
Since ns1:businessDocumentHeader
isn't even in the list of types determined by the WSDL, you might have to make use of the ImportDoctor
. I've run into similar issue in the past on a personal project of mine where the WSDL didn't correctly import the types.
I'm sorry this response isn't conclusive, but it's very difficult determine the exact fix since I can't see your WSDL. Try tinkering with the docs for the ImportDoctor
and see if that doesn't help.
Try starting with this:
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)
And then pass doctor=doctor
to the client constructor.
Upvotes: 0