2010-01-05 13 views
8

Czy ktoś ma jakiś pomysł, jak przeanalizować następujący xml przy użyciu modelu NSXMLParser sterowanego zdarzeniami?Jak używać NSXMLParser do parsowania elementów nadrzędny-podrzędny, które mają taką samą nazwę?

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

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

Chcę zebrać wszystkie trzy nazwiska z tego pliku xml, jest to możliwe, czy muszę zmienić do parsowania oparty na drzewie?

Odpowiedz

31

Jest to typowy problem z takimi analizatorami, jak "typ SAX", w którym musisz ręcznie śledzić bieżącą głębokość drzewa XML. Problem, jak zawsze, polega na tym, że ładowanie całe drzewo w strukturze DOM w pamięci może być niemożliwe, w zależności od rozmiaru danych, którymi chcesz manipulować.

Poniższy kod pokazuje klasę, która wykonuje to zadanie:

#import <Foundation/Foundation.h> 

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

- (void)start; 

@end 

Jest to realizacja:

#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 

Jest to wynikiem prowadzenia narzędzia wiersza poleceń, które wyzwala „start” Powyższa metoda:

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

dzięki za rozwiązanie, to działa dobrze dla mnie. Plik xml jest długi, zmniejszyłem go, aby pasował do pytania. –

5
- (NSInteger)columnNumber 

daje poziomie zagnieżdżenia NSXMLParser

-1

Bardzo łatwiejszy sposób go rozwiązać niż zaakceptowanej odpowiedzi na krótkie pliki XML: przykład

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> 

wdrożyć Licznik:

@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; 

} 

Skąd będę wiedzieć, że liczba czarownic to czarownica? Widzieć dziennik. Będzie to coś w rodzaju:

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: 

Dziennik pokaże, że numer czarownicy to każdy węzeł.

Powiązane problemy