使用 AFNetworking 解析 XML

Posted

技术标签:

【中文标题】使用 AFNetworking 解析 XML【英文标题】:Parsing XML with AFNetworking 【发布时间】:2013-12-05 14:03:33 【问题描述】:

我对 ios 很陌生,正在尝试执行 REST 请求并获取一些 XML 数据,对其进行解析并理想地放入自定义对象中。但现在我被困在获取 XML 数据上。

我在 Github/AFNetworking 上找到了这段代码 sn-p..

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

它可以工作并获取一个 JSON 对象。但我想得到 XML..

如果我使用 http://www.raywenderlich.com/downloads/weather_sample/weather.php?format=xml 代替,则有一个 xml 对象。但是现在代码完全崩溃了。我希望至少将 xml 作为字符串对象。

我需要更改什么来获取 xml,假设我想获取以下结构的 xml 对象:

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

我该怎么做?

更新:新代码..

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

但这给了我一个错误..

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

知道可能是什么问题吗?

我在应用程序的 android 版本中进行了类似的操作,这是在那里工作的代码并且工作正常。我从来没有在那里设置任何内容类型..

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

【问题讨论】:

好吧,您不应该假设 AFN 是 XML 解析器或 JSON 解析器。只有一些方便的功能,例如“JSON Response Serializer”,严格来说不需要成为网络库的一部分。您可以使用几行代码完成相同的 JSON 序列化器功能。解析 XML 更复杂,但您可以编写自己的 XML 序列化程序或使用“内置”AFXMLParserResponseSerializer,如果这适合您的需要。 解析 XML 是我的次要目标。最初我只想从服务器检索 XML 作为字符串或类似的。 【参考方案1】:

根据您更新的代码,您需要添加一个响应序列化程序,并且您还需要正确翻译 NSData:

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

您的响应以 text/xml 形式返回,需要将默认响应序列化程序设置为接受。

返回的数据不是 UTF8 而是 ascii,因此我们也需要适当地设置它。

我在模拟器中试了一下,它正在我的最终工作。

编辑:数据似乎是 ISO latin-1 格式。我的错。

【讨论】:

【参考方案2】:

    当你使用AFXMLResponseSerializer作为AFHTTPRequestOperationManager'sresponseSerializer时,成功块中的responseObject是一个NSXMLParser对象,你应该实现NSXMLParser's委托,并解析xml

    如果你想获取xml作为字符串对象。使用下面的代码:

使用AFHTTPResponseSerializer,然后将响应数据编码成字符串

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

更新

设置用户代理:

    AFHTTPRequestSerializer * requestSerializer = [AFHTTPRequestSerializer serializer];
    [requestSerializer setValue:@"your user agent" forHTTPHeaderField:@"User-Agent"];
    manager.requestSerializer = requestSerializer;

【讨论】:

这看起来可以工作,但在我的真实 URL 中,我需要提供一个用户代理。我该怎么做? 感谢@Joiningss!我仍然遇到一个问题......我用新代码和我不理解的错误日志更新了主要问题。我将内容类型设置为标题,但它仍然抱怨.. @SebastianL KaosDG 的回答是正确的。您错过了响应序列化程序,并且响应字符集是 iso-8859-1【参考方案3】:

这个库是最好的 -> 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];

【讨论】:

【参考方案4】:

你可以尝试使用 XmlReader 来做你想做的事,这很简单。看这里How to reloadData in tableView with didSelectedRowAtIndexPath and call group of methods in it

【讨论】:

以上是关于使用 AFNetworking 解析 XML的主要内容,如果未能解决你的问题,请参考以下文章

使用 AFNetworking 解析 XML

使用 AFNetworking 2.0 异常解析 JSON

使用 AFNetworking 解析 JSON

使用 AFNetworking 解析 JSON

使用 AFNetworking 解析 JSON 文件

使用 AFNetworking 将 JSON 解析为 NSDictionary