如何在不更改顺序的情况下从 plist 加载数据

Posted

技术标签:

【中文标题】如何在不更改顺序的情况下从 plist 加载数据【英文标题】:How to load data from plist without changing the order 【发布时间】:2016-09-08 17:40:34 【问题描述】:

我想从下面的 plist 文件中加载 NSDictionary,而不改变它的顺序。 这个 plist 文件是 Here. 我研究了很多东西,发现了OrderedDictionary和M13OrderedDictionary。 首先,我尝试了 NSDictionary(我知道它失败了)

- (void)testNSDictionary 
    NSDictionary *dictionary = [NSDictionary dictionaryWithContentsOfFile:filePath];
    NSLog(@"%@",dictionary);

然后我得到以下日志:


    G =     
        R =         
            H = "";
            S = "";
        ;
        V =         
            T = "";
        ;
    ;
    S =     
        B =         
            L = "";
        ;
        O =         
            K = "";
            L = "";
        ;
        V =         
            T = "";
        ;
    ;

这与原始 plist 文件的顺序完全不同! (我知道) 我认为这是按字母顺序排列的。 接下来,我使用以下代码尝试了 OrderedDictionary:

#import "OrderedDictionary.h"
- (void)testOrderedDictionary 
    OrderedDictionary *dictionary = [OrderedDictionary dictionaryWithContentsOfFile:filePath];
    NSLog(@"%@",dictionary);

然后我得到以下日志:


    G =     
        R =         
            H = "";
            S = "";
        ;
        V =         
            T = "";
        ;
    ;
    S =     
        B =         
            L = "";
        ;
        O =         
            K = "";
            L = "";
        ;
        V =         
            T = "";
        ;
    ;

嗯?这与 NSDictionary 的结果相同。 最后,我用下面的代码尝试了 M13OrderedDictionary。

#import "M13OrderedDictionary.h"
- (void)testM13OrderedDictionary 
    M13OrderedDictionary *dictionary = [M13OrderedDictionary orderedDictionaryWithContentsOfFile:filePath];
    NSLog(@"%@",dictionary);

然后我得到以下日志:



没有返回。我不明白发生了什么。 我想知道如何正确使用 OrderedDictionary 和 M13OrderedDictionary。如果它们已过时,我想知道将 plist 文件解析为 NSDictionary 或 NSArray 之类的替代方法。 注意:我不想更改 plist 文件,因为这种格式最适合我。

【问题讨论】:

