使用 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's
responseSerializer
时,成功块中的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的主要内容,如果未能解决你的问题,请参考以下文章