NSXMLParser retrieving wrong data from XML tags
I am reading a xml with some fields, for example:
<url>http://myurl.com/noticias/redirect.html?document=xx222&usuario=44yyy&url=http%3A%2F%2Fwww.environmental-expert.com%2FresultEachPressRelease.aspx%3Fcid%3D23745%26codi%3D234441%26lr%3D1</url>
<title>The worl开发者_运维知识库d water report – supplies falling, Tensions Rising</title>
And the output is:
2011-04-28 17:08:02.191 MyProject[12093:207] doc found
2011-04-28 17:08:02.192 MyProject[12093:207] url=http%3A%2F%2Fwww.environmental-expert.com%2FresultEachPressRelease.aspx%3Fcid%3D23745%26codi%3D234441%26lr%3D1
2011-04-28 17:08:02.193 MyProject[12093:207] – supplies falling, Tensions Rising
which is not matching the data on the xml file.
my parser has the following methods:
// Start of element
- (void)parser:(NSXMLParser *)parser
didStartElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI
qualifiedName:(NSString *)qName
attributes:(NSDictionary *)attributeDict
{
if ([elementName isEqualToString:@"document"]){
NSLog(@"doc found");
}
}
// Found Character
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSMutableString *)string
{
currentNodeContent = [string stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
}
// End Element
- (void) parser:(NSXMLParser *)parser
didEndElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI
qualifiedName:(NSString *)qName
{
if ([elementName isEqualToString:@"url"]){
NSLog(@"%@", currentNodeContent);
}
if ([elementName isEqualToString:@"title"]){
NSLog(@"%@", currentNodeContent);
}
if ([elementName isEqualToString:@"document"]){
[currentNodeContent release];
currentNodeContent = nil;
}
}
Can it be related to the function foundCharacters?
Thanks in advance for your help!
foundCharacters can be called several times for one field ! You should create a temporary NSMutableString and append foundcaracters result !
// Start of element
- (void)parser:(NSXMLParser *)parser
didStartElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI
qualifiedName:(NSString *)qName
attributes:(NSDictionary *)attributeDict
{
if ([elementName isEqualToString:@"document"]){
NSLog(@"doc found");
if (temp != nil) {
[temp release];
}
// Alloc temp string
currentNodeContent = [[NSMutableString alloc] init];
}
}
// Found Character
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSMutableString *)string
{
if (currentNodeContent != nil) {
[currentNodeContent appendString:[string stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
}
}
// End Element
- (void) parser:(NSXMLParser *)parser
didEndElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI
qualifiedName:(NSString *)qName
{
if ([elementName isEqualToString:@"url"]){
NSLog(@"%@", currentNodeContent);
}
if ([elementName isEqualToString:@"title"]){
NSLog(@"%@", currentNodeContent);
}
if ([elementName isEqualToString:@"document"]){
[currentNodeContent release];
currentNodeContent = nil;
}
// Release temp string
[currentNodeContent release];
currentNodeContent = nil;
}
Be sure to declare currentNodeContent as a NSMutableString and not a NSString !
Here is the xml parser code I'm using in my projects :
//
// XMLParser.h
//
#import <Foundation/Foundation.h>
#import "XMLNode.h"
#if __IPHONE_OS_VERSION_MAX_ALLOWED > __IPHONE_3_2
@interface XMLParser : NSObject <NSXMLParserDelegate> {
#else
@interface XMLParser : NSObject {
#endif
XMLNode *rootElement;
XMLNode *tempElement;
NSMutableString *temp;
NSMutableArray *elements;
}
- (NSObject *)parseData:(NSData *)data;
// NSXMLParser delegate implementation
- (void)parserDidStartDocument:(NSXMLParser *)parser;
- (void)parserDidEndDocument:(NSXMLParser *)parser;
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qualifiedName attributes:(NSDictionary *)attributeDict;
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName;
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string;
@end
-
//
// XMLParser.m
//
#import "XMLParser.h"
@implementation XMLParser
- (NSObject *)parseData:(NSData *)data
{
NSXMLParser *parser = [[NSXMLParser alloc] initWithData:data];
[parser setDelegate:self];
[parser setShouldResolveExternalEntities:YES];
if (![parser parse]) {
if ([[parser parserError] code] == NSXMLParserUnknownEncodingError) {
// If encoding is "us-ascii" replace encoding with something known (as NSXMLParser is not supporting this encoding)
NSString *oldString = [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding];
NSString *newEncodingString = [oldString stringByReplacingOccurrencesOfString:@"encoding=\"us-ascii\"" withString:@"encoding=\"iso-8859-1\"" options:0 range:NSMakeRange(0,100)];
newEncodingString = [newEncodingString stringByReplacingOccurrencesOfString:@"encoding=\"windows-1251\"" withString:@"encoding=\"iso-8859-1\"" options:0 range:NSMakeRange(0,100)];
[oldString release];
NSData *nameData = [newEncodingString dataUsingEncoding:NSASCIIStringEncoding];
NSXMLParser *parser2 = [[NSXMLParser alloc] initWithData:nameData];
[parser2 setDelegate:self];
[parser2 setShouldResolveExternalEntities:YES];
if (![parser2 parse]) {
DLog(@"parseXML error : %@",[[parser2 parserError] localizedDescription]);
}
[parser2 release];
} else {
DLog(@"parseXML error : %@",[[parser parserError] localizedDescription]);
}
}
[parser release];
return rootElement;
}
- (void)dealloc
{
if (tempElement != nil) {
[tempElement release];
}
if (rootElement != nil) {
[rootElement release];
}
if (temp != nil) {
[temp release];
}
if (elements != nil) {
[elements release];
}
[super dealloc];
}
// NSXMLParser delegate implementation
- (void)parserDidStartDocument:(NSXMLParser *)parser
{
if (elements != nil) {
[elements release];
}
elements = [[NSMutableArray alloc] init];
if (tempElement != nil) {
[tempElement release];
tempElement = nil;
}
if (temp != nil) {
[temp release];
temp = nil;
}
if (rootElement != nil) {
[rootElement release];
rootElement = nil;
}
}
- (void)parserDidEndDocument:(NSXMLParser *)parser
{
if (elements != nil) {
[elements release];
elements = nil;
}
if (tempElement != nil) {
[tempElement release];
tempElement = nil;
}
if (temp != nil) {
[temp release];
temp = nil;
}
}
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI
qualifiedName:(NSString *)qualifiedName
attributes:(NSDictionary *)attributeDict
{
XMLNode *element = [[[XMLNode alloc] initWithName:elementName] autorelease];
[element setAttributes:attributeDict];
if (tempElement != nil) {
[tempElement addChild:element];
[elements addObject:tempElement];
[tempElement release];
} else {
rootElement = [element retain];
}
tempElement = [element retain];
if (temp != nil) {
[temp release];
}
temp = [[NSMutableString alloc] init];
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI
qualifiedName:(NSString *)qName
{
[tempElement setContent:temp];
[temp release];
temp = nil;
[tempElement release];
tempElement = nil;
if ([elements count] > 0) {
tempElement = [[elements lastObject] retain];
[elements removeLastObject];
}
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
if (temp != nil) {
[temp appendString:string];
}
}
@end
-
//
// XMLNode.h
//
#import <Foundation/Foundation.h>
/**
* XMLNode represents an XML data node.
*
* Every node can contain multiple children, attributes, a content string
* and an element name. An XML document is represented using a reference
* to the document root node.
* @ingroup Webservice
*/
@interface XMLNode : NSObject {
NSMutableArray *children;
NSDictionary *attributes;
NSString *content;
NSString *elementName;
}
/**
* Return an initialized XMLNode.
* @param name The element name of the node.
*/
- (id)initWithName:(NSString *)name;
/**
* Set the node attributes.
* @param dictionary A dictionary containing the attributes.
*/
- (void)setAttributes:(NSDictionary *)dictionary;
/**
* Set the content as string.
* @param string The content as string.
*/
- (void)setContent:(NSString *)string;
/**
* Add a child node.
* @param xmlElement The child node.
*/
- (void)addChild:(XMLNode *)xmlElement;
/**
* Return a specific attribute.
* @param name The attribute name.
* @return The attribute for the specified name or nil.
*/
- (NSString *)attributeForName:(NSString *)name;
/**
* Return a child at a specific index.
*
* If the index is out of the bounds, an NSRangeException is thrown.
* @param index The position of the child (by document order).
* @return The child at index
* @see childElementsCount
*/
- (XMLNode *)childElementAtIndex:(int)index;
/**
* Return a child with a certain name.
* @param name The name of the element.
* @return The element or nil if not available.
*/
- (XMLNode *)childWithName:(NSString *)name;
- (XMLNode *)childWithName:(NSString *)name atIndex:(NSInteger)index;
/**
* Return the number of child nodes.
* @return The number of child nodes.
*/
- (int)childElementsCount;
- (int)childWithNameElementsCount:(NSString *)name;
/**
* Return the node content.
* @return The node content as string.
*/
- (NSString *)content;
/**
* Get the name of the xml element.
* @return The name of the element.
*/
- (NSString *)name;
- (void)dealloc;
@end
-
//
// XMLNode.m
//
#import "XMLNode.h"
@implementation XMLNode
- (id)initWithName:(NSString *)name
{
self = [super init];
elementName = [name copy];
children = [[NSMutableArray alloc] init];
return self;
}
- (void)setAttributes:(NSDictionary *)dictionary
{
if (attributes != nil) {
[attributes release];
}
attributes = [dictionary retain];
}
- (void)setContent:(NSString *)string
{
if (content != nil) {
[content release];
}
content = [string retain];
}
- (void)addChild:(XMLNode *)xmlElement
{
[children addObject:xmlElement];
}
- (NSString *)attributeForName:(NSString *)name
{
return [attributes objectForKey:name];
}
- (XMLNode *)childElementAtIndex:(int)index
{
return [children objectAtIndex:index];
}
- (XMLNode *)childWithName:(NSString *)name
{
int i;
for (i=0; i < [children count]; ++i) {
XMLNode *child = [children objectAtIndex:i];
if ([[[child name] lowercaseString] isEqualToString:[name lowercaseString]]) {
return child;
}
}
return nil;
}
- (XMLNode *)childWithName:(NSString *)name atIndex:(NSInteger)index
{
int i;
int count = 0;
for (i = 0; i < [children count]; ++i) {
XMLNode *child = [children objectAtIndex:i];
if ([[[child name] lowercaseString] isEqualToString:[name lowercaseString]]) {
if (count == index)
return child;
count ++;
}
}
return nil;
}
- (int)childElementsCount
{
return [children count];
}
- (int)childWithNameElementsCount:(NSString *)name
{
int i;
int count = 0;
for (i = 0; i < [children count]; ++i) {
XMLNode *child = [children objectAtIndex:i];
if ([[[child name] lowercaseString] isEqualToString:[name lowercaseString]]) {
count ++;
}
}
return count;
}
- (NSString *)content
{
return content;
}
- (NSString *)name
{
return elementName;
}
- (void)dealloc
{
if (content != nil) {
[content release];
}
if (children != nil) {
[children release];
}
if (attributes != nil) {
[attributes release];
}
[super dealloc];
}
@end
use this as following (this sample is to analyze a rss feed :
XMLParser *parser = [[XMLParser alloc] init];
NSObject *rss = [parser parseData:rssFeed];
feedItems = [(XMLNode *)rss childWithName:@"channel"];
if (feedItems) {
NSLog(@"%@",[[feedItems childWithName:@"title"] content]);
}
[parser release];
Check XMLNode.h for more methods if you need a more complex analysis
精彩评论