您如何确定密钥有问题?您决定访问 NSDictionary 中的键的顺序。如果您希望使用具有确定顺序的集合,请使用 NSArray,而不是 NSDictionary。 我知道 NSArray 可以保存订单,但它不能拥有 NSArray 本身的名称。例如在这种情况下,最深层的 T,S,H,T,L,K,L 可以被 NSArray 包含,但其他人不能。是否可以在 NSArray plist 中包含数组名称本身? 你知道NSXMLDocument吗?它可用于在一行中加载任何格式正确的 xml 文档(包括 plist),其 API 与 NSDictionaryNSArray (init(URL:...) 的 API 非常相似。一旦你在内存中得到了这个文档,你就可以遍历它的元素来构建你的有序字典。或者您可以将其保留为 NSXMLDocument 实例,并利用 xPath 的强大功能对其进行解析。 谢谢!我不知道 NSXMLDocument!尝试一下似乎很有意义。 NSXMLDocument 不适用于 ios 【参考方案1】:

OrderedDictionary 不能存在于 plist 文件中。好吧,从某种意义上说,它可以,但不能在您显示的 plist 文件中。 Plist 文件知道 NSArray、NSDictionary 和其他一些可以成为这些元素的基本类——仅此而已。您的 plist 文件包含 NSDictionary,而不是 OrderedDictionary。所以当你加载它时,你只会得到一个普通的 NSDictionary。

注意:我不想更改 plist 文件,因为这种格式最适合我

很好。但是你将要加载一个普通的 NSDictionary。

【讨论】:

谢谢。如果我使用 xml 文件而不是 plist 文件,是否可以将 xml 数据转换为 nsarray 或 nsdictionary? 绝对!您将不得不进行转换。但这是个好主意。当然,您可以争辩说 plist 一个 xml 文件,因此您可以保留当前格式 - 但同样,您必须自己完成所有解析。 好的,但是有没有人已经成功解析plist文件了?如果没有人做过,我会尝试在这里发布。 这是一个有趣的问题,但我们现在远远超出了您最初询问的范围。您的问题是为什么您无法使用dictionaryWithContentsOfFile 获得 OrderedDictionary。至于 OrderedDictionary initWithContentsOfFile,它只有在你保存第一个位置时才有效,当然你没有 - 你从一个普通的手工 plist 开始。 我将尝试使用 initWithContentsOfFile 保存 plist 文件,并检查保存的文件与我原来的 plist 之间的差异。【参考方案2】:

最后,我成功地使用 OrderedDictionary 解析了我的 plist 文件。这是我的代码: [ParserDelegate.h]

@interface ParserDelegate : NSObject<NSXMLParserDelegate>
@end

[ParserDelegate.m]

#import "ParserDelegate.h"
#import "OrderedDictionary.h"
@interface ParserDelegate()
@end

@implementation ParserDelegate 
    BOOL isDict;
    BOOL isKey;
    BOOL isString;
    BOOL stringExists;
    int layer;
    int arrayNum;
    MutableOrderedDictionary *parsedDictionary;
    MutableOrderedDictionary *tempDictionary;
    MutableOrderedDictionary *tempTempDictionary;
    NSMutableArray *keysArray;


- (void)parserDidStartDocument:(NSXMLParser *)parser 
    NSLog(@"Started parsing plist file...");
    isKey = NO;
    layer = 0;
    arrayNum = 0;
    parsedDictionary = [[MutableOrderedDictionary alloc] init];
    tempDictionary = [[MutableOrderedDictionary alloc] init];
    tempTempDictionary = [[MutableOrderedDictionary alloc] init];
    keysArray = [NSMutableArray array];


- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict 
    if ([elementName isEqualToString:@"dict"]) 
        isDict = YES;
        layer++;
     else if ([elementName isEqualToString:@"key"]) 
        isKey = YES;
     else if ([elementName isEqualToString:@"string"]) 
        isString = YES;
        stringExists = NO;
    


- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string 
    if (isDict) 
        if ([tempDictionary count] != 0) 
            [tempDictionary removeAllObjects];
        
        isDict = NO;
    
    if (isKey) 
        [keysArray addObject:string];
        arrayNum++;
    
    if (isString) 
        tempDictionary[[keysArray objectAtIndex:[keysArray count] - 1]] = string;
        stringExists = YES;
    


- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName 
    if ([elementName isEqualToString:@"dict"]) 
        layer--;
        if (layer == 2) 
            tempTempDictionary[[keysArray objectAtIndex:[keysArray count] - [tempDictionary count] - 1]] = [tempDictionary copy];
         else if (layer == 1) 
            parsedDictionary[[keysArray objectAtIndex:[keysArray count] - arrayNum]] = [tempTempDictionary copy];
            [tempTempDictionary removeAllObjects];
            arrayNum = 0;
        
     else if ([elementName isEqualToString:@"key"]) 
        isKey = NO;
     else if ([elementName isEqualToString:@"string"]) 
        if (!stringExists) 
            tempDictionary[[keysArray objectAtIndex:[keysArray count] - 1]] = @"";
        
        isString = NO;
    


-(void)parserDidEndDocument:(NSXMLParser *)parser 
    NSLog(@"Finished parsing!");
    NSLog(@"%@",[parsedDictionary description]);


@end

很抱歉这个脚本只支持我的plist文件,所以不能解析其他格式的plist文件。

用法:

ParserDelegate *parserDelegate = [[ParserDelegate alloc] init];
NSURL *url = [NSURL fileURLWithPath:filePath];
NSXMLParser *parser = [[NSXMLParser alloc] initWithContentsOfURL:url];
parser.delegate = parserDelegate;
[parser parse];

【讨论】:

【参考方案3】:

我发现上面的脚本有一些错误。 我联系了OrderedDictionary的开发者,最后他做了导入导出功能。OrderedDictionary v1.4可以从plist文件中导入OrderedDictionary数据(仅限xml格式)。

我真的很感激。

【讨论】:

以上是关于如何在不更改顺序的情况下从 plist 加载数据的主要内容,如果未能解决你的问题,请参考以下文章

如何在不刷新网页的情况下从下拉列表索引更改事件的数据库中检索数据

在不加载页面的情况下从“按类别排序帖子”菜单更改 <div> 内的内容

如何在不通过视图在所有页面中发送表单的情况下从 django 布局(如“base.html”)获取表单数据?

如何在不更改代码的情况下从已编译的 jar 中检索完整的异常消息?

如何让 GraphQL 在不进行轮询的情况下从数据库中获取实时/新数据?

如何在不推动我的情况下从GitHub中提取更改?