Парсинг 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>

Вы бы хотели более интересную иерархию моделей, как я - для простоты - просто поместите все в одну и ту же сущность

Другие вопросы по тегам