2010-01-05 6 views
8

Есть ли у кого-нибудь представление о том, как анализировать следующий XML-код с использованием класса NSXMLParser, управляемого событиями?Как использовать NSXMLParser для синтаксического анализа элементов parent-child, имеющих одно и то же имя

<Node> 
    <name> Main </name> 
    <Node> 
    <name> Child 1 </name> 
    </Node> 

    <Node> 
    <name> Child 2 </name> 
    </Node> 
</Node> 

Я хочу, чтобы собрать все три имени из этого XML-файла, возможно, или я должен изменить, чтобы на основе дерева разбора?

ответ

31

Это обычная проблема с синтаксическими анализаторами, подобными этой, типа SAX, где вам необходимо вручную отслеживать текущую глубину дерева XML, в котором вы находитесь. Проблема, как всегда, заключается в том, что загрузка все дерево в структуре DOM в памяти может быть невозможно, в зависимости от размера данных, которые вы хотите манипулировать.

Следующий код показывает класс, который делает эту работу:

#import <Foundation/Foundation.h> 

@interface Test : NSObject <NSXMLParserDelegate> 
{ 
@private 
    NSXMLParser *xmlParser; 
    NSInteger depth; 
    NSMutableString *currentName; 
    NSString *currentElement; 
} 

- (void)start; 

@end 

Это реализация:

#import "Test.h" 

@interface Test() 
- (void)showCurrentDepth; 
@end 


@implementation Test 

- (void)dealloc 
{ 
    [currentElement release]; 
    [currentName release]; 
    [xmlParser release]; 
    [super dealloc]; 
} 

- (void)start 
{ 
    NSString *xml = @"<?xml version=\"1.0\" encoding=\"UTF-8\" ?><Node><name>Main</name><Node><name>Child 1</name></Node><Node><name>Child 2</name></Node></Node>"; 
    xmlParser = [[NSXMLParser alloc] initWithData:[xml dataUsingEncoding:NSUTF8StringEncoding]]; 
    [xmlParser setDelegate:self]; 
    [xmlParser setShouldProcessNamespaces:NO]; 
    [xmlParser setShouldReportNamespacePrefixes:NO]; 
    [xmlParser setShouldResolveExternalEntities:NO]; 
    [xmlParser parse]; 

} 

#pragma mark - 
#pragma mark NSXMLParserDelegate methods 

- (void)parserDidStartDocument:(NSXMLParser *)parser 
{ 
    NSLog(@"Document started", nil); 
    depth = 0; 
    currentElement = nil; 
} 

- (void)parser:(NSXMLParser *)parser parseErrorOccurred:(NSError *)parseError 
{ 
    NSLog(@"Error: %@", [parseError localizedDescription]); 
} 

- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName 
    namespaceURI:(NSString *)namespaceURI 
qualifiedName:(NSString *)qName 
    attributes:(NSDictionary *)attributeDict 
{ 
    [currentElement release]; 
    currentElement = [elementName copy]; 

    if ([currentElement isEqualToString:@"Node"]) 
    { 
     ++depth; 
     [self showCurrentDepth]; 
    } 
    else if ([currentElement isEqualToString:@"name"]) 
    { 
     [currentName release]; 
     currentName = [[NSMutableString alloc] init]; 
    } 
} 

- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName 
    namespaceURI:(NSString *)namespaceURI 
qualifiedName:(NSString *)qName 
{ 

    if ([elementName isEqualToString:@"Node"]) 
    { 
     --depth; 
     [self showCurrentDepth]; 
    } 
    else if ([elementName isEqualToString:@"name"]) 
    { 
     if (depth == 1) 
     { 
      NSLog(@"Outer name tag: %@", currentName); 
     } 
     else 
     { 
      NSLog(@"Inner name tag: %@", currentName); 
     } 
    } 
}   

- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string 
{ 
    if ([currentElement isEqualToString:@"name"]) 
    { 
     [currentName appendString:string]; 
    } 
} 

- (void)parserDidEndDocument:(NSXMLParser *)parser 
{ 
    NSLog(@"Document finished", nil); 
} 

