XMLParser - 如何解析父/子关系

时间:2014-04-14 07:56:15

标签: ios objective-c xml core-data nsxmlparser

我有一个类似于这样的XML文件:

[...]
<parent>
    <title>...</title>
    [...]
    <child>
         <title>...</title>

我有一个本地核心数据库,我的父实体可以有很多孩子。父实体是XML中的父标记,child是我的子实体。

如何使用NSXMLParser基于XML结构将我的两个实体分离并解析为单独的NSManagedObject?

我目前有以下方法:

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

- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qualifiedName attributes:(NSDictionary *)attributeDict


- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string

我不确定我可以在何处以及如何获得我的父实体,建议?

1 个答案:

答案 0 :(得分:2)

我使用NSMutableArray作为堆栈:

一旦找到parent tag,我就创建一个parent对象,并将其放在该堆栈上。
一旦找到child标记,我就创建一个子对象并将其放在堆栈中。现在,当找到一个标签时,应该将其保存为对象的属性,我只需将其添加到最后一个对象。

如果我有一个孩子在堆栈顶部,我知道它的父母是它下面的对象。现在我可以建立任何形式的关系。

如果找到了child的父级的结束标记,我将从堆栈中删除最后一个对象。


一个最小的例子:

我们要解析

<root>
    <parent>
        <title>Parent1</title>
        <child>
            <title>Child 1</title>
        </child>
        <child>
            <title>Child 2</title>
        </child>
    </parent>
    <parent>
        <title>Parent 2</title>
        <child>
            <title>Child 3</title>
        </child>
        <child>
            <title>Child 3</title>
        </child>
    </parent>
</root>

我们的数据结构:

@interface TitledObject : NSObject
@property (nonatomic, copy) NSString *title;
@end

@implementation TitledObject
-(NSString *)description
{
    return [NSString stringWithFormat:@"%@: %@", NSStringFromClass([self class]), _title];
}
@end

@interface Parent :TitledObject
@property (nonatomic, strong) NSMutableArray *children;
@end
@implementation Parent
@end

@interface Child : TitledObject
@property (nonatomic, weak) Parent *parent;
@end
@implementation Child;
-(NSString *)description
{
    NSString *s = [super description];
    s = [s stringByAppendingString:[NSString stringWithFormat:@" , child of %@", self.parent]];
    return s;
}
@end

解析器:

@interface XMLReader : NSObject <NSXMLParserDelegate>
@property (nonatomic, strong) NSString *string;
@property (nonatomic, strong) NSMutableArray *stack;
@property (nonatomic, strong) NSMutableArray *results;

-(id) initWithString:(NSString *)string;
@end

@implementation XMLReader{
    NSMutableString *title;
}

-(id)initWithString:(NSString *)string
{
    if(self = [super init]){
        _string = string;
        _stack = [NSMutableArray array];
        _results = [NSMutableArray array];

    }
    return self;
}


-(void)parse
{
    NSXMLParser *parser = [[NSXMLParser alloc] initWithData:[self.string dataUsingEncoding:NSUTF8StringEncoding]];
    parser.delegate = self;
    [parser parse];
}

-(void)parser:(NSXMLParser *)parser
didStartElement:(NSString *)elementName
 namespaceURI:(NSString *)namespaceURI
qualifiedName:(NSString *)qName
   attributes:(NSDictionary *)attributeDict
{
    if ([elementName isEqualToString:@"parent"]) {
        [self.stack addObject:[[Parent alloc] init]];
    } else if ([elementName isEqualToString:@"child"]) {
        Child *child = [[Child alloc] init];
        child.parent = [self.stack lastObject];
        [child.parent.children addObject:child];
        [self.stack addObject:child];
    } else if ([elementName isEqualToString:@"title"]) {
        title = [@"" mutableCopy];
    }
}

-(void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
    if ([elementName isEqualToString:@"title"])
        [(TitledObject *)[self.stack lastObject] setTitle:title];
    else if (! [elementName isEqualToString:@"root"]){
        [self.results addObject:[self.stack lastObject]];
        [self.stack removeLastObject];
    }
}

-(void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
    [title appendString:string];
}

@end

我们使用它:

XMLReader *reader = [[XMLReader alloc] initWithString:xmlString];
[reader parse];

并访问结果:

        NSLog(@"%@", reader.results);

输出:

(
    "Child: Child 1 , child of Parent: Parent1",
    "Child: Child 2 , child of Parent: Parent1",
    "Parent: Parent1",
    "Child: Child 3 , child of Parent: Parent 2",
    "Child: Child 3 , child of Parent: Parent 2",
    "Parent: Parent 2"
)

您可以使用托管对象代替我的简单数据结构。