2011-01-14 19 views
10

Estoy tratando de consumir el siguiente servicio web http://ipinfodb.com/ip_location_api.php este servicio web devuelve una respuesta xml, el código siguiente obtiene la respuesta XML, pero de alguna manera al eliminar los valores de la respuesta XML no lo hace trabajo.Consumir un servicio web REST XML

¿Qué problema tiene mi código?

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(); 
    } 
} 

}

EDIT: esta es la respuesta XML devuelto

<?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> 

Respuesta

14

utilizo el este mismo API, me carga el XML de respuesta en un XDocument y analiza, por ejemplo,

// 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  
} 

Lo que también debe hacer es introducir una clase personalizada, p. GeoLocationInfo y ajuste su código en una función, p. GetGeoLocation(string ip) luego, en lugar de escribir la información en la ventana de la consola, puede llenar & devolver una instancia de esa clase.

15

Mi solución sería:

  • plazo la utilidad xsd.exe en su XML resultado dos veces para convertirlo en un XSD (primer paso) y una clase C# (segundo paso) - esto le daría un C# clase Response

  • siguiente, se puede deserializar fácilmente la respuesta a una instancia de esa clase:

    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()); 
    

    y ahora su result contendría una instancia de Response, con todos los elementos como buenos campos en su objeto.

Más información sobre xsd.exe en el MSDN doc page.

0

Creo que necesita usar _xtr.MoveToContent(); Método antes de usar el método de lectura ... Vea si eso funciona

1

Está asumiendo que el primer nodo será el nodo raíz, pero eso no es correcto. Primero tendrá el nodo XmlDeclaration y podrá seguir con los nodos Whitespace. Así que probablemente debería estructurar su código de algo así como

... 
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; 
... 

Pero dicho todo esto, yo personalmente preferiría crear XSD respuesta (mejor si el servicio web proporciona ella) y generar clases fuera de él (usando XSD.exe o Xsd2Code) para serializar/deserializarlo.

Cuestiones relacionadas