Questo è un problema comune con parser come questo, di "tipo SAX", in cui è necessario tenere traccia manualmente della profondità attuale dell'albero XML in cui ci si trova. Il problema, come sempre, è che il caricamento l'intero albero in una struttura DOM in memoria può essere impossibile, a seconda delle dimensioni dei dati che si desidera manipolare.
Il codice seguente mostra una classe che fa questo lavoro:
#import <Foundation/Foundation.h>
@interface Test : NSObject <NSXMLParserDelegate>
{
@private
NSXMLParser *xmlParser;
NSInteger depth;
NSMutableString *currentName;
NSString *currentElement;
}
- (void)start;
@end
Questa è l'implementazione:
#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
Questo è il risultato di esecuzione di uno strumento a riga di comando che fa scattare il "start" metodo di cui sopra:
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
fonte
2010-01-05 11:20:57
grazie per la soluzione, funziona bene per me. Il file xml è lungo, l'ho ridotto per adattarlo alla domanda. –