如何在R和Python中解析XML MTOM格式的SOAP响应
MTOM格式SOAP响应解析方案(Python+R)
核心逻辑
- 收到的
application/xop+xml类型响应属于MTOM封装的MIME多部分消息,需先拆分多部分内容提取SOAP XML片段,无法直接用常规XML库解析 - SOAP报文体中的业务数据为HTML转义后的XML字符串,需完成反转义后才能解析内层业务字段
Python 实现
方案1:内置库手动解析(无需额外SOAP客户端)
依赖Python标准库即可完成解析,无需安装第三方SOAP框架:
import html import xml.etree.ElementTree as ET from email import policy from email.parser import BytesParser # 此处替换为你实际拿到的响应原始字节内容,若用requests发请求则为response.content response_content = b'你的原始MTOM响应字节内容' # 1. 解析MIME多部分内容,提取SOAP XML片段 msg = BytesParser(policy=policy.default).parsebytes(response_content) soap_xml = None for part in msg.walk(): if part.get_content_type() == 'application/xop+xml': soap_xml = part.get_content() break # 2. 解析SOAP信封,提取转义的业务XML ns = { 's': 'http://www.w3.org/2003/05/soap-envelope', 'bir': 'http://CIS/BIR/PUBL/2014/07' } soap_root = ET.fromstring(soap_xml) encoded_biz_xml = soap_root.find('./s:Body/bir:DaneSzukajPodmiotyResponse/bir:DaneSzukajPodmiotyResult', ns).text # 3. 反转义后解析业务字段 biz_xml = html.unescape(encoded_biz_xml) biz_root = ET.fromstring(biz_xml) dane_node = biz_root.find('./dane') # 字段提取示例 regon = dane_node.find('Regon').text nip = dane_node.find('Nip').text nazwa = dane_node.find('Nazwa').text print(f"Regon编码: {regon}, NIP税号: {nip}, 公司名称: {nazwa}")
方案2:zeep SOAP客户端自动处理(推荐)
如果是主动发起SOAP请求,直接用支持MTOM的zeep框架,无需手动解析:
- 安装依赖:
pip install zeep - 调用示例:
from zeep import Client from zeep.transports import Transport # 开启MTOM支持 transport = Transport(mtom=True) # 替换为实际的WSDL地址 client = Client('https://你的服务地址?wsdl', transport=transport) # 直接调用接口方法,自动处理MTOM封装与解析 resp = client.service.DaneSzukajPodmioty(请求参数名=参数值) # 直接读取结构化返回值 print(resp.DaneSzukajPodmiotyResult.dane.Regon)
R 实现
- 先安装依赖包:
install.packages(c("httr", "xml2")) - 解析代码:
library(httr) library(xml2) # 此处resp为httr发送SOAP请求返回的响应对象,示例:resp <- POST("接口地址", body = 构造的SOAP请求体, content_type("application/soap+xml")) resp <- 你的请求响应对象 # 1. 拆分MTOM多部分内容,提取SOAP XML content_type <- headers(resp)$`Content-Type` boundary <- gsub('.*boundary="?([^";]+)"?.*', '\\1', content_type) resp_raw <- content(resp, as = "raw") parts <- strsplit(rawToChar(resp_raw), paste0("--", boundary))[[1]] parts <- parts[parts != "" & parts != "--\r\n"] soap_xml <- NULL for (part in parts) { if (grepl("Content-Type: application/xop\\+xml", part)) { # 拆分头部和内容 split_part <- strsplit(part, "\r\n\r\n")[[1]] soap_xml <- split_part[length(split_part)] break } } # 2. 解析SOAP信封提取转义XML ns <- c( s = "http://www.w3.org/2003/05/soap-envelope", bir = "http://CIS/BIR/PUBL/2014/07" ) soap_root <- read_xml(soap_xml) encoded_biz_xml <- xml_text(xml_find_first(soap_root, "//s:Body/bir:DaneSzukajPodmiotyResponse/bir:DaneSzukajPodmiotyResult", ns)) # 3. 反转义解析业务字段 biz_root <- read_xml(xml_unescape(encoded_biz_xml)) regon <- xml_text(xml_find_first(biz_root, "//dane/Regon")) nazwa <- xml_text(xml_find_first(biz_root, "//dane/Nazwa")) print(paste0("Regon编码: ", regon, " 公司名称: ", nazwa))
内容的提问来源于stack exchange,提问作者khasis lampard
相关产品推荐
相关产品推荐

