如何将动态调用SOAP WebService的XML结果转回原始DataTable类型?
解决ASMX WebService返回SOAP XML转DataTable的问题
你有一个ASMX WebService(FoodWs.asmx),其WebMethod RetrieveData 返回DataTable类型数据,通过动态调用未添加Web引用的方式获取到了SOAP结果的XML字符串soapResult,需要将其转换为原始的DataTable类型。
注意:你的WebMethod代码中存在列名拼写错误——定义列时写了
Prrice,但赋值用的是Price,建议统一为Price,否则会导致数据写入失败或解析异常。
方案一:利用DataSet.ReadXml直接解析(优先推荐)
ASMX返回的DataTable在SOAP中的结构完全符合DataSet的XML规范,因此可以直接用DataSet.ReadXml快速解析,无需手动处理节点:
修改你的Execute方法如下:
public static void Execute() { HttpWebRequest request = CreateWebRequest(); XmlDocument soapEnvelopeXml = new XmlDocument(); soapEnvelopeXml.LoadXml(@"<?xml version=""1.0"" encoding=""utf-8""?> <soap:Envelope xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xmlns:xsd=""http://www.w3.org/2001/XMLSchema"" xmlns:soap=""http://schemas.xmlsoap.org/soap/envelope/""> <soap:Body> <RetrieveData xmlns=""http://tempuri.org/"" /> </soap:Body> </soap:Envelope>"); using (Stream stream = request.GetRequestStream()) { soapEnvelopeXml.Save(stream); } using (WebResponse response = request.GetResponse()) { using (StreamReader rd = new StreamReader(response.GetResponseStream())) { string soapResult = rd.ReadToEnd(); // 核心解析逻辑 DataSet ds = new DataSet(); using (XmlReader reader = XmlReader.Create(new StringReader(soapResult))) { // 定位到返回结果的节点(跳过SOAP信封和Body) reader.ReadToFollowing("RetrieveDataResult", "http://tempuri.org/"); // 读取节点内的XML到DataSet ds.ReadXml(reader.ReadSubtree()); } // 第一个表就是目标DataTable DataTable resultDt = ds.Tables[0]; // 测试输出(可替换为你的业务逻辑) foreach (DataRow row in resultDt.Rows) { HttpContext.Current.Response.Write($"Name: {row["Name"]}, Price: {row["Price"]}<br/>"); } } } }
方案二:手动解析XmlDocument构建DataTable(精细控制场景)
如果需要自定义解析逻辑,可以手动遍历XML节点构建DataTable:
public static void Execute() { HttpWebRequest request = CreateWebRequest(); XmlDocument soapEnvelopeXml = new XmlDocument(); soapEnvelopeXml.LoadXml(@"<?xml version=""1.0"" encoding=""utf-8""?> <soap:Envelope xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xmlns:xsd=""http://www.w3.org/2001/XMLSchema"" xmlns:soap=""http://schemas.xmlsoap.org/soap/envelope/""> <soap:Body> <RetrieveData xmlns=""http://tempuri.org/"" /> </soap:Body> </soap:Envelope>"); using (Stream stream = request.GetRequestStream()) { soapEnvelopeXml.Save(stream); } using (WebResponse response = request.GetResponse()) { using (StreamReader rd = new StreamReader(response.GetResponseStream())) { string soapResult = rd.ReadToEnd(); XmlDocument doc = new XmlDocument(); doc.LoadXml(soapResult); // 设置命名空间管理器(必须匹配SOAP中的命名空间) XmlNamespaceManager nsMgr = new XmlNamespaceManager(doc.NameTable); nsMgr.AddNamespace("soap", "http://schemas.xmlsoap.org/soap/envelope/"); nsMgr.AddNamespace("temp", "http://tempuri.org/"); nsMgr.AddNamespace("diffgr", "urn:schemas-microsoft-com:xml-diffgram-v1"); nsMgr.AddNamespace("msdata", "urn:schemas-microsoft-com:xml-msdata"); // 定位到DataTable的实际数据节点 XmlNode dataNode = doc.SelectSingleNode("//diffgr:diffgram/msdata:DataSet/temp:Food", nsMgr); if (dataNode != null) { DataTable dt = new DataTable("Food"); // 添加列(根据实际节点类型调整) dt.Columns.Add("Name", typeof(string)); dt.Columns.Add("Price", typeof(int)); // 遍历行节点填充数据 XmlNodeList rowNodes = dataNode.SelectNodes("temp:Food", nsMgr); foreach (XmlNode rowNode in rowNodes) { DataRow dr = dt.NewRow(); dr["Name"] = rowNode.SelectSingleNode("temp:Name", nsMgr).InnerText; dr["Price"] = int.Parse(rowNode.SelectSingleNode("temp:Price", nsMgr).InnerText); dt.Rows.Add(dr); } // 测试输出 foreach (DataRow row in dt.Rows) { HttpContext.Current.Response.Write($"Name: {row["Name"]}, Price: {row["Price"]}<br/>"); } } } } }
关键注意事项
- 必须正确匹配SOAP中的命名空间,ASMX默认使用
http://tempuri.org/作为服务命名空间 - 方案一的
DataSet.ReadXml会自动处理列类型和数据格式,效率更高且不易出错,优先使用 - 若WebMethod返回多个DataTable,DataSet会自动生成对应数量的表,可通过表名或索引获取
内容的提问来源于stack exchange,提问作者Raymond Morphy
相关产品推荐
相关产品推荐

