NSXMLParser 在找到第一个实例时停止

NSXMLParser Stops When It Finds The Very First Instance

我正在尝试使用 NSXMLParser 解析此 XML。我在 XML 文件中有多个 "Coffee" 实例,如下所示:

… More XML
<Coffee>
        <Type Name="Type">Minimum Drinking Amount</Type>
            </Coffee>   
<Coffee>
        <Type Name="Type">Maximum Drinking Amount</Type>
            </Coffee>
… More XML

现在,一旦 NSXMLParser 找到 "Coffee" 的第一个实例,就完成并移动到 XML 的其余部分。哪个...好吧,这不是我想要的。我需要它来读取 "Coffee" 的每个实例 这就是我在 Objective-C.

中处理它的方式
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict {
    NSLog(@"Fired Stick1");

    _xmlString = elementName;

    if ([_xmlString isEqualToString:@"Coffee"]) {
        NSLog(@"Stick1 Coffee:");
    }

    if ([_xmlString isEqualToString:@"Tea"]) {
        NSLog(@"Stick1 Tea:");
}

然后是 foundCharacters 委托:

-(void) parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {

    if ([_xmlString isEqualToString:@"Coffee"] || [_xmlString isEqualToString:@"Tea"]) {
        NSLog@"%@ Called", _xmlString);
     }
    if (!_coffeeString) {
        _coffeeString = [[NSMutableString alloc] initWithString:string];
    }
    else {
        _coffeeString = string;
    }

    if (coffeeArray == NULL) {
        NSLog(@"Stick1 the coffeeArray was null");
        coffeeArray = [[NSMutableArray alloc] init];
    }

    //add the returned string into an array
    [coffeeArray addObject:_coffeeString];
    NSLog(@"Stick1 array %@", coffeeArray);

    // parse the returned data in array
    NSString *seperate = [coffeeArray componentsJoinedByString:@"\n"];
    NSLog(@"Stick1 seperate is %@", seperate);

    // another parsing
    NSArray* words = [seperate componentsSeparatedByCharactersInSet :[NSCharacterSet whitespaceAndNewlineCharacterSet]];
                                                                                            //or use newLineCharecterSet
    // Take out all of the whitespace like tabs and spaces and new lines
    _singleName = [words componentsJoinedByString:@""];

    NSLog(@"Stick1 final result %@", _singleName);
}

基本上,它被调用了两次,但不会显示两组数据。找到咖啡后,它会显示咖啡的第一部分(最小),但不会显示咖啡的第二个实例(最大)。

我认为您遇到了几个问题。其中之一是(至少使用提供的 XML),<Coffee>...</Coffee> 定义了整个 XML 文档,因此您可能遇到未处理的解析错误。您应该在 NSXMLParserDelegate 中执行以下代码并查看报告的问题:

- (void)parser:(NSXMLParser *)parser parseErrorOccurred:(NSError *)parseError {
    NSLog(@"error: %@", parseError);
}
- (void)parser:(NSXMLParser *)parser validationErrorOccurred:(NSError *)validationError {
    NSLog(@"error: %@", validationError);
}

您还遇到问题,您试图根据节点的标签名称 (elementName) 在您的代码中设置 trigger/flag,但您实际上关心包含的数据在子节点中。

此外,parser:foundCharacters: NOT 保证 return 标签的全部内容都在一个字符串中,因此您最好处理 parser:didStartElement:...parser:didEndElement:...。然后,在 parser:foundCharacters: 中,您可以确保您处于适当的节点中,并 追加 已找到的字符。

根据您提供的数据,这里有一些示例代码可以帮助您入门:

NOTE: I'm just taking a shot at what you actually want, since your data is a bit vague. Also, I did this in the App Delegate of a brand new Single View App. This is NOT the way to do a real implementation!

