views:

245

answers:

2

Hello everyone,

Given the following XML file:

    <?xml version="1.0" encoding="UTF-8"?>
<application name="foo">
 <movie name="tc" english="tce.swf" chinese="tcc.swf" a="1" b="10" c="20" />
 <movie name="tl" english="tle.swf" chinese="tlc.swf" d="30" e="40" f="50" />
</application>

How can I access the attributes ("english", "chinese", "name", "a", "b", etc.) and their associated values of the MOVIE nodes? I currently have in Cocoa the ability to traverse these nodes, but I'm at a loss at how I can access the data in the MOVIE NSXMLNodes.

Is there a way I can dump all of the values from each NSXMLNode into a Hashtable and retrieve values that way?

Am using NSXMLDocument and NSXMLNodes.

+1  A: 

There are two options. If you continue to use NSXMLDocment and you have an NSXMLNode * for the a movie element, you can do this:

if ([movieNode kind] == NSXMLElementKind)
{
    NSXMLElement *movieElement = (NSXMLElement *) movieNode;
    NSArray *attributes = [movieElement attributes];

    for (NSXMLNode *attribute in attributes)
    {
        NSLog (@"%@ = %@", [attribute name], [attribute stringValue]);
    }
}

Otherwise, you can switch to using an NSXMLParser instead. This is an event driven parser that informs a delegate when it has parsed elements (among other things). The method you're after is parser:didStartElement:namespaceURI:qualifiedName:attributes:

- (void) loadXMLFile
{
    NSXMLParser *parser = [NSXMLParser parserWithContentsOfURL:@"file:///Users/jkem/test.xml"];
    [parser setDelegate:self];
    [parser parse];
}


// ... later ...

-      (void)         parser:(NSXMLParser *)parser
             didStartElement:(NSString *)elementName
                namespaceURI:(NSString *)namespaceURI
               qualifiedName:(NSString *)qualifiedName
                  attributes:(NSDictionary *)attributeDict
{
    if ([elementName isEqualToString:@"movie"])
    {
        NSLog (@"%@", [attributeDict objectForKey:@"a"]);
        NSLog (@"%d", [[attributeDict objectForKey:@"b"] intValue]);
    }
}
dreamlax
Thank you dreamlax! I also found my own solution to this problem, which I posted as well. But I'm accepting yours since you took time and energy to solve it as well. Thank you, and I look forward to using your code as a reference as well.
Jeffrey Kern
@Jeffrey Kern: It's good to solve things on your own, after all, I had a mistake in my answer ;)
dreamlax
Heh, I think your solution is a lil bit more elegant than mine. :)
Jeffrey Kern
+1  A: 

YES! I answered my own question somehow.

When iterating through the XML document, instead of assigning each child node as an NSXMLNode, assign it as an NSXMLElement. You can then use the attributeForName function, which returns an NSXMLNode, to which you can use stringValue on to get the attribute's value.

Since I'm bad at explaining things, here's my commented code. It might make more sense.

//make sure that the XML doc is valid
if (xmlDoc != nil) {
            //get all of the children from the root node into an array
            NSArray *children = [[xmlDoc rootElement] children];
            int i, count = [children count];

            //loop through each child
            for (i=0; i < count; i++) {
                NSXMLElement *child = [children objectAtIndex:i];

                    //check to see if the child node is of 'movie' type
                    if ([child.name isEqual:@"movie"]) {
                    {
                        NSXMLNode *movieName = [child attributeForName:@"name"];
                        NSString *movieValue = [movieName stringValue];

                        //verify that the value of 'name' attribute of the node equals the value we're looking for, which is 'tc'
                        if ([movieValue isEqual:@"tc"]) {
                        //do stuff here if name's value for the movie tag is tc.
                        }
                    }
            }   
   }
Jeffrey Kern
You can also drill down to the nodes you want using [ xmldoc nodesForXPath: @"/application/movie[@name='tc']" error: err ]You can use the returned nodes as the new context node for evaluating further XPath expressions.
Steven D. Majewski
Thank you. I wasn't sure how XPath queries worked, but with your example given with my XML file I can see how basic queries work. Reading up on XCode on the internet, I was confused by the examples because I wasn't sure of the context to use them in.
Jeffrey Kern