Парсинг XML-ответа с сайта
В настоящее время я пишу сетевой логин для своего приложения для iOS, я провел некоторое исследование о том, какую библиотеку я должен использовать для обработки HTTP-запросов и XML-парсинга. Я закончил с AFNetworking и KissXML. Я также использую дополнение KissXML для AFNetworking. Запрос к сайту выполнен успешно, но я как бы застрял при разборе полученного XML.
Ответ выглядит так:
<login>
<response status="success" result="correct"/>
<data>
<username>testusername</username>
<country>Germany</country>
</data>
</login>
В моем коде я делаю HTTPRequest на сайт, чтобы получить XML, а затем пытаюсь проверить, действительны ли пользовательские данные или нет. Если они действительны, я хочу получить такие элементы, как имя пользователя и страна. Но если произошла ошибка, я хочу вернуть ее. Мой код софар:
{
__block BOOL success = NO;
__block NSError *localerror = nil;
__block NSString *domain = @"de.FranzBusch.Searchlight.ErrorDomain";
//HTTP Request
NSURL *url = [NSURL URLWithString:@"http://www.example.de/login.php"];
AFHTTPClient *client = [[AFHTTPClient alloc] initWithBaseURL:url];
NSDictionary *params = [NSDictionary dictionaryWithObjectsAndKeys:
email, @"email",
password, @"password", nil];
NSMutableURLRequest *request = [client requestWithMethod:@"POST" path:@"" parameters:params];
//Parse XML-Response
AFKissXMLRequestOperation *operation = [AFKissXMLRequestOperation XMLDocumentRequestOperationWithRequest:request success:^(NSURLRequest *request, NSHTTPURLResponse *response, DDXMLDocument *XMLDocument)
{
NSArray *resultNodes = nil;
NSError *responseError = nil;
resultNodes = [XMLDocument nodesForXPath:@"//response" error:&responseError];
if (responseError || ([resultNodes count] != 1))
{
localerror = [NSError errorWithDomain:domain code:-101 userInfo:[self generateErrorDictionary:@"XMLError"]];
success = NO;
}
else
{
for (DDXMLElement *element in resultNodes)
{
DDXMLNode *node = [element attributeForName:@"status"];
NSString *status = [node stringValue];
if ([status isEqualToString:@"fail"])
{
success = NO;
localerror = [NSError errorWithDomain:domain code:-101 userInfo:[self generateErrorDictionary:[[element attributeForName:@"result"] stringValue]]];
}
else
{
NSError *usernameError = nil;
NSArray *dataNodes = [XMLDocument nodesForXPath:@"//data//username" error:&usernameError];
if (usernameError || ([dataNodes count] != 1))
{
localerror = [NSError errorWithDomain:domain code:-101 userInfo:[self generateErrorDictionary:@"XMLError"]];
success = NO;
}
else
{
for (DDXMLELement *dataElement in dataNodes)
{
}
}
}
}
}
}failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, DDXMLDocument *XMLDocument)
{
NSLog(@"failure");
}];
[operation start];
return success;
}
Кто-нибудь может дать мне подсказку о том, как улучшить код и как это сделать правильно. Потому что, если я хочу назначить localerror на ошибку, я всегда получаю ошибку:(
1 ответ
Если я вас правильно понимаю, у вас проблемы с анализом XML-ответа. Я обычно просто использую потоковый анализатор XML Apple, NSXMLParser. Это просто, быстро и легко в использовании.
Я сделал небольшой пример проекта для вас (с использованием ARC), анализируя XML-ответ, который вы описываете, с помощью NSXMLParser: https://github.com/erikt/ETXMLParseSOExample
Вы можете поиграть с ним и запустить проект, но важной частью является делегат NSXMLParser:
@interface ETLoginInfoXMLParser ()
@property (strong,nonatomic) NSMutableString *currentElementValue;
@property (strong,nonatomic) ETLoginInfo *loginInfo;
@end
@implementation ETLoginInfoXMLParser
#pragma mark - NSXMLParserDelegate
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
{
if ([elementName isEqualToString:@"login"]) {
if (!self.loginInfo) {
self.loginInfo = [[ETLoginInfo alloc] init];
}
return;
}
if ([elementName isEqualToString:@"response"]) {
self.loginInfo.responseStatus = [attributeDict objectForKey:@"status"];
self.loginInfo.responseResult = [attributeDict objectForKey:@"result"];
}
}
- (void) parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
if (!self.currentElementValue) {
self.currentElementValue = [[NSMutableString alloc] initWithString:string];
} else {
[self.currentElementValue appendString:string];
}
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
if ([elementName isEqualToString:@"username"]) {
NSString *trimmedValue = [self.currentElementValue stringByTrimmingCharactersInSet:
[NSCharacterSet whitespaceAndNewlineCharacterSet]];
self.loginInfo.username = trimmedValue;
}
if ([elementName isEqualToString:@"country"]) {
NSString *trimmedValue = [self.currentElementValue stringByTrimmingCharactersInSet:
[NSCharacterSet whitespaceAndNewlineCharacterSet]];
self.loginInfo.country = trimmedValue;
}
self.currentElementValue = nil;
}
/** Parse XML login response */
+(ETLoginInfo *)parseXMLLoginResponse:(NSString *)xml {
ETLoginInfoXMLParser *loginInfoParser = [[ETLoginInfoXMLParser alloc] init];
NSXMLParser *xmlParser = [[NSXMLParser alloc] initWithData:[xml dataUsingEncoding:NSUTF8StringEncoding]];
[xmlParser setDelegate:loginInfoParser];
BOOL success = [xmlParser parse];
if (success) {
return loginInfoParser.loginInfo;
} else {
NSLog(@"Error parsing login information");
return nil;
}
}
@end
Я подключил его к глупому iOS-приложению, чтобы показать разбор этого XML-ответа:
<login>
<response status="success" result="correct"/>
<data>
<username>Willy Wonka</username>
<country>Germany</country>
</data>
</login>
Вы бы хотели более интересную иерархию моделей, как я - для простоты - просто поместите все в одну и ту же сущность