Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Parsing XML CDATA Blocks

I'm attempting to parse an XML file (using NSXMLParser) from the website librarything.com. This is the first file I have ever parsed, but for the most part it seems fairly straight forward. My problem occurs when trying to parse a CDATA block; the method parser:foundCDATA: isn't called, and I can't understand why. I know my parser is set up properly because the parser:foundCharacters: method works fine. The XML data I am trying to parse looks like this http://www.librarything.com/services/rest/1.1/?method=librarything.ck.getwork&isbn=030788743X&apikey=d231aa37c9b4f5d304a60a3d0ad1dad4 and the CDATA block occurs inside the element with the attribute name "description".

Any help as to why the method is not being called would be greatly appreciated!

EDIT: I ran the parser:foundCharacters: method on the description CDATA block and it returned "<". I'm assuming this means that the parser is not seeing the CDATA tag correctly. Is there anything that can be done on my end to fix this?

like image 445
Scott Mielcarski Avatar asked Nov 03 '22 20:11

Scott Mielcarski


1 Answers

It appears the CDATA contents in the <fact> tags is being returned incrementally over multiple call backs in parser:foundCharacters. In you class where you are conforming to NSXMLParserDelegate try building up the CDATA by appending it to an NSMutableString instance, like so:

(Note: here _currentElement is an NSString property and _factString is an NSMutableString property)

- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qualifiedName attributes:(NSDictionary *)attributeDict {    
    self.currentElement = elementName;
    if ([_currentElement isEqualToString:@"fact"]) {
        // Make a new mutable string to store the fact string
        self.factString = [NSMutableString string];
    }

}

- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {
    if ([elementName isEqualToString:@"fact"]) {
        // If fact string starts with CDATA tags then just get the CDATA without the tags
        NSString *prefix = @"<![CDATA[";
        if ([_factString hasPrefix:prefix]) {
            NSString *cdataString = [_factString substringWithRange:NSMakeRange((prefix.length+1), _factString.length - 3 -(prefix.length+1))];
            // Do stuff with CDATA here...
            NSLog(@"%@", cdataString);
            // No longer need the fact string so make a new one ready for next XML CDATA
            self.factString = [NSMutableString string];

        }
    }

}

- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
    if ([_currentElement isEqualToString:@"fact"]) {
        // If we are at a fact element, append the string
        // CDATA is returned to this method in more than one go, so build the string up over time
        [_factString appendString:string];
    }

}
like image 138
lukestringer90 Avatar answered Nov 15 '22 06:11

lukestringer90