使用REST XML Web服务

我正在尝试使用以下Web服务http://ipinfodb.com/ip_location_api.php此Web服务返回xml响应,下面的代码获取XML响应,但不知何故,当从XML响应中定相值时,它不会工作。

我的代码出了什么问题?

using System; using System.Collections.Generic; using System.Text; using System.Web; using System.IO; using System.Net; using System.Xml; namespace ConsoleApplication3 { class Program { static void Main(string[] args) { HttpWebRequest request = null; HttpWebResponse response = null; String Xml; // Create the web request request = WebRequest.Create("http://api.ipinfodb.com/v2/ip_query.php?key=&ip=74.125.45.100&timezone=true") as HttpWebRequest; // Get response using (response = request.GetResponse() as HttpWebResponse) { // Get the response stream StreamReader reader = new StreamReader(response.GetResponseStream()); Xml = reader.ReadToEnd(); } // Console xml output Console.WriteLine(Xml); //see if we get the xml response, (YES we do) Console.ReadLine(); string _currentField = ""; StringReader _sr = new StringReader(Xml); XmlTextReader _xtr = new XmlTextReader(_sr); _xtr.XmlResolver = null; _xtr.WhitespaceHandling = WhitespaceHandling.None; // get the root node _xtr.Read(); if ((_xtr.NodeType == XmlNodeType.Element) && (_xtr.Name == "Response")) { while (_xtr.Read()) { if ((_xtr.NodeType == XmlNodeType.Element) && (!_xtr.IsEmptyElement)) { _currentField = _xtr.Name; _xtr.Read(); if (_xtr.NodeType == XmlNodeType.Text) { switch (_currentField) { case "Status": Console.WriteLine(_xtr.Value); //we print to console for testing purposes, normally assign it to a variable here! break; case "CountryCode": Console.WriteLine(_xtr.Value); break; case "CountryName": Console.WriteLine(_xtr.Value); break; case "RegionCode": Console.WriteLine(_xtr.Value); break; case "RegionName": Console.WriteLine(_xtr.Value); break; case "City": Console.WriteLine(_xtr.Value); break; case "ZipPostalCode": Console.WriteLine(_xtr.Value); break; case "Latitude": Console.WriteLine(_xtr.Value); break; case "Longitude": Console.WriteLine(_xtr.Value); break; case "Gmtoffset": Console.WriteLine(_xtr.Value); break; case "Dstoffset": Console.WriteLine(_xtr.Value); break; case "TimezoneName": Console.WriteLine(_xtr.Value); break; case "Isdst": Console.WriteLine(_xtr.Value); break; case "Ip": Console.WriteLine(_xtr.Value); break; default: // unknown field throw new Exception("Unknown field in response."); } } } } } Console.ReadLine(); } } 

}

编辑:这是返回的XML响应

   -  OK US United States 06 California Mountain View 94043 37.4192 -122.057 -28800 0 America/Los_Angeles 0 74.125.45.100  

我使用相同的API,我将响应XML加载到XDocument并解析例如

 // build URL up at runtime string apiKey = ConfigurationManager.AppSettings["geoApiKey"]; string url = String.Format(ConfigurationManager.AppSettings["geoApiUrl"], apiKey, ip); WebRequest request = WebRequest.Create(url); try { WebResponse response = request.GetResponse(); using (var sr = new System.IO.StreamReader(response.GetResponseStream())) { XDocument xmlDoc = new XDocument(); try { xmlDoc = XDocument.Parse(sr.ReadToEnd()); string status = xmlDoc.Root.Element("Status").Value; Console.WriteLine("Response status: {0}", status); if (status == "OK") { // if the status is OK it's normally safe to assume the required elements // are there. However, if you want to be safe you can always check the element // exists before retrieving the value Console.WriteLine(xmlDoc.Root.Element("CountryCode").Value); Console.WriteLine(xmlDoc.Root.Element("CountryName").Value); ... } } catch (Exception) { // handle if necessary } } } catch (WebException) { // handle if necessary } 

您还应该做的是引入一个自定义类,例如GeoLocationInfo并将您的代码包装在一个函数中,例如GetGeoLocation(string ip)然后您可以填充并返回该类的实例,而不是将信息写入控制台窗口。

我的解决方案是:

  • 在结果XML上运行xsd.exe实用程序两次以将其转换为XSD(第一步)和C#类(第二步) – 这将为您提供C#类Response

  • 接下来,您可以轻松地将响应反序列化为该类的实例:

     HttpWebRequest request = WebRequest.Create("http://api.ipinfodb.com/v2/ip_query.php?key=--yourkey--&ip=74.125.45.100&timezone=true") as HttpWebRequest; XmlSerializer ser = new XmlSerializer(typeof(Response)); WebResponse response = request.GetResponse(); var result = ser.Deserialize(response.GetResponseStream()); 

    现在你的result将包含一个Response实例,所有元素都是你对象中的好字段。

在其MSDN文档页面上阅读有关xsd.exe的更多信息。

您假设第一个节点将是根节点,但这不正确。 您将首先拥有XmlDeclaration节点,然后可能会有Whitespace节点。 所以你应该把你的代码构造成类似的东西

 ... bool isRootRead = false; while (_xtr.Read()) { if (_xtr.NodeType == XmlNodeType.Element) { if (!isRootRead) { if (_xter.Name == "Response") { // root found isRootRead = true; } // jump to next node if root node / ignore other nodes till root element is read continue; } _currentField = _xtr.Name; _xtr.Read(); if (_xtr.NodeType == XmlNodeType.Text) { switch (_currentField) { case "Status": Console.WriteLine(_xtr.Value); //we print to console for testing purposes, normally assign it to a variable here! break; ... 

但是说,我个人更喜欢创建响应XSD(如果Web服务提供它更好)并从中生成类(使用XSD.exe或Xsd2Code )来序列化/反序列化它。

我认为你需要使用_xtr.MoveToContent(); 使用read方法之前的方法..看看是否有效