Feeding NSXMLParser a stream of xml

NSXMLParser is a great parser, but what if you are reading XML from, say a socket. You may not have the complete message right away, and there may be multiple root tags (or you can close and open a socket and live with the setup time)

Wouldn’t it be cool if we could feed it bits and pieces of XML and it would call us back when a complete message has been parsed? I tackled a problem like this for the ivef-sdk (google it) and here’s what works:

- (bool) parseXMLString:(NSString *)data andBuffer: (bool) cont {

     // create a seperate memory pool, so we can quickly deallocate temp objects generated by the parser
     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

  // data may or may not be lead by xml definitions, but we need them before each message
  data = [data stringByReplacingOccurrencesOfString:@"\n" withString:@""];
     data = [data stringByReplacingOccurrencesOfString:@"\n" withString:@""];
     [m_dataBuffer appendString: data];

     NSRange firstTagRange;
     do {
         // search if a message is in the buffer
        firstTagRange = NSMakeRange(NSNotFound , 0);
         for (NSString *tag in m_closeTags) {
             NSRange rangeOfTag = [m_dataBuffer rangeOfString:tag];
             if (rangeOfTag.location != NSNotFound) {
                 if (firstTagRange.location != NSNotFound) {
                     if (rangeOfTag.location < firstTagRange.location) {
                         firstTagRange = rangeOfTag;
                     }
                 } else {
                     firstTagRange = rangeOfTag;
                 }
             }
         }
         // process a message if found
         if (firstTagRange.location != NSNotFound) {
             NSRange firstMessageRange = NSMakeRange(0, firstTagRange.location + firstTagRange.length);
             NSString *messages = [NSString stringWithFormat:@"\n\n%@\n", [m_dataBuffer substringWithRange:firstMessageRange]];
             [m_dataBuffer deleteCharactersInRange:firstMessageRange];
             NSXMLParser *tempParser = [[NSXMLParser alloc] initWithData:[messages dataUsingEncoding:NSUnicodeStringEncoding]];
             [tempParser setDelegate:self];
             [tempParser parse];
             [tempParser release];
         }        
     } while (firstTagRange.location != NSNotFound);

    if (!cont) {
         [m_dataBuffer setString: @""];
     }

     // free temp memory
     [pool release];

     return true;
}

Where m_closeTags is an NSArray with …. (you can guess) You use this function by calling it every time you have some data, as you can see it will look for a close tag and then parse the messages until it has no complete message left to parse, the left over bits are saved for your next call in the NSMutableString m_dataBuffer

Tagged with: , , ,
Posted in Code
One comment on “Feeding NSXMLParser a stream of xml

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: