Question

Being said that I understand the basic parsing of XML files with NSXMLParser, I have the following situation, where I have several elements <table_data>...</table_data> which differ from each other for the value of a certain attribute, so, for example:

<table_data attr="one">...</table_data> 

<table_data attr="two">...</table_data>

<table_data attr="three">...</table_data>

While in didStartElement, I'd like that the parser takes into account the <table_data> element as the start element only if it has the attr="one".

This would imply that in foundCharacters I could get only the content of children elements of <table_data attr="one"> but not of <table_data attr="two">, <table_data attr="three">, etc.

By now, I try this:

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

    elementoCorrente = [elementName copy];

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

        if ([[attributeDict objectForKey:@"attr"] isEqualToString:@"one"]) {
            stringDesc = [[NSMutableString alloc] init];

        }

    }

}


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


    if ([elementoCorrente isEqualToString:@"field"]) {

        [stringDesc appendString:string];
        NSLog(@"%@",string);
    }


}

But what I get is the log of the content of the <field> element, child of all the <table_data>. Is there a way to print only the content of the <field> element, if child of <table_data attr="one"> ? Thanks Fabio

Was it helpful?

Solution

The problem is that you do nothing to stop foundCharacters from appending data for the other occurrences of table_data. You could have your didStartElement save the attributeDict[@"attr"] value, too, and then foundCharacters could check both elementoCorrente as well as this new ivar in which you're holding the attributeDict[@"attr"] value. For example:

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

    elementoCorrente = nil;
    atributoCorrente = nil;

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

        if ([attributeDict[@"attr"] isEqualToString:@"one"]) {
            elementoCorrente = [elementName copy];
            atributoCorrente = [attributeDict[@"attr"] copy];
            stringDesc = [[NSMutableString alloc] init];
        }
    }
}

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

    if ([elementoCorrente isEqualToString:@"table_data"] && [atributoCorrente isEqualToString:@"one"]) {

        [stringDesc appendString:string];
    }
}

Frankly, you probably want a didEndElement implementation, too, that saves stringDesc wherever you wanted to save it, and then sets elementoCorrente to nil.

OTHER TIPS

Perhaps the code fragment is missing something, but from what you are showing here, to print the content of all the field tags is the expected behavior, since the only test you make in the parser:foundCharacters: method is if the current element is field.

You could add a flag indicating that you are inside the table_data with attr_one. Something like:

if ([[attributeDict objectForKey:@"attr"] isEqualToString:@"one"]) {
    stringDesc = [[NSMutableString alloc] init];
    insideTableOne = YES;
}

And then, in the parser:foundCharacters: also test if insideTableOne is true before appending the string.

This test is also necessary so your program won't crash if it finds a table_data without the expected attribute. If that happens, stringDesc won't have been instantiated yet.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top