Search code examples
xmlxcodecocoansxmldocument

Cocoa XML reader app


I'm a newbie to Cocoa, just develop some little apps with C/C++ on Windows. I want to make a "simple" app on Cocoa. When the user specific XML file, the file nodes are represented "enduser viewable".

I made an interface with some NSTextField. I made a subclass of NSDocument called "XMLFile" so I got "XMLFile.h" and "XMLFile.m" in my Xcode project.

In the plist of my app I set up a new "Document Types": XML File - extensions: xml - role: view - class: XMLFile - store type: XML

Here is my "XMLFile.h":

#import <Cocoa/Cocoa.h>


@interface FichierXML : NSDocument {

}

        IBOutlet NSTextField *dateField;
        IBOutlet NSTextField *titleField;
        IBOutlet NSTextField *descField;
        IBOutlet NSTextField *vidfileField;
        IBOutlet NSTextField *imgfileField;
        IBOutlet NSObjectController *object;
        NSUInteger *mask;

@end

And here is my "XMLFile.m":

#import "XMLFile.h"

@implementation XMLFile

- (BOOL)readFromData:(NSData *)datafile ofType:(NSString *)typeName error:(NSError **)outerror

{

    NSMutableArray* ReportCreationDate = [[NSMutableArray alloc] initWithCapacity:10];
    NSMutableArray* ReportTitle = [[NSMutableArray alloc] initWithCapacity:10];
    NSMutableArray* ReportDescription = [[NSMutableArray alloc] initWithCapacity:10];
    NSMutableArray* VideoPath = [[NSMutableArray alloc] initWithCapacity:10];
    NSMutableArray* VideoThumbnailImageName = [[NSMutableArray alloc] initWithCapacity:10];

    NSXMLDocument* doc = [[NSXMLDocument alloc] initWithData:datafile options:mask error:outerror];
    NSXMLElement* root  = [doc rootElement];
    NSArray* dateElement = [root nodesForXPath:@"//Report/ReportCreationDate" error:nil];
    for(NSXMLElement* xmlElement in dateElement)
        [dateElement setStringValue:[xmlElement stringValue]];
    NSArray* titleElement = [root nodesForXPath:@"//Report/ReportTitle" error:nil];
    for(NSXMLElement* xmlElement in titleElement)
        [titleField setStringValue:[xmlElement stringValue]];
    NSArray* descElement = [root nodesForXPath:@"//Report/ReportDescription" error:nil];
    for(NSXMLElement* xmlElement in descElement)
        [descField setStringValue:[xmlElement stringValue]];
    NSArray* vidfileElement = [root nodesForXPath:@"//Report/Videos/Video/VideoPath" error:nil];
    for(NSXMLElement* xmlElement in vidfileElement)
        [vidfileField setStringValue:[xmlElement stringValue]];
    NSArray* imgfileElement = [root nodesForXPath:@"//Report/Videos/Video/VideoThumbnailImageName" error:nil];
    for(NSXMLElement* xmlElement in imgfileElement)
        [imgfileField setStringValue:[xmlElement stringValue]];

    [doc release];
    [ReportCreationDate release];
    [ReportTitle release];
    [ReportDescription release];
    [VideoPath release];
    [VideoThumbnailImageName release];

    return YES;
}

@end

The user opens the XMLFile, and XMLDocument analyses the file to extract nodes' data and sends it to the differents NSTextField. But it doesn't work.

If someone can help me.


Solution

  • You're not too specific about what doesn't work, but here's a guess or two at some things that could be causing trouble...

    One thing that can be easy to forget as a new Cocoa user is that IBOutlets have to be actually hooked up in Interface Builder. Control-drag from each text field to File's Owner in your Document.xib, and make sure that they are assigned to the correct outlet.

    Another item that seems strange (though I don't know for sure it would cause a problem) is your use of a for loop to set the stringValue of the text fields. If there is more than one item in each element's array, you will need to concatenate the strings yourself before setting the text field's value. Repeatedly setting the value will simply get rid of the previous value. If there is only one item in each array, why not simply do:

    NSArray *dateElement = [root 
                   nodesForXPath:@"//Report/ReportCreationDate" 
                           error:nil];
    [dateField setStringValue:
               [[dateElement objectAtIndex:0] stringValue]];
    

    Finally, you might want to try making sure there are no errors when you're querying the NSXMLDocument:

    NSError *dateErr;
    NSArray *dateElement = [root 
                   nodesForXPath:@"//Report/ReportCreationDate" 
                           error:&dateErr];
    if( dateElement ){
        // set the stringValue
    }
    else {
        // inspect the error
    }