如何在C#中将SOAP XML响应转换为DataTable
解决SOAP XML转C# DataTable无数据问题
原代码问题分析
- 未处理XML命名空间:原XML包含
soap和http://www.crifbuergel.de/bone_v1两个命名空间,直接使用Name.ToString()会忽略命名空间,导致无法匹配目标节点。 - 错误的模板节点选择:原代码取第一个子节点
correlationId作为列模板,该节点无下级元素,导致DataTable未创建任何列。 - 目标节点定位错误:没有定位到实际数据所在的
candidate节点,而是遍历了无关节点集合。
正确实现代码
using System.Data; using System.Xml.Linq; public DataTable ConvertSoapXmlToDataTable(string xmlData) { // 定义XML命名空间 XNamespace soapNs = "http://schemas.xmlsoap.org/soap/envelope/"; XNamespace boneNs = "http://www.crifbuergel.de/bone_v1"; // 解析XML XElement root = XElement.Parse(xmlData); // 定位所有candidate节点(实际数据行) var candidates = root.Descendants(soapNs + "Body") .Elements(boneNs + "searchResponse") .Elements(boneNs + "candidate"); DataTable dt = new DataTable(); // 预定义所有需要的列(覆盖所有可能的字段) dt.Columns.Add("VAT", typeof(string)); dt.Columns.Add("ONR", typeof(string)); dt.Columns.Add("TAX_ID", typeof(string)); dt.Columns.Add("RegistryType", typeof(string)); dt.Columns.Add("RegistryNumber", typeof(string)); dt.Columns.Add("RegistryCity", typeof(string)); dt.Columns.Add("HitType", typeof(string)); dt.Columns.Add("Name", typeof(string)); dt.Columns.Add("Street", typeof(string)); dt.Columns.Add("House", typeof(string)); dt.Columns.Add("City", typeof(string)); dt.Columns.Add("Zip", typeof(string)); dt.Columns.Add("CountryCode", typeof(string)); dt.Columns.Add("CountryText", typeof(string)); dt.Columns.Add("UnitType", typeof(string)); dt.Columns.Add("Status", typeof(string)); dt.Columns.Add("Similarity", typeof(int)); // 遍历每个candidate节点,填充数据行 foreach (var candidate in candidates) { DataRow dr = dt.NewRow(); // 处理identifier节点(多个,按type区分) foreach (var identifier in candidate.Elements(boneNs + "identifier")) { string type = identifier.Element(boneNs + "type")?.Value; string value = identifier.Element(boneNs + "value")?.Value; if (!string.IsNullOrEmpty(type) && dt.Columns.Contains(type)) { dr[type] = value; } } // 处理registry节点 var registry = candidate.Element(boneNs + "registry"); if (registry != null) { dr["RegistryType"] = registry.Element(boneNs + "type")?.Value; dr["RegistryNumber"] = registry.Element(boneNs + "number")?.Value; dr["RegistryCity"] = registry.Element(boneNs + "city")?.Value; } // 处理直接字段 dr["HitType"] = candidate.Element(boneNs + "hitType")?.Value; dr["Name"] = candidate.Element(boneNs + "name")?.Value; dr["UnitType"] = candidate.Element(boneNs + "unitType")?.Value; dr["Status"] = candidate.Element(boneNs + "status")?.Value; if (int.TryParse(candidate.Element(boneNs + "similarity")?.Value, out int similarity)) { dr["Similarity"] = similarity; } // 处理location节点 var location = candidate.Element(boneNs + "location"); if (location != null) { dr["Street"] = location.Element(boneNs + "street")?.Value; dr["House"] = location.Element(boneNs + "house")?.Value; dr["City"] = location.Element(boneNs + "city")?.Value; dr["Zip"] = location.Element(boneNs + "zip")?.Value; var country = location.Element(boneNs + "country"); if (country != null) { dr["CountryCode"] = country.Element(boneNs + "code")?.Value; dr["CountryText"] = country.Element(boneNs + "text")?.Value; } } dt.Rows.Add(dr); } return dt; }
代码说明
- 命名空间处理:明确声明SOAP和业务数据的命名空间,确保能准确定位节点。
- 列预定义:根据XML结构提前定义所有可能的列,避免因节点缺失导致的异常。
- 节点遍历逻辑:
- 对
identifier节点按type值匹配到对应列。 - 分层处理嵌套节点(
registry、location),提取子节点值。 - 对数值类型字段(如
similarity)做类型转换,保证数据类型正确。
- 对
内容的提问来源于stack exchange,提问作者Shakil Ahmed
相关产品推荐
相关产品推荐

