SOAP with Attachments(SwA)通过在MIME多部分消息中封装SOAP XML主体和各类附件,实现了Web服务中复杂数据的传输。处理这类消息的核心难点在于正确建立XML主体内容与对应附件的映射关系,避免数据关联错误。

SOAP with Attachments的基础结构
SwA消息本质是MIME多部分消息,通常包含两个部分:第一部分是SOAP XML信封,描述消息的核心业务内容和附件引用信息;后续部分是各类附件,比如图片、文档、二进制数据等。两部分通过MIME边界标识符分隔,XML中会通过特定的引用方式指向对应的附件。
常见的XML引用附件的方式是在元素中添加href属性,属性值为附件的Content-ID,格式通常为cid:附件标识,例如<file href="cid:attachment1"/>。
XML映射的核心处理步骤
1. 解析MIME消息边界
首先需要从SwA消息的原始字节流中提取MIME边界,边界值通常出现在消息头的Content-Type字段中,格式为multipart/related; boundary=自定义边界字符串。解析出边界后,就可以按边界拆分出所有的MIME部分。
2. 提取SOAP XML主体
拆分后的第一个MIME部分通常是SOAP XML主体,需要读取该部分的Content-Type确认是XML类型,然后将其内容解析为XML文档对象,方便后续提取附件引用信息。
3. 提取所有附件并建立索引
遍历剩余的MIME部分,读取每个部分的Content-ID头信息,去掉首尾的尖括号后得到纯净的附件标识,以标识为键、附件内容为值建立映射字典,方便后续快速查找。
4. 关联XML元素与对应附件
遍历解析后的XML文档,查找所有包含href属性且属性值以cid:开头的元素,提取出cid:后的附件标识,从之前建立的附件索引中查找对应的附件内容,完成映射关联。
代码示例:Java实现SwA XML映射处理
以下是使用Java Mail的MIME解析能力和DOM XML解析能力处理SwA XML映射的完整示例:
import javax.mail.BodyPart;
import javax.mail.Multipart;
import javax.mail.Session;
import javax.mail.internet.MimeMessage;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import java.io.ByteArrayInputStream;
import java.util.HashMap;
import java.util.Map;
public class SwaXmlMapper {
public static class MappingResult {
public Document soapXml;
public Map<String, byte[]> attachmentMap;
}
public static MappingResult processSwaMessage(byte[] swaMessageBytes) throws Exception {
MappingResult result = new MappingResult();
result.attachmentMap = new HashMap<>();
// 解析MIME消息
MimeMessage mimeMessage = new MimeMessage(Session.getDefaultInstance(new java.util.Properties()), new ByteArrayInputStream(swaMessageBytes));
Multipart multipart = (Multipart) mimeMessage.getContent();
// 处理第一个部分:SOAP XML主体
BodyPart soapPart = multipart.getBodyPart(0);
String soapContentType = soapPart.getContentType();
if (!soapContentType.contains("text/xml") && !soapContentType.contains("application/soap+xml")) {
throw new IllegalArgumentException("第一个MIME部分不是SOAP XML内容");
}
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
result.soapXml = builder.parse(soapPart.getInputStream());
// 处理后续部分:附件
for (int i = 1; i < multipart.getCount(); i++) {
BodyPart attachmentPart = multipart.getBodyPart(i);
String contentId = attachmentPart.getHeader("Content-ID", null);
if (contentId != null) {
// 去掉Content-ID首尾的尖括号
contentId = contentId.replaceAll("^<|>$", "");
byte[] attachmentData = new byte[(int) attachmentPart.getSize()];
attachmentPart.getInputStream().read(attachmentData);
result.attachmentMap.put(contentId, attachmentData);
}
}
// 关联XML中的附件引用
NodeList elementsWithHref = result.soapXml.getElementsByTagName("*");
for (int i = 0; i < elementsWithHref.getLength(); i++) {
Element element = (Element) elementsWithHref.item(i);
String href = element.getAttribute("href");
if (href != null && href.startsWith("cid:")) {
String attachmentId = href.substring(4);
if (result.attachmentMap.containsKey(attachmentId)) {
// 这里可以将附件内容设置到元素的自定义属性中,或者单独维护映射关系
element.setAttribute("attachmentDataRef", attachmentId);
}
}
}
return result;
}
}
注意事项
- 部分SwA消息的XML中可能使用自定义属性引用附件,需要提前确认消息的引用规范,避免遗漏映射关系。
- 附件的
Content-ID可能存在大小写差异,建立索引和查找时建议统一转为小写处理,避免匹配失败。 - 处理大附件时需要注意内存占用,避免一次性将过大的附件内容加载到内存中,可采用流式读取的方式处理。
SOAP_with_AttachmentsXML映射附件处理消息解析修改时间:2026-07-01 20:15:31