//  AppDelegate.m
#import "AppDelegate.h"
@interface AppDelegate () <NSXMLParserDelegate> {

}
@property (assign, nonatomic) BOOL               inNode;
@property (strong, nonatomic) NSMutableArray    *coffeeArray;
@property (strong, nonatomic) NSMutableString   *coffeeString;
@property (copy  , nonatomic) NSString          *singleName;
@property (copy  , nonatomic) NSString          *xmlString;
@end
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    NSXMLParser *parser = [[NSXMLParser alloc] initWithData:[[self xml] dataUsingEncoding:NSUTF8StringEncoding]];
    parser.delegate     = self;
    [parser parse];
    return YES;
}
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict {
    NSLog(@"Fired Stick1");

    self.xmlString = elementName;

    if ([self.xmlString isEqualToString:@"Coffee"]) {
        NSLog(@"Stick1 Coffee:");
        self.coffeeString   = [[NSMutableString alloc] init];
        self.inNode          = YES;
    } else if ([self.xmlString isEqualToString:@"Tea"]) {
        NSLog(@"Stick1 Tea:");
        self.coffeeString   = [[NSMutableString alloc] init];
        self.inNode          = YES;
    } else {
        self.inNode          = NO;
    }
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
    if (self.inNode == YES) {
        if ([self.xmlString isEqualToString:@"Coffee"] || [self.xmlString isEqualToString:@"Tea"]) {
            NSLog(@"%@ Called", self.xmlString);
        }
        [self.coffeeString appendString:string];
    }
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {
    if ([elementName isEqualToString:@"Coffee"] || [elementName isEqualToString:@"Tea"]) {
        if (self.coffeeArray == nil) {
            NSLog(@"Stick1 the coffeeArray was null");
            self.coffeeArray    = [[NSMutableArray alloc] init];
        }

        //add the returned string into an array
        [self.coffeeArray addObject:self.coffeeString];
        NSLog(@"Stick1 array %@", self.coffeeArray);

        // parse the returned data in array
        NSString *seperate = [self.coffeeArray componentsJoinedByString:@"\n"];
        NSLog(@"Stick1 seperate is %@", seperate);

        // another parsing
        NSArray* words = [seperate componentsSeparatedByCharactersInSet :[NSCharacterSet whitespaceAndNewlineCharacterSet]];
        //or use newLineCharecterSet
        // Take out all of the whitespace like tabs and spaces and new lines
        _singleName = [words componentsJoinedByString:@""];

        NSLog(@"Stick1 final result %@", _singleName);

    }
}
- (void)parser:(NSXMLParser *)parser parseErrorOccurred:(NSError *)parseError {
    NSLog(@"error: %@", parseError);
}
- (void)parser:(NSXMLParser *)parser validationErrorOccurred:(NSError *)validationError {
    NSLog(@"error: %@", validationError);
}
- (NSString *)xml {
    NSMutableString *xml = [[NSMutableString alloc] init];
    [xml appendString:@"<Document>"];
    [xml appendString:@""
     @"<Coffee>"
     @"  <Type Name=\"Type\">"
     @"    Minimum Drinking Amount"
     @"  </Type>"
     @"</Coffee>"
     @"<Coffee>"
     @"  <Type Name=\"Type\">"
     @"    Maximum Drinking Amount"
     @"  </Type>"
     @"</Coffee>\n"];
    [xml appendString:@""
     @"<Coffee>"
     @"  <Type Name=\"Type\">"
     @"    Minimum Drinking Amount"
     @"  </Type>"
     @"</Coffee>"
     @"<Coffee>"
     @"  <Type Name=\"Type\">"
     @"    Maximum Drinking Amount"
     @"  </Type>"
     @"</Coffee>\n"];
    [xml appendString:@""
     @"<Coffee>"
     @"  <Type Name=\"Type\">"
     @"    Minimum Drinking Amount"
     @"  </Type>"
     @"</Coffee>"
     @"<Coffee>"
     @"  <Type Name=\"Type\">"
     @"    Maximum Drinking Amount"
     @"  </Type>"
     @"</Coffee>\n"];
    [xml appendString:@""
     @"<Coffee>"
     @"  <Type Name=\"Type\">"
     @"    Minimum Drinking Amount"
     @"  </Type>"
     @"</Coffee>"
     @"<Coffee>"
     @"  <Type Name=\"Type\">"
     @"    Maximum Drinking Amount"
     @"  </Type>"
     @"</Coffee>\n"];
    [xml appendString:@""
     @"<Coffee>"
     @"  <Type Name=\"Type\">"
     @"    Minimum Drinking Amount"
     @"  </Type>"
     @"</Coffee>"
     @"<Coffee>"
     @"  <Type Name=\"Type\">"
     @"    Maximum Drinking Amount"
     @"  </Type>"
     @"</Coffee>\n"];
    [xml appendString:@""
     @"<Coffee>"
     @"  <Type Name=\"Type\">"
     @"    Minimum Drinking Amount"
     @"  </Type>"
     @"</Coffee>"
     @"<Coffee>"
     @"  <Type Name=\"Type\">"
     @"    Maximum Drinking Amount"
     @"  </Type>"
     @"</Coffee>\n"];
    [xml appendString:@"</Document>"];
    return [xml copy];
}
@end