Search code examples
iosxmlios5xml-parsingnsxmlparser

iOS parsing entire XML elements


I know that questions about XML had been answered million times here but i couldn't find any answer that fits me. Here is my issue and any help is welcome!

After reading a XML file from a php script in my server and send it to a NSXMLParser i cannot find a way to get all elements called "name" in that XML in order to populate an UITableView later in my app. My goal is to read the entire XML file, get all elements called "name" and store them in a NSMutableArray to populate a Table View.

So here is the XML code passed to NSXMLParser by calling a PHP script:

<?xml version="1.0" encoding="ISO-8859-1"?><?xml-stylesheet type="text/xsl" href="auctions_xsl.xsl"?><auctions>
<auction>
    <id>1</id>
    <name>Leilão Tijuca</name>
    <description>Casa de vila, ótimo estado e ótima localização. Leiloeiro responsável: Fulano de Tal. Contato pelo telefone 3554-5555</description>
    <date>2012-03-06</date>
    <imagepath1>imagem 1</imagepath1>
    <imagepath2>imagem 2</imagepath2>
    <imagepath3>imagem 3</imagepath3>
    <location>Rua São Francisco Xavier, 390 - Tijuca - Rio de Janeiro - RJ</title>
</auction>
<auction>
    <id>2</id>
    <name>Leilão Barra</name>
    <description>Cobertura ótimo estado. Leiloeiro responsável Leandro. Contato pelo tel: 3554-9356</description>
    <date>2012-03-28</date>
    <imagepath1>001</imagepath1>
    <imagepath2>002</imagepath2>
    <imagepath3>003</imagepath3>
    <location>Avenida das Américas, 500 - Barra - Rio de Janeiro - RJ</title>
</auction>
<auction>
    <id>3</id>
    <name>Leilão Flamengo</name>
    <description>Apartamento andar baixo. Localizado em frente ao metrô. Leiloeiro Marcel pelo tel 3554-6678</description>
    <date>2012-03-18</date>
    <imagepath1>im1</imagepath1>
    <imagepath2>im2</imagepath2>
    <imagepath3>im3</imagepath3>
    <location>Avenida Oswaldo Cruz, 110 - Flamengo - Rio de Janeiro - RJ</title>
</auction>

And here is part of my objective-c code: (wrong parts commented)

-(void)viewDidLoad {

[super viewDidLoad];
NSURL *url = [NSURL URLWithString:@"http://leandroprellapps.capnix.com/script.php"];
NSXMLParser *xmlParser = [[NSXMLParser alloc] initWithContentsOfURL:url];
allNames = [NSMutableArray arrayWithObjects: nil]; //declared as instance variable in .h file
xmlParser.delegate = self;
[xmlParser parse];
NSLog(@"%@",allNames); //getting wrong data here
}

//and later on

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

// SUPPOSE TO READ ALL XML FILE AND FIND ALL "name" ELEMENTS
if ([elementName isEqualToString:@"name"]) {

    self.currentName = [[NSMutableString alloc] init];       
    }
}

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

[self.currentName appendString:string]; //passing the value of the current elemtn to the string
}

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

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

    NSLog(@"%@", currentName); //show current element
    [allNames addObject:currentName];//not only is not reading all xml "name" elements but also adding another elements not shown in above NSLog....        
    }
}

To exemplify, here is my NSLog results:

2012-03-06 22:51:37.622 Leilao Invest 2.0[10032:f803] Leilão Tijuca

2012-03-06 22:51:37.623 Leilao Invest 2.0[10032:f803] (
"Leil\U00e3o Tijuca\n\t\tCasa de vila, \U00f3timo estado e \U00f3tima localiza\U00e7\U00e3o. Leiloeiro respons\U00e1vel: Fulano de Tal. Contato pelo telefone 3554-5555\n\t\t2012-03-06\n\t\timagem 1\n\t\timagem 2\n\t\timagem 3\n\t\tRua S\U00e3o Francisco Xavier, 390 - Tijuca - Rio de Janeiro - RJ"

)

Note that the first NSLog shows the correct name of the current element but in the second NSLog, after adding the current element do my MutableArray, it shows just the first element called "name" and a bunch of other elements that was not supposed to be added and it did not keep the encoding (NSISOLating1) of the strings.


Solution

  • It is because the foundCharacters function will called when the parser found something between any tag.

    In your case, your first tag is 'id', since it is not match the name, your currentName have not initialized and therefore foundCharacters does not append the value '2' as the currentName is nil at this time. Then the 2nd tag is name, so it match your condition and initialize the string. From this point, every characters found between tag will append to currentName.

    If you would like to parse the name only, one way is to check if the current tag is 'name' before appending characters to currentName.

    - (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI  qualifiedName:(NSString *)qualifiedName attributes:(NSDictionary *)attributeDict {
    
        // SUPPOSE TO READ ALL XML FILE AND FIND ALL "name" ELEMENTS
        if ([elementName isEqualToString:@"name"]) {
            isNameTag = YES;
            self.currentName = [[NSMutableString alloc] init];       
        }
    }
    
    - (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
        if (isNameTag) {
            [self.currentName appendString:string]; //passing the value of the current elemtn to the string
        }
    }
    
    - (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {
    
        if ([elementName isEqualToString:@"name"]) {
            isNameTag = NO;  // disable the flag
            NSLog(@"%@", currentName); //show current element
            [allNames addObject:currentName];//not only is not reading all xml "name" elements but also adding another elements not shown in above NSLog....        
        }
    }