2011-01-14 136 views
10

我试图使用以下Web服务http://ipinfodb.com/ip_location_api.php 此Web服务返回xml响应,下面的代码获取XML响应,但是在某种程度上,当从XML响应中逐步调整值时,它不会工作。使用REST XML Web服务

我的代码有什么问题?

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=<yourkey>&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响应中返回

<?xml version="1.0" encoding="UTF-8" ?> 
- <Response> 
    <Status>OK</Status> 
    <CountryCode>US</CountryCode> 
    <CountryName>United States</CountryName> 
    <RegionCode>06</RegionCode> 
    <RegionName>California</RegionName> 
    <City>Mountain View</City> 
    <ZipPostalCode>94043</ZipPostalCode> 
    <Latitude>37.4192</Latitude> 
    <Longitude>-122.057</Longitude> 
    <Gmtoffset>-28800</Gmtoffset> 
    <Dstoffset>0</Dstoffset> 
    <TimezoneName>America/Los_Angeles</TimezoneName> 
    <Isdst>0</Isdst> 
    <Ip>74.125.45.100</Ip> 
    </Response> 

回答

14

我使用此相同的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)然后而不是写信息到控制台窗口,您可以填充&返回该类的一个实例。

15

我的解决办法是:

  • 运行xsd.exe工具上你的结果XML两次将其转换为一个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的实例,并将所有元素作为对象中的不错字段。

了解更多关于xsd.exe在其MSDN doc page

0

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

1

你假设第一个节点将是根节点,但这是不正确的。您将首先有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(更好,如果网络服务提供IT)和(使用XSD.EXE或Xsd2Code生成类出来的)为序列化/反序列化它。