2009-08-07 56 views
4

在XML中存储枚举并将其重新读出的最简单方法是什么?说我有:在C枚举和XML之间进行转换

enum ETObjectType {ETNormalObjectType, ETRareObjectType, ETEssentialObjectType}; 

...我想采取一个变量,enum ETObjectType objectType = ETNormalObjectType;,并将其转换为XML,看起来像这样:<objectType>ETNormalObjectType</objectType>

我在做什么当前是这样的:

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

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

...但是这不完全理想;每次更改枚举时,我都不满意更新这两个列表。但这是可以接受的。很多,更糟的是读回XML,我目前正在这样做:

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!这让我厌恶。至少要有一种更清晰的阅读方式,或者可能是一种统一的阅读和写作方式?

我使用的是Obj-C和Cocoa,但我不介意一些纯粹的C函数。如果是唯一的方法,我甚至会使用预处理器的东西。

回答

17

我还没有找到比复制字符串中的枚举更好的方法。但是,我这样做略有不同,即:

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

然后在执行:

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; 
} 

我用的是#定义是避免声明在头文件中的数组的原因,但它会疯狂地将枚举的定义与字符串序列的定义分开,所以这是我找到的最好的折衷方案。

由于代码是样板文件,所以您实际上可以使它们成为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 

然后:

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

好主意保持头文件中的枚举和字符串序列。有些东西让我困扰着将它们变成NSArray方法,但我可能会这样做。谢谢! – andyvn22 2009-08-07 08:55:18

+0

定义的检查功能在哪里? – zekel 2010-05-18 15:30:09

+1

检查在AssertMacros.h中定义,以及verify,require和变量_noerr,_action,_quiet,_string。他们应该经常撒在你的代码中,这样你才能在你的用户之前找到你的错误。 – 2010-05-19 07:04:00

5

以下是我通常写这些样式的方法:

#define countof(array) (sizeof(array)/sizeof(array[0])) 

enum { 
    ETNormalObjectType, 
    ETRareObjectType, 
    ETEssentialObjectType 
}; 
typedef NSInteger ETObjectType; 

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

NSString *ETStringFromObjectType(ETObjectType type) { 
    return ETObjectTypesAsStrings[type]; 
} 

ETObjectType ETObjectTypeFromString(NSString *string) { 
    NSString *match = nil; 
    for(NSInteger idx = 0; !match && (idx < countof(ETObjectTypesAsStrings)); idx += 1) { 
     if ([string isEqualToString:ETObjectTypesAsStrings[idx]]) { 
      match = ETObjectTypesAsStrings[idx]; 
     } 
    } 
    return match; 
} 

你最终不得不把你的枚举值在两个地方,原来的枚举,而整数值映射到其字符串名称数组。实际做映射的两个函数虽然没有映射的副本。

0

XML的伟大之处在于它可以转换为几乎任何东西,甚至可以转换为代码。翻译一次只需要很多努力。我曾在几个将XML转换为代码的项目中工作。这节省了很多时间。例如,该技术在“XSLT Cookbook 2nd edition,S.Mangano,O'Reilley”一书的第12章中进行了介绍。

这不是一个简单的解决方案,但如果你有一个很好的映射 - 具有高清(你的XML)的单点 - 可以生成.h文件用枚举 - 可以生成表或函数来读/写xml中的值

这取决于枚举的数量以及它们如果值得更改的频率。 祝你好运!

5

我赞同Jon的解决方案,但你可以使用可怕的X-macro,以避免重复自己的。我不知道如何评论乔恩的代码格式的答案,所以这里是一个新的答案。

#define ETObjectTypeEntries \ 
ENTRY(ETNormalObjectType) \ 
ENTRY(ETRareObjectType) \ 
ENTRY(ETEssentialObjectType) 

typedef enum ETObjectType { 
#define ENTRY(objectType) objectType, 
    ETObjectTypeEntries 
#undef ENTRY 
} ETObjectType; 

NSString *ETObjectTypesAsStrings[] = { 
#define ENTRY(objectType) [objectType] = @"" # objectType, 
    ETObjectTypeEntries 
#undef ENTRY 
}; 

#define countof(array) (sizeof(array)/sizeof(array[0])) 

NSString *ETStringFromObjectType(ETObjectType type) { 
    return ETObjectTypesAsStrings[type]; 
} 

NSString *ETObjectTypeFromString(NSString *string) { 
    NSString *match = nil; 
    for(NSInteger idx = 0; !match && (idx < countof(ETObjectTypesAsStrings)); idx += 1) { 
     if ([string isEqualToString:ETObjectTypesAsStrings[idx]]) { 
      match = ETObjectTypesAsStrings[idx]; 
     } 
    } 
    return match; 
} 
+0

这真是恶心。 :D谢谢! (我打算使用NSArray策略中的类别,但玩起来真的很有趣。) – andyvn22 2009-08-11 01:43:40

+1

“真恶心”?我会说非常优雅。 – 2009-08-14 10:38:12

+0

@JonHess你变老了,那是一种恭维 – Madbreaks 2012-12-28 00:59:42

0

我用该溶液进行实验 -

static NSString *stepTypeEnum[kStepTypeCount] = {@"one",@"two",@"three",@"four"}; 

int enumFromStrings(NSString*findString,NSString *strings[],int enumMax){ 
    for (int i=0;i<enumMax;i++){ 
     if ([findString isEqual: strings[i]]) { 
      return i; 
     } 
    } 
    NSLog(@"enum was not found for string %@", findString); 
    assert(false); 
    return INT_MAX; 
} 

我喜欢它,因为它会检查在编译时串数组的长度,并且enumFromStrings功能是通用的,可重复使用的。你这样称呼它:

-(void)setType:(NSString*)typeString{ 
    type = enumFromStrings(typeString,stepTypeEnum,kStepTypeCount); 
}