nsxml parser issue - iphone

I am quite fine with iPhone and have done this before but can't figure it out right now.
I am using the XMLParser and getting a response as shown below:
username = {
text = akhildas;
type = string;
};
Instead what I expect is
username = akhildas
What I have already done is:
- (NSDictionary *)objectWithData:(NSData *)data
{
// Clear out any old data
[dictionaryStack release];
[textInProgress release];
dictionaryStack = [[NSMutableArray alloc] init];
textInProgress = [[NSMutableString alloc] init];
// Initialize the stack with a fresh dictionary
[dictionaryStack addObject:[NSMutableDictionary dictionary]];
// Parse the XML
NSXMLParser *parser = [[NSXMLParser alloc] initWithData:data];
parser.delegate = self;
BOOL success = [parser parse];
// Return the stack's root dictionary on success
if (success)
{
NSDictionary *resultDict = [dictionaryStack objectAtIndex:0];
return resultDict;
}
return nil;
}
#pragma mark -
#pragma mark NSXMLParserDelegate methods
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
{
// Get the dictionary for the current level in the stack
NSMutableDictionary *parentDict = [dictionaryStack lastObject];
// Create the child dictionary for the new element, and initilaize it with the attributes
NSMutableDictionary *childDict = [NSMutableDictionary dictionary];
[childDict addEntriesFromDictionary:attributeDict];
// If there's already an item for this key, it means we need to create an array
id existingValue = [parentDict objectForKey:elementName];
if (existingValue)
{
NSMutableArray *array = nil;
if ([existingValue isKindOfClass:[NSMutableArray class]])
{
// The array exists, so use it
array = (NSMutableArray *) existingValue;
}
else
{
// Create an array if it doesn't exist
array = [NSMutableArray array];
[array addObject:existingValue];
// Replace the child dictionary with an array of children dictionaries
[parentDict setObject:array forKey:elementName];
}
// Add the new child dictionary to the array
[array addObject:childDict];
}
else
{
// No existing value, so update the dictionary
[parentDict setObject:childDict forKey:elementName];
}
// Update the stack
[dictionaryStack addObject:childDict];
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
// Update the parent dict with text info
NSMutableDictionary *dictInProgress = [dictionaryStack lastObject];
// Set the text property
if ([textInProgress length] > 0)
{
[dictInProgress setObject:textInProgress forKey:kXMLReaderTextNodeKey];
// Reset the text
[textInProgress release];
textInProgress = [[NSMutableString alloc] init];
}
// Pop the current dict
[dictionaryStack removeLastObject];
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
// Build the text value
[textInProgress appendString:string];
}
Any one had same problem and solved it well?

