Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Parsing XML with AFNetworking

I am fairly new with iOS and is trying to do a REST request and fetch some XML data, parse that and ideally put into a custom Object. But for now I am stuck with the getting XML data.

I found this code snippet on Github/AFNetworking..

- (void) fetchInterestData{
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
manager.responseSerializer = [AFXMLResponseSerializer new];
NSDictionary *parameters = @{@"foo": @"bar"};
[manager POST:@"http://www.raywenderlich.com/downloads/weather_sample/weather.php?format=json" parameters:parameters success:^(AFHTTPRequestOperation *operation, id responseObject) {
    NSLog(@"JSON: %@", responseObject);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
    NSLog(@"Error: %@", error);
}];
}

It works and fetches a JSON object. But I want to get the XML..

If I use http://www.raywenderlich.com/downloads/weather_sample/weather.php?format=xml instead there is an xml object. But now the code breaks down completely. I was hoping to at least get the xml as a string object.

What do I need to change to fetch the xml and assumingly I want to fetch a xml object of following structure:

<RootNode>
<Banks>
  <Bank>
   <BankId>17</BankId>
   <BankName>Bluestep</BankName>
   <BankUrl>http://www.bluestep.se</BankUrl>
   <BankImage>
   http://smartkalkyl.se/smartfiles/layout/banklogos/bluestep.png
   </BankImage>
   <Rates>
       <Rate>
          <RateDate>2013-12-05</RateDate>
          <RateType>5</RateType>
          <RateInterest>6,23</RateInterest>
          <RateDescription/>
          <RateBefore>6,27</RateBefore>
          <RateChange>False</RateChange>
          <RateBeforeDate>2013-08-13</RateBeforeDate>
     </Rate>
   </Rates>
   </Bank>
   <Bank>
   ...

How can I do that?

UPDATE: New code..

AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
AFHTTPRequestSerializer * requestSerializer = [AFHTTPRequestSerializer serializer];
NSString *ua = @"Mozilla/5.0 (iPhone; CPU iPhone OS 6_0 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Version/6.0 Mobile/10A5376e Safari/8536.25";
[requestSerializer setValue:ua forHTTPHeaderField:@"User-Agent"];
[requestSerializer setValue:@"application/xml" forHTTPHeaderField:@"Content-type"];
manager.requestSerializer = requestSerializer;

NSDictionary *parameters = @{@"foo": @"bar"};


[manager POST:@"http://smartkalkyl.se/rateapp.aspx?user=xxxx&pass=xxx"
   parameters:parameters
success:^(AFHTTPRequestOperation *operation, id responseObject) {
    NSData * data = (NSData *)responseObject;
    self.fetchedXML = [NSString stringWithUTF8String:[data bytes]];
    //NSLog(@"Response string: %@", self.fetchedXML);
}
failure:^(AFHTTPRequestOperation *operation, NSError *error) {
    NSLog(@"Error: %@", error);
}];

But this gives me an error..

2013-12-06 00:04:10.657 TabbedDemo[38335:a0b] Error: Error Domain=AFNetworkingErrorDomain Code=-1016 "Request failed: unacceptable content-type: text/xml" UserInfo=0x8d80ac0 {NSErrorFailingURLKey=http://smartkalkyl.se/rateapp.aspx?user=xxxx&pass=xxxx, AFNetworkingOperationFailingURLResponseErrorKey=<NSHTTPURLResponse: 0x8a75230> { URL: http://smartkalkyl.se/rateapp.aspx?user=xxxx&pass=xxxx } { status code: 200, headers {
"Cache-Control" = private;
"Content-Encoding" = deflate;
"Content-Length" = 1260;
"Content-Type" = "text/xml; charset=iso-8859-1";
Date = "Thu, 05 Dec 2013 23:03:47 GMT";
Server = "Microsoft-IIS/7.5";
"Set-Cookie" = "ASP.NET_SessionId=ad3zikxbh4bcawxulkhwt2j3; path=/; HttpOnly";
"X-AspNet-Version" = "4.0.30319";
"X-Powered-By" = "UrlRewriter.NET 2.0.0, ASP.NET";
} }, NSLocalizedDescription=Request failed: unacceptable content-type: text/xml}

Any idea what could be the problem?

I am doing similar operation in the Android version of the app and this is the code that works there and that work. I never set any content type there..

