Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
325 views
in Technique[技术] by (71.8m points)

objective c - Converting between C enum and XML

What's the cleanest way to store an enum in XML and read it back out again? Say I've got:

enum ETObjectType {ETNormalObjectType, ETRareObjectType, ETEssentialObjectType};

...and I want to take a variable, enum ETObjectType objectType = ETNormalObjectType;, and convert it to XML that looks like this: <objectType>ETNormalObjectType</objectType>.

Currently what I'm doing is something like this:

NSString* const ETObjectTypeAsString[] = {@"ETNormalObjectType",@"ETRareObjectType",@"ETEssentialObjectType"};

[anXMLElement addChild:[NSXMLElement elementWithName:@"objectType" stringValue:ETObjectTypeAsString[objectType]]];

...but that's not entirely ideal; I'm not happy about updating both lists every time I change my enum. But it's acceptable. Much, much worse is reading XML back in, for which I am currently doing this:

if ([[[anXMLElement childNamed:@"objectType"] stringValue] isEqualToString:@"ETRareObjectType"])
{
    [self initObjectType:ETRareObjectType];
}
else if ([[[anXMLElement childNamed:@"objectType"] stringValue] isEqualToString:@"ETEssentialObjectType"])
{
    [self initObjectType:ETEssentialObjectType];
}
else
{
    [self initObjectType:ETNormalObjectType];
}

Yuck! This disgusts me. There's got to be a cleaner way to read, at least, or perhaps a unified way to read and write?

I'm using Obj-C and Cocoa, but I wouldn't mind some pure C functions. I'd even use preprocessor stuff, if it's the only way.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

I haven't found a better way than duplicating the enum in a string. However, I do it slightly differently, namely:

typedef enum {
    kManipulateWindowTargetFrontWindow,
    kManipulateWindowTargetNamedWindow, 
    kManipulateWindowTargetWindowNameContaining, 
    kManipulateWindowTargetDEFAULT = kManipulateWindowTargetFrontWindow, 
} ManipulateWindowTargetType;
#define kManipulateWindowTargetTypeNamesArray @"FrontWindow", @"NamedWindow", @"WindowNameContaining", nil

then in the implementation:

static NSArray* kManipulateWindowTargetTypeArray = [[NSArray alloc] initWithObjects: kManipulateWindowTargetTypeNamesArray];

NSString* ManipulateWindowTargetTypeToString( ManipulateWindowTargetType mwtt )
{
    return [kManipulateWindowTargetTypeArray objectAtIndex:mwtt];
}

ManipulateWindowTargetType ManipulateWindowTargetTypeFromString( NSString* s )
{
    NSUInteger n = [kManipulateWindowTargetTypeArray indexOfObject:s];
    check( n != NSNotFound );
    if ( n == NSNotFound ) {
        n = kManipulateWindowTargetDEFAULT;
    }
    return (ManipulateWindowTargetType) n;
}

The reason I use the #define is to avoid declaring the array in the header file, but it would be insane to separate the definition of the enum from the definition of the sequence of strings, so this is the best compromise I've found.

Since the code is boilerplate, you can actually make them a category on NSArray.

@interface NSArray (XMLExtensions)

- (NSString*) stringWithEnum: (NSUInteger) e;
- (NSUInteger) enumFromString: (NSString*) s default: (NSUInteger) def;
- (NSUInteger) enumFromString: (NSString*) s;

@end

@implementation NSArray (XMLExtensions)

- (NSString*) stringWithEnum: (NSUInteger) e;
{
    return [self objectAtIndex:e];
}

- (NSUInteger) enumFromString: (NSString*) s default: (NSUInteger) def;
{
    NSUInteger n = [self indexOfObject:s];
    check( n != NSNotFound );
    if ( n == NSNotFound ) {
        n = def;
    }
    return n;
}

- (NSUInteger) enumFromString: (NSString*) s;
{
    return [self enumFromString:s default:0];
}


@end

and then:

NSLog( @"s is %@", [kManipulateWindowTargetTypeArray stringWithEnum:kManipulateWindowTargetNamedWindow] );
ManipulateWindowTargetType mwtt = (ManipulateWindowTargetType)[kManipulateWindowTargetTypeArray enumFromString:@"WindowNameContaining" default:kManipulateWindowTargetDEFAULT];
NSLog( @"e is %d", mwtt );

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...