これは、このような「タイプ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
これは、上記の「start」メソッドをトリガーするコマンドラインツールを実行した結果です。
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