NSXMLParser忽略节点

时间:2012-04-26 18:15:50

标签: objective-c ios nsxmlparser

我在xml中有以下操作,我想阅读。但我想阅读<goodactions><niceactions>。我是否需要在didStartElement委托功能中放置标志?

<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 个答案:

答案 0 :(得分: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; 

    }

}

答案 1 :(得分: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;
    }
}

答案 2 :(得分: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