在C#开发中调用SOAP服务后,服务端返回的响应内容通常是符合SOAP协议的XML格式,我们需要从中提取需要的数据字段来完成业务逻辑。处理这类XML时,核心是要适配SOAP协议的命名空间规则,同时精准定位目标节点。

SOAP响应XML的基本结构
标准的SOAP响应XML一般包含<Envelope>、<Body>等根节点,自定义的业务数据通常放在<Body>的子节点中,同时会携带多个命名空间。示例如下:
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Body>
<GetUserInfoResponse xmlns="http://tempuri.org/">
<GetUserInfoResult>
<UserName>张三</UserName>
<Age>25</Age>
<Email>test@ipipp.com</Email>
<GetUserInfoResult>
</GetUserInfoResponse>
</soap:Body>
</soap:Envelope>
使用XmlDocument解析SOAP响应
XmlDocument是C#内置的传统XML解析类,适合处理结构相对固定的SOAP响应,我们可以通过注册命名空间来定位节点。
步骤说明
- 加载XML字符串到XmlDocument实例
- 创建XmlNamespaceManager管理命名空间
- 使用XPath语句查询目标节点
- 提取节点的InnerText作为结果
代码示例
以下是解析上述SOAP响应获取用户信息的完整代码:
using System;
using System.Xml;
class Program
{
static void Main()
{
// 模拟SOAP响应的XML字符串
string soapResponse = @"<?xml version=""1.0"" encoding=""utf-8""?>
<soap:Envelope xmlns:soap=""http://schemas.xmlsoap.org/soap/envelope/"" xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xmlns:xsd=""http://www.w3.org/2001/XMLSchema"">
<soap:Body>
<GetUserInfoResponse xmlns=""http://tempuri.org/"">
<GetUserInfoResult>
<UserName>张三</UserName>
<Age>25</Age>
<Email>test@ipipp.com</Email>
</GetUserInfoResult>
</GetUserInfoResponse>
</soap:Body>
</soap:Envelope>";
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.LoadXml(soapResponse);
// 创建命名空间管理器,添加SOAP和自定义命名空间
XmlNamespaceManager nsManager = new XmlNamespaceManager(xmlDoc.NameTable);
nsManager.AddNamespace("soap", "http://schemas.xmlsoap.org/soap/envelope/");
nsManager.AddNamespace("temp", "http://tempuri.org/");
// 查询Body下的GetUserInfoResponse节点
XmlNode bodyNode = xmlDoc.SelectSingleNode("//soap:Body", nsManager);
XmlNode resultNode = bodyNode.SelectSingleNode("temp:GetUserInfoResponse/temp:GetUserInfoResult", nsManager);
if (resultNode != null)
{
string userName = resultNode.SelectSingleNode("temp:UserName", nsManager)?.InnerText;
string age = resultNode.SelectSingleNode("temp:Age", nsManager)?.InnerText;
string email = resultNode.SelectSingleNode("temp:Email", nsManager)?.InnerText;
Console.WriteLine($"用户名:{userName}");
Console.WriteLine($"年龄:{age}");
Console.WriteLine($"邮箱:{email}");
}
}
}
使用XDocument解析SOAP响应
XDocument是LINQ to XML的核心类,语法更简洁,适合结合LINQ查询处理XML,代码可读性更高。
代码示例
同样解析上述SOAP响应,使用XDocument的实现如下:
using System;
using System.Linq;
using System.Xml.Linq;
class Program
{
static void Main()
{
string soapResponse = @"<?xml version=""1.0"" encoding=""utf-8""?>
<soap:Envelope xmlns:soap=""http://schemas.xmlsoap.org/soap/envelope/"" xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xmlns:xsd=""http://www.w3.org/2001/XMLSchema"">
<soap:Body>
<GetUserInfoResponse xmlns=""http://tempuri.org/"">
<GetUserInfoResult>
<UserName>张三</UserName>
<Age>25</Age>
<Email>test@ipipp.com</Email>
</GetUserInfoResult>
</GetUserInfoResponse>
</soap:Body>
</soap:Envelope>";
XDocument xDoc = XDocument.Parse(soapResponse);
// 定义命名空间
XNamespace soapNs = "http://schemas.xmlsoap.org/soap/envelope/";
XNamespace tempNs = "http://tempuri.org/";
// 获取结果节点
var resultNode = xDoc.Descendants(soapNs + "Body")
.Descendants(tempNs + "GetUserInfoResponse")
.Descendants(tempNs + "GetUserInfoResult")
.FirstOrDefault();
if (resultNode != null)
{
string userName = resultNode.Element(tempNs + "UserName")?.Value;
string age = resultNode.Element(tempNs + "Age")?.Value;
string email = resultNode.Element(tempNs + "Email")?.Value;
Console.WriteLine($"用户名:{userName}");
Console.WriteLine($"年龄:{age}");
Console.WriteLine($"邮箱:{email}");
}
}
}
两种解析方式的选择建议
| 解析方式 | 优势 | 适用场景 |
|---|---|---|
| XmlDocument | 兼容旧版本.NET Framework,XPath查询灵活 | 传统.NET项目,需要复杂XPath查询的场景 |
| XDocument | 语法简洁,支持LINQ查询,可读性强 | .NET Framework 3.5及以上版本,需要简洁代码的场景 |
处理SOAP响应XML时,一定要注意命名空间的匹配,否则会出现查询不到节点的问题。如果响应结构复杂,也可以先将XML反序列化为对应的实体类,提升代码的可维护性。