2012-04-26 108 views
1

我在我想要读取的xml中有以下操作。但我想只读<goodactions><niceactions>。我需要在didStartElement委托函数中放置标志吗?NSXMLParser忽略节点

<goodactions> 
    <action name=\"play\" id=\"0\"/> 
    <action name=\"eat\" id=\"1\" /> 
    <action name=\"sleep\" id=\"2\" /> 
    <action name=\"study\" id=\"3\"/> 
</goodactions> 
<badactions> 
    <action name=\"smoke\" id=\"0\"/> 
    <action name=\"watch_tv\" id=\"1\"/> 
</badactions> 
<niceactions> 
    <action name=\"cycling\" id=\"0\"/> 
    <action name=\"swimming\" id=\"1\"/> 
</niceactions> 

回答

3

也许你在问别的东西,但是一个简单的布尔值就足够了。

BOOL ignoreElement; 

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

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

     self.ignoreElement = YES; 

    } 
} 

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

    if (!self.ignoreElement) { 
     // data from other elements 
    } 
} 

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

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

     self.ignoreElement = NO; 

    } 

} 
+0

这会排除坏行为吗?或只是元素badactions? – 2012-04-26 20:27:24

+0

是的,这会忽略下badactions的行动,因为XML解析器是连续的,通常被称为“事件驱动”的解析器或“SAX”解析器。 http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/XMLParsing/Articles/ParserArchitecture.html,http://en.wikipedia.org/wiki/Simple_API_for_XML – 2012-04-26 20:43:10

+0

感谢克里斯......但回答@ user1118321给了更优雅,但... – 2012-04-26 21:28:28

1

是的,我就是这么做的。当您的委托的-parser:didStartElement::::方法被调用时,如果元素名称为“badactions”,则设置一个标志以忽略所有内容。然后在-parser:didEndElement:重置标志,如果元素名称是“badactions”。类似这样的:

- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict { 
    if ([elementName isEqualToString:@"badactions"]) 
    { 
     _ignoreElement = YES; 
     return; 
    } 
    if (!_ignoreElement) 
    { 
     // handle other elements here 
    } 
} 

- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName { 
    // Reset if we were ignoring a badactions element 
    if (([elementName isEqualToString:@"badactions"]) && (_ignoreElement)) 
    { 
     _ignoreElement = NO; 
    } 
} 
+0

这是否会排除下badactions目前的行动?或只是元素badactions? – 2012-04-26 20:28:05

+0

谢谢......这有助于...... – 2012-04-26 21:28:48

0

忽略特定节点或分支的最简单解决方案是创建自己的XPath类XML路径并维护元素堆栈。

因此,无论何时您解析新元素,您都会将堆栈上的节点推入并更新当前的XML路径。然后当你偶然发现标签时,你只需从堆栈中弹出元素。

但是,您的堆栈可能不一致,因为您可能想忽略一些分支,您可以随时保留并比较堆栈上结束标记和最后一个节点的XMLPath。

在下面给出的示例中,我使用点分隔符存储XML路径。它很便宜且易于分析和比较。

由于这种方法的一个好处,你可以实现一些简单的比较算法,而忽略或XML结构,但潜水的中间匹配特定的树枝和解析出特定节点更深。

拥有堆栈元素是一项巨大的好处,因为如果您需要填充位于层次结构内部的某些信息,则始终可以引用相关节点。

// Base node class 
@interface MYNode : NSObject 

@property NSString* XMLPath; 

@end 

// Some custom node subclass 
@interface MYRootNode : MYNode @end 

// Some other custom node subclass 
@interface MYBlockNode : MYNode @end 

// NSXMLParserDelegate interface 
@interface MYXMLParserDelegate : NSObject<NSXMLParserDelegate> 

@property NSMutableArray* elementStack; 
@property NSString* XMLPath; 
@property MYRootNode* rootNode; 

@end 

// NSXMLParserDelegate implementation 
@implementation MYXMLParserDelegate 

#pragma mark - Initializer 

- (id)init { 
    if(self = [super init]) { 
     self.elementStack = [NSMutableArray new]; 
    } 
    return self; 
} 

#pragma mark - XMLPath manipulation methods 

- (void)addXMLPathComponent:(NSString*)component { 
    NSString* newXMLPath; 

    if(self.XMLPath.length) { 
     newXMLPath = [self.XMLPath stringByAppendingFormat:@".%@", component]; 
    } else { 
     newXMLPath = component; 
    } 

    self.XMLPath = newXMLPath; 
} 

- (void)removeLastXMLPathComponent { 
    NSRange range = [self.XMLPath rangeOfString:@"." options:NSBackwardsSearch]; 
    if(range.location != NSNotFound) { 
     self.XMLPath = [self.XMLPath substringToIndex:range.location]; 
    } 
} 

#pragma mark - NSXMLParserDelegate 

- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict { 
    MYNode* node; 

    // Add XML path component 
    [self addXMLPathComponent:elementName]; 

    // Process relevant nodes 
    if([self.XMLPath isEqualToString:@"document.page"]) 
    { 
     node = [[MYRootNode alloc] initWithAttributes:attributeDict]; 

     // Save root node 
     self.rootNode = node; 
    } 
    else if([self.XMLPath isEqualToString:@"document.page.block"]) 
    { 
     node = [[MYBlockNode alloc] initWithAttributes:attributeDict]; 
    } 

    // Push relevant node on stack 
    if(node) { 
     node.XMLPath = self.XMLPath; 
     [self.elementStack addObject:node]; 

     NSLog(@"-> %@", self.XMLPath); 
    } 
} 

- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName { 
    MYNode* node = [self.elementStack lastObject]; 

    // Remove node from stack if XML path match found  
    if([node.XMLPath isEqualToString:self.XMLPath]) { 
     [self.elementStack removeLastObject]; 

     NSLog(@"<- %@", self.XMLPath); 
    } 

    // Pop XML path component 
    [self removeLastXMLPathComponent]; 
} 

@end