I always try to avoid callback based (SAX) NSXMLParser in favor of DOM parsers which creates DOM tree model for you. I find DOM parsers so much easier to cope with.
My favorite is GDataXML parser (developed by Google). It is very reliable and easy to use. It consists of 2 files only (and libxml2 library) but is very powerful.
It saves you from looking up your delegates methods and wondering if you followed your XML structure correctly and extracted your object in proper way.
Mapping XML document to the Objective-C objects tree can be done as short as below:
NSData *xmlData = [[NSMutableData alloc] initWithContentsOfFile:filePath];
NSError *error;
GDataXMLDocument *doc = [[GDataXMLDocument alloc] initWithData:xmlData
options:0 error:&error];
if (doc != nil)NSLog(#"%#", doc.rootElement);
See this very popular tutorial on XML parsing for iPhone where GDataXML is explained:
http://www.raywenderlich.com/725/how-to-read-and-write-xml-documents-with-gdataxml
Hope it will make your life easier with tracking and parsing XML data.

Related

iOS NSXMLParsing unformed HTML

This is my method body for parsing "img src" image links from poorly formed html generated by an RSS feed... I am aware that NSXML only parses XML, but I have this hope that it can stumble through the mess to find these miniscule image links from messy html.
I'm trying to retrieve ONLY the FIRST image link found in the src attribute I find in each element name called IMG in nsData that has a src attribute and then save it to a NSString *img in another class. The img tags are not all the same, for instance an instance of nsData will contain only one image instance like any one of these:
< img class="ms-rteStyle-photoCredit" src="www.imagelinkthatineed.com" stuff I don't need
< img alt="" src="www.imagelinkineedfortableimagecellpreview" stuff I don't need
< img class="ms-rteStyle-photoCredit" src="www.IneedThisLink.com" more stuff I don't need
The only class that seems to generate NSLog output is the first one.
How can I get the parser methods to actually run ?
Given that there's a way, is there a different, simpler way you recommend?
#import "HtmlParser.h"
#import "ArticleItem.h"
#implementation HtmlParser
#synthesize elementArray;
- (HtmlParser *) InitHtmlByString:(NSString *)string {
// NSString *description = [NSString string];
NSData *nsData = [[NSData alloc] initWithContentsOfFile:(NSString *)string];
elementArray = [[NSMutableArray alloc] init];
parser = [[NSXMLParser alloc] initWithData:nsData];
parser.delegate = self;
[parser parse];
If I NSLog(#"%#", nsData); in this method body, the output spits out the raw HTML.
currentHTMLElement = [ArticleItem alloc];
return self;
}
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qualifiedName attributes:(NSDictionary *)attributeDict
{
if ([elementName isEqualToString:#"img src"]) {
currentHTMLElement = [[ArticleItem alloc] init];
}
NSLog(#"\t%# found a %# element", self, elementName);
}
- (void) parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
if (!currentHTMLElement)
currentHTMLElement = [[NSMutableString alloc] initWithString:string];
NSLog(#"Processing Value: %#", currentHTMLElement);
}
- (void) parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
if ([elementName isEqualToString:#"img src"])
{
currentHTMLElement.img = elementName;
[elementArray addObject:currentHTMLElement];
currentHTMLElement = nil;
currentNodeContent = nil;
}
else
{
if (currentHTMLElement !=nil && elementName != nil && ([elementName isEqualToString:#"img src"]))
{
[currentHTMLElement setValue:currentHTMLElement forKey:elementName];
}
}
currentHTMLElement = nil;
}
#end
Thank you for your thoughts.
Given that HTML is generally not well-formed XML, NSXMLParser might not work. If you want to parse HTML, you might refer to this Ray Wenderlich article, How to Parse HTML on iOS. If you've followed those instructions and have added Hpple to your project, you can then retrieve the image src attributes like so:
#import "TFHpple.h"
- (void)retrieveImageSourceTagsViaHpple:(NSURL *)url
{
NSData *data = [NSData dataWithContentsOfURL:url];
TFHpple *parser = [TFHpple hppleWithHTMLData:data];
NSString *xpathQueryString = #"//img";
NSArray *nodes = [parser searchWithXPathQuery:xpathQueryString];
for (TFHppleElement *element in nodes)
{
NSString *src = [element objectForKey:#"src"];
NSLog(#"img src: %#", src);
}
}
Alternatively, and I say this bracing myself for the onslaught of anti-NSRegularExpression responses (in the vein of my all-time favorite Stack Overflow answer), if you want a list of img tags in an html file, you can use the following somewhat complicated regular expression:
- (void)retrieveImageSourceTagsViaRegex:(NSURL *)url
{
NSString *string = [NSString stringWithContentsOfURL:url
encoding:NSUTF8StringEncoding
error:nil];
NSError *error = NULL;
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:#"(<img\\s[\\s\\S]*?src\\s*?=\\s*?['\"](.*?)['\"][\\s\\S]*?>)+?"
options:NSRegularExpressionCaseInsensitive
error:&error];
[regex enumerateMatchesInString:string
options:0
range:NSMakeRange(0, [string length])
usingBlock:^(NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop) {
NSString *src = [string substringWithRange:[result rangeAtIndex:2]];
NSLog(#"img src: %#", src);
}];
}
If you wanted to use NSXMLParser, it would look like so:
- (void)retrieveImageSourceTagsViaNSXMLParser:(NSURL *)url
{
NSXMLParser *parser = [[NSXMLParser alloc] initWithContentsOfURL:url];
parser.delegate = self;
[parser parse];
}
#pragma mark - NSXMLParserDelegate methods
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
{
if ([elementName isEqualToString:#"img"])
{
NSString *src = attributeDict[#"src"];
NSLog(#"img src: %#", src);
}
}
The problem is, in my experience, NSXMLParser is less successful in parsing HTML than LibXML2/Hpple is. I find that on some simple pages, the above works great. But in other situations, it doesn't. Bottom line, While NSXMLParser is great at parsing well-formed XML, I'd be wary of using it for the parsing of HTML.

Desperate for NSXMLParser Guidance

I previously asked this question XMLParser Advice.
However I am still unable to get it to function properly....
So I guess I will start from scratch:
Located at a certain URL is an XML Tree that looks like this
<result>
//stuff that I dont need
<title>
//thing that I do need
</title>
//stuff that I dont need
<body>
//thing that I do need
</body>
<result>
How the heck do I go about parsing that?
The (useless) code I have so far can be found in the link at the top of this question.
Thank you for your time.
Write a simple class, which will be the parser's delegate.
#interface YourObject : NSObject <NSXMLParserDelegate> {
NSString *title, *body; // object attributes
NSXMLParser *parser; // will parse XML
NSMutableString *strData; // will contains string data being parsed
}
#property(readwrite, copy) NSString *title, body;
// will be used to set your object attributes
-(void)fetchValuesAtURL:(NSString *)url;
#end
The fetchValuesAtURL: method will initiate the parse operation.
#implementation YourObject
#synthesize title, body;
-(id)init {
self = [super init];
if(self) {
title = #"";
body = #"";
parser = nil;
strData = [[NSMutableString alloc] initWithCapacity:10];
}
return self;
}
-(void)fetchValuesAtURL:(NSString *)url {
if(parser) {
[parser release];
}
NSURL *xmlURL = [NSURL URLWithString:url];
parser = [[NSXMLParser alloc] initWithContentsOfURL:xmlURL];
[parser setDelegate:self];
[parser parse];
}
-(void)parser:(NSXMLParser *)parser
didStartElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI
qualifiedName:(NSString *)qName
attributes:(NSDictionary *)attributeDict {
// element is about to be parsed, clean the mutable string
[strData setString:#""];
}
// the probably missing method
-(void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
// content (or part of) has been found, append that to the current string
[strData appendString:string];
}
-(void)parser:(NSXMLParser *)parser
didEndElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI
qualifiedName:(NSString *)qName {
// element has been parsed, test the element name
// and store strData accordingly
if([elementName isEqualToString:#"title"]) {
self.title = strData;
}
else { // or else if, here you got two elements to parse
self.body = strData;
}
}
-(void)dealloc {
[title release];
[body release];
[strData release];
if(parser) {
[parser release];
}
[super dealloc];
}
#end
Then :
YourObject *obj = [[YourObject alloc] init];
[obj fetchValuesAtURL:#"http://www.site.com/xml/url"];
NSXMLParser's delegate is able to do many more things, as described in Event-Driven XML Programming Guide from Apple.
For complete reference on delegate methods, see NSXMLParserDelegate Protocol Reference.

XML Parsing in iPhone

I am new in xml parsing.I am totaly cofused how many methods we should have to require for xml parsing and what does use of that method.I want to send input to the webservied and by use of xml parsing i want to display result in my text field.
See this questions for resources on how to pick an XML parser for your iOS application:
Choosing the right IOS XML parser
I choose TouchXML for my projects. It is a DOM parser and has XPath support:
https://github.com/TouchCode/TouchXML
You should use the following methods:
- (void)parseXMLFileAtURL:(NSString *)URL { //own method from me, URL could be local file or internet website
itemsOfFeed = [[NSMutableArray alloc] init];
NSURL *xmlURL = [NSURL URLWithString:URL];
feedParser = [[NSXMLParser alloc] initWithContentsOfURL:xmlURL];
[feedParser setDelegate:self];
[feedParser setShouldProcessNamespaces:NO];
[feedParser setShouldReportNamespacePrefixes:NO];
[feedParser setShouldResolveExternalEntities:NO];
[feedParser parse];
}
- (void)parser:(NSXMLParser *)parser parseErrorOccurred:(NSError *)parseError {
//in case of an error
}
- (void)parserDidStartDocument:(NSXMLParser *)parser {
// start to parse xml
}
-(void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict {
feedElement = [elementName copy];
if([elementName isEqualToString:#"item"]) { //main xml tag
item = [[NSMutableDictionary alloc] init];
feedTitle = [[NSMutableString alloc] init];
feedDate = [[NSMutableString alloc] init];
feedText = [[NSMutableString alloc] init];
feedLink = [[NSMutableString alloc] init];
}
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
if([feedElement isEqualToString:#"title"]) {
[feedTitle appendString:string];
} else if([feedElement isEqualToString:#"link"]) { // some examples of tags
[feedLink appendString:string];
} else if([feedElement isEqualToString:#"content:encoded"]) {
[feedText appendString:string];
} else if([feedElement isEqualToString:#"pubDate"]) {
[feedDate appendString:string];
}
}
- (void) parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {
if([elementName isEqualToString:#"item"]) {
[item setObject:feedTitle forKey:#"title"];
[item setObject:feedDate forKey:#"date"];
[item setObject:feedText forKey:#"text"];
[item setObject:feedLink forKey:#"link"];
[itemsOfFeed addObject:item];
}
}
- (void)parserDidEndDocument:(NSXMLParser *)parser {
[self.myTableView reloadData]; // for example reload table view
[self writeArrayToFile]; //or write to a local property list
}
in your header file:
NSMutableArray *itemsOfFeed;
NSXMLParser *feedParser;
NSMutableDictionary *item;
NSMutableString *feedElement;
NSMutableString *feedTitle, feedDate, feedText, feedLink; //strings of your tags
Then you have:
NSArray
NSDictionary
object a
object b
object c
Just access 'object a' and put it in your text field
hopefully this code example helps you
Here is the very helpful tutorial.
http://www.edumobile.org/iphone/iphone-programming-tutorials/parsing-an-xml-file/
Hi I would personally prefer to use NSXMLParser.
Write your own code which uses NSXMLParserDelegate methods implementation.
But still there are some third party libraries available. Here is a nice example to compare how all those parser differs from each other and also having nice explanation. Code is also available over there.
Hope this will be helpful to you.
-Mrunal
i have a demo app for parsing static XML to UITableView, I think this one will surely will help you.
Availiable third party libraries available below, depend on developer choice this, which is best?
NSXMLParser
libxml2
TBXMLParser
TouchXMLParser
KissXMLParser
TinyXMLParser
GDataXMLParser
And you can also get more information from this great tutorial link
http://www.raywenderlich.com/553/how-to-chose-the-best-xml-parser-for-your-iphone-project
Try this:
XMLReader.h
//
// XMLReader.h
//
//
#import <Foundation/Foundation.h>
#interface XMLReader : NSObject <NSXMLParserDelegate>
{
NSMutableArray *dictionaryStack;
NSMutableString *textInProgress;
NSError *errorPointer;
}
+ (NSDictionary *)dictionaryForPath:(NSString *)path error:(NSError **)errorPointer;
+ (NSDictionary *)dictionaryForXMLData:(NSData *)data error:(NSError **)errorPointer;
+ (NSDictionary *)dictionaryForXMLString:(NSString *)string error:(NSError **)errorPointer;
#end
XMLReader.m
//
// XMLReader.m
//
#import "XMLReader.h"
//NSString *const kXMLReaderTextNodeKey = #"text";
#interface XMLReader (Internal)
- (id)initWithError:(NSError **)error;
- (NSDictionary *)objectWithData:(NSData *)data;
#end
#implementation XMLReader
#pragma mark -
#pragma mark Public methods
+ (NSDictionary *)dictionaryForPath:(NSString *)path error:(NSError **)errorPointer
{
NSString *fullpath = [[NSBundle bundleForClass:self] pathForResource:path ofType:#"xml"];
NSData *data = [[NSFileManager defaultManager] contentsAtPath:fullpath];
NSDictionary *rootDictionary = [XMLReader dictionaryForXMLData:data error:errorPointer];
return rootDictionary;
}
+ (NSDictionary *)dictionaryForXMLData:(NSData *)data error:(NSError **)error
{
XMLReader *reader = [[XMLReader alloc] initWithError:error];
NSDictionary *rootDictionary = [reader objectWithData:data];
[reader release];
return rootDictionary;
}
+ (NSDictionary *)dictionaryForXMLString:(NSString *)string error:(NSError **)error
{
NSArray* lines = [string componentsSeparatedByString:#"\n"];
NSMutableString* strData = [NSMutableString stringWithString:#""];
for (int i = 0; i < [lines count]; i++)
{
[strData appendString:[[lines objectAtIndex:i] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]];
}
NSData *data = [strData dataUsingEncoding:NSUTF8StringEncoding];
return [XMLReader dictionaryForXMLData:data error:error];
}
#pragma mark -
#pragma mark Parsing
- (id)initWithError:(NSError **)error
{
if ((self = [super init]))
{
errorPointer = *error;
}
return self;
}
- (void)dealloc
{
[dictionaryStack release];
[textInProgress release];
[super dealloc];
}
- (NSDictionary *)objectWithData:(NSData *)data
{
// Clear out any old data
[dictionaryStack release];
[textInProgress release];
dictionaryStack = [[NSMutableArray alloc] init];
textInProgress = [[NSMutableString alloc] init];
// Initialize the stack with a fresh dictionary
[dictionaryStack addObject:[NSMutableDictionary dictionary]];
// Parse the XML
NSXMLParser *parser = [[NSXMLParser alloc] initWithData:data];
parser.delegate = self;
BOOL success = [parser parse];
[parser release];
// Return the stack's root dictionary on success
if (success){
NSDictionary *resultDict = [dictionaryStack objectAtIndex:0];
return resultDict;
}
return nil;
}
# pragma mark
# pragma mark - NSXMLParserDelegate methods
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
{
// Get the dictionary for the current level in the stack
NSMutableDictionary *parentDict = [dictionaryStack lastObject];
// Create the child dictionary for the new element
NSMutableDictionary *childDict = [NSMutableDictionary dictionary];
// Initialize child dictionary with the attributes, prefixed with '#'
for (NSString *key in attributeDict) {
[childDict setValue:[attributeDict objectForKey:key]
forKey:key];
}
// If there's already an item for this key, it means we need to create an array
id existingValue = [parentDict objectForKey:elementName];
if (existingValue){
NSMutableArray *array = nil;
if ([existingValue isKindOfClass:[NSMutableArray class]]){
// The array exists, so use it
array = (NSMutableArray *) existingValue;
}
else{
// Create an array if it doesn't exist
array = [NSMutableArray array];
[array addObject:existingValue];
// Replace the child dictionary with an array of children dictionaries
[parentDict setObject:array forKey:elementName];
}
// Add the new child dictionary to the array
[array addObject:childDict];
}
else{
// No existing value, so update the dictionary
[parentDict setObject:childDict forKey:elementName];
}
// Update the stack
[dictionaryStack addObject:childDict];
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
// Update the parent dict with text info
NSMutableDictionary *dictInProgress = [dictionaryStack lastObject];
// Pop the current dict
[dictionaryStack removeLastObject];
// Set the text property
if ([textInProgress length] > 0){
if ([dictInProgress count] > 0){
[dictInProgress setObject:textInProgress forKey:kXMLReaderTextNodeKey];
}
else{
// Given that there will only ever be a single value in this dictionary, let's replace the dictionary with a simple string.
NSMutableDictionary *parentDict = [dictionaryStack lastObject];
id parentObject = [parentDict objectForKey:elementName];
// Parent is an Array
if ([parentObject isKindOfClass:[NSArray class]]){
[parentObject removeLastObject];
[parentObject addObject:textInProgress];
}
// Parent is a Dictionary
else{
[parentDict removeObjectForKey:elementName];
[parentDict setObject:textInProgress forKey:elementName];
}
}
// Reset the text
[textInProgress release];
textInProgress = [[NSMutableString alloc] init];
}
// If there was no value for the tag, and no attribute, then remove it from the dictionary.
else if ([dictInProgress count] == 0){
NSMutableDictionary *parentDict = [dictionaryStack lastObject];
[parentDict removeObjectForKey:elementName];
}
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
// Build the text value
[textInProgress appendString:[string stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]];
}
- (void)parser:(NSXMLParser *)parser parseErrorOccurred:(NSError *)parseError
{
// Set the error pointer to the parser's error object
if (errorPointer)
errorPointer = parseError;
}
#end
Use it:
NSMutableDictionary *yourDic= (NSMutableDictionary *)[XMLReader dictionaryForXMLData:yourData error:&error];

XML parser SDK for IOS

I need to be able to parse XML for a project I'm working on.
How can I parse XML from a web page to the iPhone then read its contents?
Follow this , how to parse XML in Objective c using ASIHTTPRequest and handle all this methods
-(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
See this link too
NSString *url=#"http://www.lancers.jp/work";
NSData *data=[NSData dataWithContentsOfURL:[NSURL URLWithString:url]];
NSDictionary *dict=[XMLParser dictionaryForXMLData:data error:nil];
NSLog(#"%#",[dict description]);
and use below file::::::
XMLParser.h
//
// XMLReader.h
//
// Created by Troy on 9/18/10.
// Copyright 2010 Troy Brant. All rights reserved.
//
#import <Foundation/Foundation.h>
#interface XMLParser : NSObject<NSXMLParserDelegate>
{
NSMutableArray *dictionaryStack;
NSMutableString *textInProgress;
NSError **errorPointer;
}
+ (NSDictionary *)dictionaryForXMLData:(NSData *)data error:(NSError **)errorPointer;
+ (NSDictionary *)dictionaryForXMLString:(NSString *)string error:(NSError **)errorPointer;
#end
XMLParser.m
//
// XMLReader.m
//
// Created by Troy on 9/18/10.
// Copyright 2010 Troy Brant. All rights reserved.
//
#import "XMLParser.h"
NSString *const kXMLReaderTextNodeKey = #"text";
#interface XMLParser (Internal)
- (id)initWithError:(NSError **)error;
- (NSDictionary *)objectWithData:(NSData *)data;
#end
//NSString *url=[NSString stringWithFormat:#"%#",NSLocalizedString(#"locationname", nil)];
//url=[NSString stringWithFormat:url,app.latnear,app.lngnear];
//NSData *data=[NSData dataWithContentsOfURL:[NSURL URLWithString:url]];
//NSDictionary *dict=[XMLReader dictionaryForXMLData:data error:nil];
#implementation XMLParser
#pragma mark -
#pragma mark Public methods
+ (NSDictionary *)dictionaryForXMLData:(NSData *)data error:(NSError **)error
{
XMLParser *reader = [[XMLParser alloc] initWithError:error];
NSDictionary *rootDictionary = [reader objectWithData:data];
[reader release];
return rootDictionary;
}
+ (NSDictionary *)dictionaryForXMLString:(NSString *)string error:(NSError **)error
{
NSData *data = [string dataUsingEncoding:NSUTF8StringEncoding];
return [XMLParser dictionaryForXMLData:data error:error];
}
#pragma mark -
#pragma mark Parsing
- (id)initWithError:(NSError **)error
{
if (self = [super init])
{
errorPointer = error;
}
return self;
}
- (void)dealloc
{
[dictionaryStack release];
[textInProgress release];
[super dealloc];
}
- (NSDictionary *)objectWithData:(NSData *)data
{
// Clear out any old data
[dictionaryStack release];
[textInProgress release];
dictionaryStack = [[NSMutableArray alloc] init];
textInProgress = [[NSMutableString alloc] init];
// Initialize the stack with a fresh dictionary
[dictionaryStack addObject:[NSMutableDictionary dictionary]];
// Parse the XML
NSXMLParser *parser = [[NSXMLParser alloc] initWithData:data];
parser.delegate = self;
BOOL success = [parser parse];
// Return the stack's root dictionary on success
if (success)
{
NSDictionary *resultDict = [dictionaryStack objectAtIndex:0];
return resultDict;
}
return nil;
}
#pragma mark -
#pragma mark NSXMLParserDelegate methods
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
{
// Get the dictionary for the current level in the stack
NSMutableDictionary *parentDict = [dictionaryStack lastObject];
// Create the child dictionary for the new element, and initilaize it with the attributes
NSMutableDictionary *childDict = [NSMutableDictionary dictionary];
[childDict addEntriesFromDictionary:attributeDict];
// If there's already an item for this key, it means we need to create an array
id existingValue = [parentDict objectForKey:elementName];
if (existingValue)
{
NSMutableArray *array = nil;
if ([existingValue isKindOfClass:[NSMutableArray class]])
{
// The array exists, so use it
array = (NSMutableArray *) existingValue;
}
else
{
// Create an array if it doesn't exist
array = [NSMutableArray array];
[array addObject:existingValue];
// Replace the child dictionary with an array of children dictionaries
[parentDict setObject:array forKey:elementName];
}
// Add the new child dictionary to the array
[array addObject:childDict];
}
else
{
// No existing value, so update the dictionary
[parentDict setObject:childDict forKey:elementName];
}
// Update the stack
[dictionaryStack addObject:childDict];
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
// Update the parent dict with text info
NSMutableDictionary *dictInProgress = [dictionaryStack lastObject];
// Set the text property
if ([textInProgress length] > 0)
{
[dictInProgress setObject:textInProgress forKey:kXMLReaderTextNodeKey];
// Reset the text
[textInProgress release];
textInProgress = [[NSMutableString alloc] init];
}
// Pop the current dict
[dictionaryStack removeLastObject];
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
// Build the text value
[textInProgress appendString:string];
}
- (void)parser:(NSXMLParser *)parser parseErrorOccurred:(NSError *)parseError
{
// Set the error pointer to the parser's error object
*errorPointer = parseError;
}
#end

Help me out Strange issue when parsing

I am having a strange problem when using this XML-to-NSDictionary class.really it was working great.
suddenly we found one weired problem using this.Let me explain this...when i have only one item the app is crashing. but when i have more than one item the app is not crashing.
When i have only one item to parse , after parsing if i print the count it shows as 6
But when i have more than one item, after parsing when i print the count it shows correctly
**
crash log:-
-[NSCFString objectAtIndex:]: unrecognized selector sent to instance
0x5c9a040 Terminating app due to
uncaught exception
'NSInvalidArgumentException', reason:
'-[NSCFString objectAtIndex:]:
unrecognized selector sent to instance
0x5c9a040'
**
Please help me out and thanks for your time
Source code
-(void)RequestUpdate
{
NSDictionary *mailDict = [[XMLReader dictionaryForXMLString:responseXML error:nil]
valueForKeyPath:#"response.mails.mail"];
NSLog(#"MAILS>MAIL COUNT %d %#", [mailDict count], mailDict);
}
#import "XMLReader.h"
NSString *const kXMLReaderTextNodeKey = #"text";
#interface XMLReader (Internal)
- (id)initWithError:(NSError **)error;
- (NSDictionary *)objectWithData:(NSData *)data;
#end
#implementation XMLReader
#pragma mark -
#pragma mark Public methods
+ (NSDictionary *)dictionaryForXMLData:(NSData *)data error:(NSError **)error
{
XMLReader *reader = [[XMLReader alloc] initWithError:error];
NSDictionary *rootDictionary = [reader objectWithData:data];
[reader release];
return rootDictionary;
}
+ (NSDictionary *)dictionaryForXMLString:(NSString *)string error:(NSError **)error
{
NSData *data = [string dataUsingEncoding:NSUTF8StringEncoding];
return [XMLReader dictionaryForXMLData:data error:error];
}
#pragma mark -
#pragma mark Parsing
- (id)initWithError:(NSError **)error
{
if ((self = [super init]))
{
errorPointer = error;
}
return self;
}
- (void)dealloc
{
[dictionaryStack release];
[textInProgress release];
[super dealloc];
}
- (NSDictionary *)objectWithData:(NSData *)data
{
// Clear out any old data
[dictionaryStack release];
[textInProgress release];
dictionaryStack = [[NSMutableArray alloc] init];
textInProgress = [[NSMutableString alloc] init];
// Initialize the stack with a fresh dictionary
[dictionaryStack addObject:[NSMutableDictionary dictionary]];
// Parse the XML
NSXMLParser *parser = [[[NSXMLParser alloc] initWithData:data] autorelease];
parser.delegate = self;
BOOL success = [parser parse];
// Return the stack's root dictionary on success
if (success)
{
NSDictionary *resultDict = [dictionaryStack objectAtIndex:0];
return resultDict;
}
return nil;
}
#pragma mark -
#pragma mark NSXMLParserDelegate methods
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
{
// Get the dictionary for the current level in the stack
NSMutableDictionary *parentDict = [dictionaryStack lastObject];
// Create the child dictionary for the new element, and initilaize it with the attributes
NSMutableDictionary *childDict = [NSMutableDictionary dictionary];
[childDict addEntriesFromDictionary:attributeDict];
// If there's already an item for this key, it means we need to create an array
id existingValue = [parentDict objectForKey:elementName];
if (existingValue)
{
NSMutableArray *array = nil;
if ([existingValue isKindOfClass:[NSMutableArray class]])
{
// The array exists, so use it
array = (NSMutableArray *) existingValue;
}
else
{
// Create an array if it doesn't exist
array = [NSMutableArray array];
[array addObject:existingValue];
// Replace the child dictionary with an array of children dictionaries
[parentDict setObject:array forKey:elementName];
}
// Add the new child dictionary to the array
[array addObject:childDict];
}
else
{
// No existing value, so update the dictionary
[parentDict setObject:childDict forKey:elementName];
}
// Update the stack
[dictionaryStack addObject:childDict];
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
// Update the parent dict with text info
NSMutableDictionary *dictInProgress = [dictionaryStack lastObject];
// Set the text property
if ([textInProgress length] > 0)
{
[dictInProgress setObject:textInProgress forKey:kXMLReaderTextNodeKey];
// Reset the text
[textInProgress release];
textInProgress = [[NSMutableString alloc] init];
}
// Pop the current dict
[dictionaryStack removeLastObject];
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
// Build the text value
[textInProgress appendString:string];
}
- (void)parser:(NSXMLParser *)parser parseErrorOccurred:(NSError *)parseError
{
// Set the error pointer to the parser's error object
*errorPointer = parseError;
}
#end
Sample XML Data
<response>
<mails>
<mail id="4e12a3b04ff5ae0774000082">
<created_on>2011-07-05T05:40:00+00:00</created_on>
<updated_on>2011-07-05T05:40:00+00:00</updated_on>
<creator id="4e0abdff54b53058ff0000a2"><name>Merk Warn</name></creator>
<text>eee</text>
</mail>
<mail id="4e12dcvxva3b04ff5ae0774000082">
<created_on>2011-07-05T05:40:00+00:00</created_on>
<updated_on>2011-07-05T05:40:00+00:00</updated_on>
<creator id="4e0abdff54b53058ff0000a2"><name>Merk Warn</name></creator>
<text>eee</text>
</mail>
</mails>
</response>
That's because the tag is stored directly as an NSDictionary object if there is only one element. The count you are getting is the number of key-value pairs in a dictionary.
You can handle this differently,
-(void)update
{
id value = [[XMLReader dictionaryForXMLString:responseXML error:nil] valueForKeyPath:#"response.mails.mail"];
NSArray * mails;
if ( [value isKindOfClass:[NSDictionary class]] ) {
mails = [NSArray arrayWithObject:value];
}
else {
mails = (NSArray *)value;
}
/* `mails` is an array of <mail> based dictionaries */
}
You will have to retain it appropriately.