#pragma mark - 
#pragma mark Private methods 

- (void)showCurrentDepth 
{ 
    NSLog(@"Current depth: %d", depth); 
} 

@end 

Это результат работы инструмента командной строки, которая запускает «Пуск» метод выше:

Document started 
Current depth: 1 
Outer name tag: Main 
Current depth: 2 
Inner name tag: Child 1 
Current depth: 1 
Current depth: 2 
Inner name tag: Child 2 
Current depth: 1 
Current depth: 0 
Document finished 
+0

спасибо за ваше решение, он отлично работает для меня. Файл xml длинный, я уменьшил его, чтобы соответствовать вопросу. –

5
- (NSInteger)columnNumber 

дает уровень вложенности NSXMLParser

-1

очень простой способ решить, чем принято отвечать, для коротких файлов XML: пример

XML:

<cotacoes> 
    <bovespa> 
      <cotacao>50058</cotacao> 
      <variacao>-0.16</variacao> 
    </bovespa> 
    <dolar> 
      <cotacao>3.4610</cotacao> 
      <variacao>+0.29</variacao> 
    </dolar> 
    <euro> 
      <cotacao>3.7673</cotacao> 
      <variacao>-0.25</variacao> 
    </euro> 
    <atualizacao>04/08/15 - 18:14</atualizacao> 
</cotacoes> 

Реализовать счетчик:

@implementation className{ 
    int parserCounter; 
} 

- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string 
{ 
    parserCounter++; 

    NSLog(@"%d: %@",contadorParser,string); 

    if (parserCounter == 3) doAnythingFor3; 
    if (parserCounter == 5) doAnythingFor5; 
    if (parserCounter == 9) doAnythingFor9; 
    if (parserCounter == 11) doAnythingFor11; 
    if (parserCounter == 15) doAnythingFor15; 
    if (parserCounter == 17) doAnythingFor17; 
    if (parserCounter == 20) doAnythingFor20; 

} 

Как я узнаю число ведьм - ведьма-узел? Увидев журнал. Это будет что-то вроде:

2015-08-04 23:36:08.070 Tesouro Direto[7252:1554402] 1:  
2015-08-04 23:36:08.070 Tesouro Direto[7252:1554402] 2:  
2015-08-04 23:36:08.071 Tesouro Direto[7252:1554402] 3:  50058 
2015-08-04 23:36:08.105 Tesouro Direto[7252:1554402] 4:  
2015-08-04 23:36:08.105 Tesouro Direto[7252:1554402] 5:  -0.16 
2015-08-04 23:36:08.131 Tesouro Direto[7252:1554402] 6:  
2015-08-04 23:36:08.132 Tesouro Direto[7252:1554402] 7:  
2015-08-04 23:36:08.132 Tesouro Direto[7252:1554402] 8:  
2015-08-04 23:36:08.132 Tesouro Direto[7252:1554402] 9:  3.4610 
2015-08-04 23:36:08.156 Tesouro Direto[7252:1554402] 10:  
2015-08-04 23:36:08.156 Tesouro Direto[7252:1554402] 11: +0.29 
2015-08-04 23:36:08.180 Tesouro Direto[7252:1554402] 12:  
2015-08-04 23:36:08.180 Tesouro Direto[7252:1554402] 13:  
2015-08-04 23:36:08.180 Tesouro Direto[7252:1554402] 14:  
2015-08-04 23:36:08.180 Tesouro Direto[7252:1554402] 15: 3.7673 
2015-08-04 23:36:08.203 Tesouro Direto[7252:1554402] 16:  
2015-08-04 23:36:08.203 Tesouro Direto[7252:1554402] 17: -0.25 
2015-08-04 23:36:08.226 Tesouro Direto[7252:1554402] 18:  
2015-08-04 23:36:08.227 Tesouro Direto[7252:1554402] 19:  
2015-08-04 23:36:08.227 Tesouro Direto[7252:1554402] 20: 04/08/15 - 18:14 
2015-08-04 23:36:08.227 Tesouro Direto[7252:1554402] 21: 

В журнале будет показано, что номер ведьмы - это каждый узел.