Разбор 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;
}

Может ли кто-нибудь дать мне подсказку о том, как улучшить код и как сделать это правильно. Потому что, если я хочу присвоить локальную ошибку ошибке, я всегда получаю сообщение об ошибке :(


person digga    schedule 06.11.2012    source источник
comment
Вы когда-нибудь находили свое решение, используя AFNetwork и KissXML, или вы выбрали ответ ниже? Если да, поделитесь своим заключением с KissXML/AFNetwork.   -  person NodeDad    schedule 08.05.2013


Ответы (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>

введите здесь описание изображениявведите здесь описание изображения

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

person Erik Tjernlund    schedule 06.11.2012
comment
Спасибо за ваш комментарий. Но я хотел использовать KissXML, потому что расширение для AFNetworking довольно приятное. Чтобы описать мою проблему более подробно. Я борюсь с назначением ошибки. Я использую локальный __block NSError, но я не могу назначить его ошибке, указанной при вызове метода. Он говорит, что не может назначить NSError __block для NSError. Также я не знаю, правильно ли циклы for. - person digga; 07.11.2012