使用Python Zeep调用Belboon SOAP API遇xml-soap Map解析错误
Got it, let's tackle this issue with Zeep and Belboon's SOAP API. That NamespaceError happens because the API uses an old, non-standard Apache SOAP Map type (from the http://xml.apache.org/xml-soap namespace) in its response, and Zeep doesn't have a built-in rule to parse this type by default. When you set raw_response=True, you're skipping Zeep's parsing layer, which is why you get valid XML but not a usable Python object.
Solution: Add a Custom Type Mapping
We need to tell Zeep how to convert that Map element into a Python dictionary. Here's how to do it with a custom type definition registered to the client's schema:
from zeep import Client, Settings from zeep.transports import Transport from requests.auth import HTTPBasicAuth from requests import Session from zeep.xsd import ComplexType, Element, AnySimpleType # Set up session with your Belboon credentials session = Session() session.auth = HTTPBasicAuth('your_belboon_login', 'your_belboon_password') # Configure Zeep settings (keep your existing strict=False setting) settings = Settings(strict=False, xml_huge_tree=True) # Initialize the Zeep client client = Client('http://api.belboon.com/?wsdl', settings=settings, transport=Transport(session=session)) # Define the structure of the Apache SOAP Map type apache_soap_namespace = 'http://xml.apache.org/xml-soap' map_complex_type = ComplexType( Element('item', [ Element('key', AnySimpleType()), Element('value', AnySimpleType()) ]), name='Map', target_namespace=apache_soap_namespace ) # Register this custom type with the client's WSDL schema client.wsdl.types.add_type(map_complex_type) # Now call the API method as intended try: account_info = client.service.getAccountInfo() print(account_info) except Exception as e: print(f"Error encountered: {str(e)}")
How This Works
The custom ComplexType we defined matches the structure of the Apache SOAP Map—it expects a sequence of <item> elements, each containing a <key> and <value>. Zeep will now convert these items into key-value pairs in a Python dictionary, just like the PHP SoapClient does automatically.
Alternative Shortcut
If you prefer a more concise approach, you can directly map the Map element to Zeep's built-in Dict type:
from zeep import xsd # ... (keep your session/client setup code) # Register the Map as a dictionary type client.wsdl.add_element( xsd.Element( '{http://xml.apache.org/xml-soap}Map', xsd.Dict(xsd.AnySimpleType(), xsd.AnySimpleType()) ) )
Fallback: Manual XML Parsing
If the type mapping doesn't work for some edge cases, you can stick with raw_response=True and parse the XML manually using a library like xmltodict:
import xmltodict # ... (session/client setup) raw_response = client.service.getAccountInfo(raw_response=True) parsed_data = xmltodict.parse(raw_response.content) print(parsed_data)
This is less ideal since you lose Zeep's type handling, but it's a reliable fallback if needed.
内容的提问来源于stack exchange,提问作者Julien