// defaultHttpClient
DefaultHttpClient httpClient = new DefaultHttpClient();
HttpProtocolParams.setUserAgent(httpClient.getParams(),
System.getProperty("http.agent"));
HttpPost httpPost = new HttpPost(url);

HttpResponse httpResponse = httpClient.execute(httpPost);
HttpEntity httpEntity = httpResponse.getEntity();
xml = EntityUtils.toString(httpEntity);
like image 864
Sebastian L Avatar asked Dec 05 '13 14:12

Sebastian L


4 Answers

This library is the best -> https://github.com/nicklockwood/XMLDictionary

NSURL *URL = [NSURL URLWithString:@"http://maps.googleapis.com/maps/api/directions/xml?origin=Toronto&destination=Montreal&sensor=false"];
NSURLRequest *request = [NSURLRequest requestWithURL:URL];
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
operation.responseSerializer = [AFXMLDictionaryResponseSerializer serializer];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {

    NSDictionary *d0 = [NSDictionary dictionaryWithXMLParser:(NSXMLParser*)responseObject];
    NSLog(@"d0:%@", d0);
} failure:nil];

[operation start];
like image 65
johndpope Avatar answered Nov 16 '22 04:11

johndpope


Based on your updated code, you need to add a response serializer, and you also need to translate the NSData properly:

AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
AFHTTPRequestSerializer * requestSerializer = [AFHTTPRequestSerializer serializer];
AFHTTPResponseSerializer * responseSerializer = [AFHTTPResponseSerializer serializer];

NSString *ua = @"Mozilla/5.0 (iPhone; CPU iPhone OS 6_0 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Version/6.0 Mobile/10A5376e Safari/8536.25";
[requestSerializer setValue:ua forHTTPHeaderField:@"User-Agent"];
//    [requestSerializer setValue:@"application/xml" forHTTPHeaderField:@"Content-type"];
responseSerializer.acceptableContentTypes = [NSSet setWithObjects:@"text/xml", nil];
manager.responseSerializer = responseSerializer;
manager.requestSerializer = requestSerializer;

NSDictionary *parameters = @{@"foo": @"bar"};

[manager POST:@"http://smartkalkyl.se/rateapp.aspx?user=xxxxx&pass=xxxxxx"
   parameters:parameters
      success:^(AFHTTPRequestOperation *operation, id responseObject) {
          NSData * data = (NSData *)responseObject;
          self.fetchedXML = [NSString stringWithCString:[data bytes] encoding:NSISOLatin1StringEncoding];
          NSLog(@"Response string: %@", self.fetchedXML);
      }
      failure:^(AFHTTPRequestOperation *operation, NSError *error) {
          NSLog(@"Error: %@", error);
      }];

Your response is coming back as text/xml, and the default response serializer needs to be set to accept that.

The data isn't coming back as UTF8 but ascii, so we need to set that appropriately as well.

I gave it a shot in the simulator and it's working on my end.

edit: seems the data is in ISO latin-1 format. my bad.

like image 17
KaosDG Avatar answered Nov 16 '22 03:11

KaosDG


  1. When you use AFXMLResponseSerializer as AFHTTPRequestOperationManager's responseSerializer, the responseObject in success block is a NSXMLParser object, you should implemente NSXMLParser's delegate,and parsing xml

  2. If you want to get the xml as a string object.Use the code below:

Using AFHTTPResponseSerializer, then encode the response data to string

    AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
    manager.responseSerializer = [AFHTTPResponseSerializer new];
    NSDictionary *parameters = @{@"foo": @"bar"};
    [manager POST:@"http://www.raywenderlich.com/downloads/weather_sample/weather.php?format=xml" parameters:parameters success:^(AFHTTPRequestOperation *operation, id responseObject) {
        NSData * data = (NSData *)responseObject;
        NSLog(@"Response string: %@", [NSString stringWithUTF8String:[data bytes]]);
    } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
        NSLog(@"Error: %@", error);
    }];

UPDATE

set User-Agent:

    AFHTTPRequestSerializer * requestSerializer = [AFHTTPRequestSerializer serializer];
    [requestSerializer setValue:@"your user agent" forHTTPHeaderField:@"User-Agent"];
    manager.requestSerializer = requestSerializer;
like image 12
Joiningss Avatar answered Nov 16 '22 04:11

Joiningss


you can try to use XmlReader to do what you want, it's pretty simple. Look here How to reloadData in tableView with didSelectedRowAtIndexPath and call group of methods in it

like image 1
daleijn Avatar answered Nov 16 '22 05:11

daleijn