2

I am having a hard time trying to create and populate on the fly an NSMutableDictionary from a tree like structure.

Let's say you have a node where

node.attributes retrieves an NSArray of key/value pairs

and

node.children retrieves an NSArray of nodes from the same node type

how can you convert that tree into a nested NSMutableDictionary?

my aproach is to try to create a NSMutableDictionary for each node and populate it with its attributes and children, creating a new NSMutableDictionary per child and iterate again with it... it sounds like recursion, isn't it

The following code works, for one level deep (parent and children) but throw SIGABRT for grandchildren and beyond.

[self parseElement:doc.rootElement svgObject:&svgData];

where

-(void) parseElement:(GDataXMLElement*)parent svgObject:(NSMutableDictionary**)svgObject
{
    NSLog(@"%@", parent.name);

    for (GDataXMLNode* attribute in parent.attributes)
    {
        [*svgObject setObject:attribute.stringValue forKey:attribute.name];
        NSLog(@"  %@ %@", attribute.name, attribute.stringValue);
    }

    NSLog(@"  children %d", parent.childCount);
    for (GDataXMLElement *child in parent.children) {
        NSLog(@"%@", child.name);

        NSMutableDictionary* element = [[[NSMutableDictionary alloc] initWithCapacity:0] retain];

        NSString* key = [child attributeForName:@"id"].stringValue;

        [*svgObject setObject:element forKey:key];
        [self parseElement:child svgObject:&element];
    }
}

UPDATE:

thanks for your answers, I managed to do the code to work

apparently GDataXMLElement doesn't respond to attributeForName when there is no atributes and so my code threw some exeptions, that where dificult to debug being a recursive method

I am taking into account all your (best practice related) sugestions too

Regards

4

1 回答 1

1

Please note that I replaced your double indirections by a simple pointer. The only case I know where pointers to pointers make sense is in the connection with NSError. I would rewrite this part of code:

-(void) parseElement:(GDataXMLElement*)parent svgObject:(NSMutableDictionary*)svgObject
{

for (GDataXMLNode* attribute in parent.attributes)
{
    // setObject:forKey: retains the object. So we are sure it won't go away.
    [svgObject setObject:attribute.stringValue forKey:attribute.name];
}


for (GDataXMLElement *child in parent.children) {
    NSLog(@"%@", child.name);
    // Here you claim ownership with alloc, so you have to send it a balancing autorelease.
    NSMutableDictionary* element = [[[NSMutableDictionary alloc] init] autorelease];

    // You could also write [NSMutableDictionary dictionary];

    NSString* key = [child attributeForName:@"id"].stringValue;

    // Here your element is retained (implicitly again) so that it won't die until you let it.
    [svgObject setObject:element forKey:key];
    [self parseElement:child svgObject:element];
}

}

If you don't trust in the magic behind implicit retains, just read what Apple tells you about the setObject:forKey:

  • (void)setObject:(id)anObject forKey:(id)aKey Parameters

anObject

The value for key. The object receives a retain message before being added to the dictionary. This value must not be nil.

EDIT: Forgot about your first part:

NSMutableDictionary* svgData = [[NSMutableDictionary dictionary];
[self parseElement:doc.rootElement svgObject:svgData];
于 2012-06-14T08:09:52.727 回答