Sebastian L
Sebastian L

Reputation: 924

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

Upvotes: 9

Views: 18958

Answers (4)

johndpope
johndpope

Reputation: 5249

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

Upvotes: 7

Joiningss
Joiningss

Reputation: 1320

  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;

Upvotes: 12

KaosDG
KaosDG

Reputation: 466

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.

Upvotes: 17

daleijn
daleijn

Reputation: 738

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

Upvotes: 1

Related Questions