Search code examples
objective-cplistobjective-c-literals

Converting property lists into Objective-C literals


I'm not sure if this is possible, but I've seen people do crazy things with regex and other tools.

I want to convert this plist to an Objective-C literals:

<dict>
    <key>ar</key>
    <array>
        <string>+54## #### ####</string>
        <string>## #### ####</string>
    </array>
    <key>at</key>
    <array>
        <string>+43 1 ########</string>
        <string>+43 ############</string>

</dict>

converted to:

NSDictionary *dic = @{ 
     @"ar" : @[@"+54## #### ####", @"## #### ####"],
     @"at" : @[@"+43 1 ########",@"+43 ############"]
};

Is it possible to automate such conversion? This guy did something similiar: he parsed a PHP list into an NSDictionary using VIM.


Solution

  • Plist don't have a separate 'format' for use in code (this question doesn't quite make sense as-is). You either want to 1. generate Objective-C code which initializes the dictionary with these values, or 2. initialize the dictionary using the file, for which you can write

    NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:@"UIPhoneFormats.plist"];
    

    Edit: so you want to generate Objective-C code that in turn will reproduce the same dictionary. For this, you need to re-print the contents of the dictionary in a formatted way. You can write a program like this:

    #import <stdio.h>
    #import <Foundation/Foundation.h>
    
    NSString *recursiveDump(id object)
    {
        if ([object isKindOfClass:[NSString class]]) {
            return [NSString stringWithFormat:@"@\"%@\"", object];
        } else if ([object isKindOfClass:[NSNumber class]]) {
            return [NSString stringWithFormat:@"@%@", object];
        } else if ([object isKindOfClass:[NSArray class]]) {
            NSMutableString *str = [NSMutableString stringWithString:@"@["];
            NSInteger size = [object count];
            NSInteger i;
            for (i = 0; i < size; i++) {
                if (i > 0) [str appendString:@", "];
                [str appendString:recursiveDump([object objectAtIndex:i])];
            }
            [str appendString:@"]"];
            return str;
        } else if ([object isKindOfClass:[NSDictionary class]]) {
            NSMutableString *str = [NSMutableString stringWithString:@"@{"];
            NSString *key;
            NSInteger size = [object count];
            NSArray *keys = [object allKeys];
            NSInteger i;
            for (i = 0; i < size; i++) {
                if (i > 0) [str appendString:@", "];
                key = [keys objectAtIndex:i];
                [str appendFormat:@"%@: %@", recursiveDump(key), recursiveDump([object objectForKey:key])];
            }
            [str appendString:@"}"];
            return str;
        } else {
            // feel free to implement handling NSData and NSDate here,
            // it's not that straighforward as it is for basic data types.
        }
    }
    
    
    int main(int argc, char *argv[])
    {
        NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    
        NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:@"UIPhoneFormats.plist"];
        NSMutableString *code = [NSMutableString stringWithString:@"NSDictionary *dict = "];
        [code appendString:recursiveDump(dict)];
        [code appendString:@";"];
        printf("%s\n", [code UTF8String]);
    
        [pool release];
        return 0;
    }
    

    This program will generate (hopefully syntax error-free) Objective-C initialization code out of the provided property list which can be copy-pasted to a project and be used.

    Edit: I just run the program on a stripped version of the plist file OP has provided (the original file was way too large, so I cut it a bit) and it generated the following code:

    NSDictionary *dict = @{@"at": @[@"+43 1 ########", @"+43 ############", @"01 ########", @"00 $"], @"ar": @[@"+54## #### ####", @"## #### ####", @"00 $", @"18 ### $ "]};
    

    To verify it was really valid, I pasted this into the middle of an int main() to a file called 'test.m', so I got this program:

    #import <Foundation/Foundation.h>
    
    int main()
    {
        NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    
        NSDictionary *dict = @{@"at": @[@"+43 1 ########", @"+43 ############", @"0$
        NSLog(@"%@", dict);
    
        [pool release];
        return 0;
    }
    

    To verify, I run clang -o test test.m -lobjc -framework Foundation and surprise, surprise:

    It worked.

    Edit 2: I made this a command line utility, just to facilitate further work - who knows, this may be useful in the future. Plist2ObjC

    Hope this helps.