rest json响应结构决定xml层级,硬编码转换必错;需依data字段嵌套、数组、null等动态生成soap,配合wsdl命名空间与xsd格式严格校验。

REST JSON 响应结构决定 XML 元素层级
直接硬编码转换必然出错,关键看 REST 接口返回的 data 字段是否嵌套、是否有数组、是否存在空值或 null。比如响应里是 {"user": {"id": 123, "profile": {"name": "Alice"}}},那 SOAP 的 <user></user> 下就得有 <profile></profile> 子元素,不能 flatten 成平级字段。
- 遇到
Array类型(如"orders": [{"id": "A1"}, {"id": "A2"}]),SOAP 中需用重复元素(如多个<order></order>)或包装容器(如<orders><order>...</order></orders>) -
null或缺失字段在 SOAP 中通常省略,除非 WSDL 明确要求nillable="true"并需带上xsi:nil="true" - 注意字段命名冲突:JSON 键名
user_id在 XML 中建议转为userId(驼峰)或保持下划线,但必须与 WSDL 定义一致
用 Python 的 dicttoxml 或 xmltodict 反向生成时的陷阱
这两个库不处理命名空间、SOAP Envelope 包装、必需的 xmlns 和 xsi 前缀——它们只生成裸 XML。强行用 dicttoxml.dicttoxml(response_data) 得到的是无效 SOAP 请求。
- 必须手动添加 SOAP 外层:
<envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"><body>...</body></envelope> - 目标命名空间(如
xmlns:ns="http://example.com/ws")要从 WSDL 的<definitions targetnamespace="..."></definitions>提取,并用于包裹操作元素(如<getuserrequest></getuserrequest>) -
xmltodict适合解析已有 SOAP 响应,不适合构造请求;它把 XML 转成 dict 后再转回,会丢失属性顺序和命名空间声明
真实项目中推荐的三步构造法
跳过通用序列化库,用模板 + 显式映射更可控。尤其当 REST 和 SOAP 字段语义不完全对齐时(比如 JSON 用 created_at,WSDL 要求 creationTimestamp)。
- 第一步:解析 WSDL,提取目标操作的输入结构,用工具如
zeep client.wsdl.dump()或在线 WSDL 查看器确认GetUserRequest的 exact 元素名、类型、是否可选 - 第二步:写一个轻量映射函数,例如:
def json_to_soap_request(json_resp): return { "userId": json_resp["user"]["id"], "userName": json_resp["user"].get("profile", {}).get("name", ""), "timestamp": datetime.now().isoformat() # 补充 SOAP 要求但 JSON 没有的字段 } - 第三步:用
lxml.etree或字符串模板填充命名空间和 Envelope,避免拼接错误。例如用etree.Element("{http://schemas.xmlsoap.org/soap/envelope/}Envelope")确保前缀绑定正确
调试时必查的三个 XML 错误点
SOAP 请求失败 80% 是 XML 结构问题,不是逻辑错误。抓包看实际发出的请求体,对照 WSDL 验证以下三点:
- 根元素名是否匹配 WSDL 中
<operation name="GetUser"></operation>对应的<input message="tns:GetUserRequest">所引用的消息名(通常是GetUserRequest,不是GetUser) - 所有元素是否在正确的命名空间下——比如
<getuserrequest></getuserrequest>中的ns必须与 WSDL 的targetNamespace一致,且该 namespace 已在 Envelope 中声明 - 日期/数字格式是否符合 XSD 类型:JSON 的
"2024-05-20"传给 XSDxs:dateTime字段时,必须补全时间部分变成"2024-05-20T00:00:00Z",否则服务器校验失败
最易被忽略的是 WSDL 中定义的 elementFormDefault="qualified" —— 这意味着所有局部元素(非顶层)也必须带命名空间前缀,哪怕你没写,生成器也得强制加上。










