2

我目前正在处理一个 iPad 项目,我需要将大型 XML 文件处理到 SQLite 后端。我目前正在使用TBXML解析器进行这项工作。

所以所有的逻辑都已经到位,并且通常 TBXML 解析器完成了它需要做的工作。我现在遇到的唯一问题是 XML 文件变得太大并且内存不足。因此,我考虑切换到 SAX 解析器,例如 Alan Quatermain 的AQXMLParser之类的核心 NSXMLParser 。然而,这将要求我重做我当前的所有逻辑,这些逻辑在某种程度上依赖于 DOM 树提供的功能。这是我宁愿不做的事情。

所以我想要尝试并做的是创建一种混合方法。鉴于我的 XML 结构,这应该是可能的。它基本上是一些重复的“记录”元素。在每条记录中都有可以重复和嵌套的各种元素。在我目前的方法中,我解析文档并将每个记录元素传递给将其处理到数据库中的函数。鉴于这已经存在,我想在我的混合解析方法中使用它。

这就是我想要实现的。我使用 SAX 解析器遍历我的文档。在遍历文档时,我构建了一个 Record 元素。每当我完成一个记录元素时,我都会将它传递给使用 TBXML 处理它的现有函数。然后 SAX 解析器继续构建下一个记录元素。主要目标是: - 修复内存占用(它不需要尽可能小,但它必须保持不变或至少比使用 TBXML 更小) - 保持性能可接受。

目前想实现这个如下:

- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qualifiedName attributes:(NSDictionary *)attributeDict{
    //Recreate record string each time record element is encountered
    if([elementName isEqualToString:@"Record"]) record = [[NSMutableString alloc] init];
    //Write XML tag with name
    [record appendFormat@"<%@>, elementName];
}

- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string{
    //Write XML content
    [record appendString:string];
}

- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName{
    //Write XML tag
    [record appendFormat@"</%@>, elementName];
    if([elementName isEqualToString:@"Record"]){
        //Parse record string into TBXML object
        TBXML * tbxmlRecord = [TBXML tbxmlWithXMLString:record];
        //Send it to the TBXML record processor
        [self processElement:tbxmlRecord.rootXMLElement];
    }
}

我认为这应该可行,但使用字符串感觉很脏。此外,当解析器到达新的记录元素时,我担心记录字符串是否不会很快被覆盖。

所以我的问题是,如果这是解决这个问题的合理方法,或者是否有更好的方法让我实现我正在寻找的东西?

编辑: 我已经实现了这种方法,它看起来工作得很好。我遇到的唯一问题是,如果我的源文件不是 UTF-8 编码的,我只会得到部分结果。但是当我纠正这一切时,一切顺利。内存使用并没有那么好。但也许它会尽其所能。需要进行更多测试...

4

1 回答 1

1

一般来说,你的方法对我来说听起来不错。如果您的解决方案在没有性能问题的情况下为您工作,那么我不会太担心字符串处理。如果你愿意,你可以分析你的应用程序,看看这浪费了多少 CPU 时间。

如果您想做一些更优化的事情,您可以尝试找到一个 SAX 解析器,它可以为您提供原始缓冲区的字节偏移量,并将其与一个 DOM 解析器相结合,让您可以使用非空终止的 C 字符串。我相信这意味着您必须切换到 C 或 C++ 库。我已经将rapidxml用于与您正在尝试的东西模糊相似的东西(嵌入在大文件中的 xml 块)。

于 2012-07-31T08:04:48.057 回答