-1

I have an XML file that looks something like this:

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

I have a local core data database where my parent entity can have many child's. The parent entity is the parent tag in the XML, and child is my child entity.

How can I separate and parse my two entities into separate NSManagedObjects based on a XML structure like the one above using NSXMLParser?

I currently have the following methods:

- (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

I'm not sure where and how I can get my parent entity, suggestions?

Anders
  • 2,903
  • 7
  • 58
  • 114

1 Answers1

2

I'd use a NSMutableArray as stack:

As soon as a parent tag is found, I create a parent object, and put it on that stack.
As soon as a child tag is found, I create a child objects and put it on a stack. Now when ever a tag is found, that should be saved as property on an objects, I just add it to the last object.

If I have a child on top of the stack, I know it's parent is the object below it. Now I can establish any form of relationship.

If a closing tag of a parent of child is found, I remove the last object from the stack.


a minimal example:

We want to parse

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

Our data structure:

@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

And the parser:

@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

we use it like:

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

and the access the results:

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

Output:

(
    "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"
)

Instead of my simple data structure you can use managed objects.

vikingosegundo
  • 52,040
  • 14
  • 137
  • 178