2012-04-26 106 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