如何使用NSXMLParser解析复杂的XML结构

时间:2013-06-14 03:12:36

标签: ios objective-c xml nsxmlparser

我有一些由以下结构组成的xml

<Succession SuccessionID= ....>
    <LinkedSuccession>
        <Succession SuccessionID= ..../> // multiple possible
    </LinkedSuccession>
    <SUF>
        <SeeAlsoSuccession>
            <Succession SuccessionID= ..../> // multiple possible
        </SeeAlsoSuccession>
    </SUF>
    <Plugins>
        <Plugin PluginIdent= ..../> // multiple possible
    </Plugins>
    <Card>
        <Actives>  // multiple possible
            <Active activeNo= ....>  // multiple possible
                <Machs>
                    <Mach Mach= ...../>  // multiple possible
                </Machs>
            </Active>
        </Actives>
    </Card>
</Succession>

我想知道如何使用NSXMLParser解析这个我知道两种方法

- (void)startTheParsingProcess:(NSData *)parserData
{
    NSXMLParser *parser = [[NSXMLParser alloc] initWithData:parserData]; //parserData passed to NSXMLParser delegate which starts the parsing process
    [parser setDelegate:self];
    [parser parse]; // starts the event-driven parsing operation.
}


- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
{
    //..??
}

- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{

    //..??


}

- (void)parser:(NSXMLParser *)parser parseErrorOccurred:(NSError *)parseError
{
    NSLog(@"Paser Error = %@", parseError);
    UIAlertView *errorAlert = [[UIAlertView alloc] initWithTitle:@"Error!" message:@"A parsing failure occurred." delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil, nil];
    [errorAlert show];
}


- (void)parserDidEndDocument:(NSXMLParser *)parser
{
 //..
}

通常我会使用这样的东西来访问每个元素,但是由于这个xml文件的结构,这个dosnt正常工作,就像它读取Succession一样,如果只是覆盖了最后一个读取的值。

if ([elementName isEqualToString:@"Succession"]) {

等,但是这个XML文件的结构对我来说太过分了。我希望能帮助我们使用NSXMLParser来阅读这个xml文件。

任何帮助都会受到超级赞赏。

4 个答案:

答案 0 :(得分:0)

简单的解决方案是简单地使用一些类属性来跟踪您是否在LinkedSuccessionSeeAlsoSuccession内,或者两者都没有,这样,当您遇到{{1}时}元素,你会知道你是否在这两个子元素数组之一,或者你是否处理顶级Succession条目,并采取相应的行动。


虽然有一些简单的方法可以解决您的问题,但如上所述,我可能会建议另外两个可能帮助您应对挑战的Succession实施方案。第一个是NSXMLParser available on GitHub的基于块的实现。要将它与XML示例一起使用(其中所有数据都显示在XML标记的属性中,您只需提供NSXMLParser,但在我提供的示例代码中,我还说明了您的方式也提供beginElementBlock。无论如何,使用您的示例XML,您可以执行以下操作:

endElementBlock

另一种方法是使用XMLBlockParser *parser = [[XMLBlockParser alloc] initWithData:data]; // handler for the parsing of the start of an element, often useful for parsing the attributes included within // that opening element tag parser.beginElementBlock = ^(NSArray *elementNames, NSDictionary *attributeDict) { NSString *elementName = [elementNames lastObject]; if ([elementName isEqualToString:@"Succession"]) { if ([elementNames count] == 1) { // top level "Succession": create an object self.currentObject = [NSMutableDictionary dictionary]; [self.currentObject setObject:attributeDict[@"SuccessionID"] forKey:@"SuccessionID"]; [self.objects addObject:self.currentObject]; } else { // "Succession" in either "LinkedSuccession" or "SeeAlsoSuccession" // let's find the array "LinkedSuccession" or "SeeAlsoSuccession" objects NSString *container = elementNames[[elementNames count] - 2]; NSMutableArray *array = self.currentObject[container]; if (!array) { // if not found, then let's create it and add it to our currentObject array = [NSMutableArray array]; self.currentObject[container] = array; } // how add the attributeDict value [array addObject:attributeDict[@"SuccessionID"]]; } } }; [parser parse]; 简单地将整个XML解析为一些嵌套的树结构,例如this example on GitHub。为此,您不必编写任何特定于应用程序的代码来解析XML,但最终还是会遇到比标准NSXMLParser / NSArray更复杂的内容。

您有许多可能的方法。我希望这会有所帮助。

答案 1 :(得分:0)

如何处理此XML将在很大程度上取决于您的数据模型的稳健性。如果你开始使用一些NSMutableDictionaries提交你的数据,特别是那些你可能有多个相同元素实例的数据,与自定义数据类捆绑在一起,我认为你会更好。不重复使用该重复数据的关键是利用didEndElement作为触发器,在您生成具有相同名称的另一个元素之前将该元素提交到您的父数据类中。

答案 2 :(得分:0)

您需要记住,有两种方法可以使用NSXMLParser 搜索 构建数据结构

如果您事先知道要处理的结构或架构,那么这些并不是那么糟糕。 如果你不知道,那就更有用了,但是解析器给你提供了两个重要的方法:lineNumber和columnNumber

您可以利用这些优势。 基本上,处理未知XML结构时可以采用的策略是进行干运行或预解析。 在那里,跟踪每列或元素或注释等的总列数和行数。 它可能需要一些试验和错误才能习惯。 但基本上你是在探索XML的结构,然后你对后续轮次有一些想法,你可以使用它。

预解析的一个优点是它可以快得多。它还使后续的解析操作更容易,更快捷。

陷阱正在尝试在一个解析操作中完成所有这一切,当你不知道你接收到了什么并且它不小。

答案 3 :(得分:0)

这是一些可能有用的伪代码:

NSMutableArray *linkedSuccessionIDs = [NSMutableArray array];
NSMutableArray *seeAlsoSuccessionIDs = [NSMutableArray array];
BOOL isInLinkedSuccession = NO;
BOOL isInSeeAlsoSuccession = NO;

- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
{
    if ([elementName isEqualToString:@"LinkedSuccession"])
    {
        isInLinkedSuccession = YES;
    }
    else if ([elementName isEqualToString:@"SeeAlsoSuccession"])
    {
        isInSeeAlsoSuccession = YES;
    }
    else if ([elementName isEqualToString:@"Succession"])
    {
        if (isInLinkedSuccession)
        {
            [linkedSuccessionIDs addObject:[attributeDict[@"SuccessionID"]]];
        }
        else if (isInSeeAlsoSuccession)
        {
            [seeAlsoSuccessionIDs addObject:[attributeDict[@"SuccessionID"]]];
        }
    }
}

- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
    if ([elementName isEqualToString:@"LinkedSuccession"])
    {
        isInLinkedSuccession = NO;
    }
    else if ([elementName isEqualToString:@"SeeAlsoSuccession"])
    {
        isInSeeAlsoSuccession = NO;
    }
}

- (void)parserDidEndDocument:(NSXMLParser *)parser
{
    [self processLinkedSuccessionIDs:linkedSuccessionIDs];
    [self processSeeAlsoSuccessionIDs:seeAlsoSuccessionIDs];
}