Search code examples
iosobjective-carraysxmlnsxmlparser

NSXMLParser \n and \t inside of text


I have the following XML architecture :

    <resources>
    <string-array name="enl">
            <item> </item>
            <item> </item>
            <item>"TextTextTextTextTextTextTextTextTextTextText.
Text Text Textv Text Text Text Text Text Text Text.
TextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextText.
TextTextTextTextTextTextTextTextTextTextText"</item>

As it shows between the sentence 1 and sentence 2 there is a return to the start ( Enter ) which creates usually a \n code. As it shows, all this paragraph is inside one <item>. The problem is, when i am parsing it using NSXmlParser, and load it into a nsmutablearray, whenever there is a \n or \t inside the text ( not the ones generated from the spaces between <item> </item> ) i get two entries in the array.

array[0] = @"TextTextTextTextTextTextTextTextTextTextText."  -> 1st sentence <br/>
array[1] = @"Text Text Textv Text Text Text Text Text Text Text." -> 2nd sentence

But i need them to be in the same array entry since it's the same paragraph.

This is the code I use:

- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qualifiedName attributes:(NSDictionary *)attributeDict
{
    // currentElement = elementName ;
    //[elementName release];
    //elementName = nil;
//    if ( [elementName isEqualToString:@"eng"] ) {

        NSString *color = [attributeDict objectForKey:@"name"];
       // NSString *value = [attributeDict valueForKey:@"left"];

        if([color isEqualToString:@"enl"]){

            //NSLog(@"The data in the left pane is %@", value );
        Dir = @"left";

        }
        else if([color isEqualToString:@"enr"]){
            Dir = @"right";
        }
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
    NSString *tagName = @"resources";

    if([tagName isEqualToString:@"resources"])
    {
        if([Dir isEqualToString:@"left"]){
            if(![string isEqualToString:@"\n"] && ![string isEqualToString:@"\n        "] && ![string isEqualToString:@"\""] && ![string isEqualToString:@"\n \""] && ![string isEqualToString:@"\n\t\t"] )
                [leftArray addObject:string];
            } else {
                if([Dir isEqualToString:@"right"]){
                    if(![string isEqualToString:@"\n"] && ![string isEqualToString:@"\n        "] && ![string isEqualToString:@"\""] && ![string isEqualToString:@"\n \""] && ![string isEqualToString:@"\n\t\t"] )
                        [rightArray addObject:string];
                    }
                }
            }
        }

What can I do?


Solution

  • This is because you misunderstood the way the character input is handled by the parser: you can get more than one foundCharacters: callbacks per character entry between the didStartElement: and didEndElement: calls. Your code assumes that there would be only a single call, because you add the object right away:

    [leftArray addObject:string];
    

    or

    [rightArray addObject:string];
    

    What you should do instead is to set up a mutable string buf, and append the content of the string parameter from foundCharacters: to it. The call to addObject: has to happen only in the didEndElement: method, which you need to write.

    You would need to do some minimal buffer management, too: didStartElement: and didEndElement: calls should clear the buf to avoid unwanted characters from other elements mixing with the actual content.