How to parse data from a website using NSXMLParser - ios

I want to get the updates from a website based on the titles and links which is in xml format.
I have tried with the code below but it's not working. In console it is showing the message:
2011-11-03 14:45:05.987 tabbar[673:e903] * Terminating app due to
uncaught exception 'NSInvalidArgumentException', reason: '-[NSCFString
isEqualtostring:]: unrecognized selector sent to instance 0x5746830'
If I run again, the table view is loading but there is no data in the table cells.
It is showing this message at the line if ([elementName isEqualtostring:#"item"]):
program received signal SIGABRT
-(void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
{
classelement = elementName;
if ([elementName isEqualtostring:#"item"])
{
itemselected = YES;
multitle = [[NSMutableString alloc]init];
mullink = [[NSMutableString alloc]init];
}
}
-(void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedname:(NSString *)qName
{
if ([elementName isEqualToString:#"item"])
{
itemselected = NO;
[titlearray addObject:multitle];
[linkarray addObject:mullink];
[multitle release];
[mullink release];
[self.tbl reloadData];
}
}
-(void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
if (itemselected)
{
if ([classelement isEqualToString:#"title"])
{
NSLog(#"%#",string);
[multitle appendString:multitle];
}
else if([classelement isEqualToString:#"link"])
{
[multitle appendString:string];
}
}
}

If you are reading directly from a website more than likely you are getting "invalid" characters. As soon as the parser see's these invalid characters it will crash. I would suggest looking at using "HPPLE Parser". It works much better and wont crash if invalid characters come in.
Hpple information here: http://blog.objectgraph.com/index.php/2010/02/24/parsing-html-iphone-development/

Finally I got it. What I did is I have taken two NSMutableArrays and two NSMutableStrings and I appended the items to the strings, and later those strings I appended to the two arrays.
(void)viewDidLoad
{
titlearray = [[NSMutableArray alloc]init];
linkarray = [[NSMutableArray alloc]init];
NSString *rssaddress =#"http://www.greenday.com/rss";
NSURL *url = [NSURL URLWithString:rssaddress];
xmlparser = [[NSXMLParser alloc]initWithContentsOfURL:url];
[xmlparser setDelegate:self];
[xmlparser parse];
[super viewDidLoad];
}
(void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
{
classelement = elementName;
if([elementName isEqualToString:#"item" ])
{
itemselected = YES;
titlestrng = [[NSMutableString alloc]init];
linkstrng = [[NSMutableString alloc]init];
}
}
(void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
if([elementName isEqualToString:#"item" ])
{
itemselected = NO;
[titlearray addObject:titlestrng];
[linkarray addObject:linkstrng];
[titlestrng release];
[linkstrng release];
[self.tb reloadData];
}
}
(void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
if(itemselected)
{
if([classelement isEqualToString:#"title"])
{
[titlestrng appendString: string];
NSLog(#"%#",titlestrng);
}
else if ([classelement isEqualToString:#"link"])
{
[linkstrng appendString:string];
NSLog(#"%#",linkstrng);
}
}
}

Related

NSXMLParser - empty value

I am trying NSXMLParser for getting values from an XML for first time. But I have a problem.
Below my XML:
<Library>
<Book>
<ID>1</ID>
<TITLE>Test</TITLE>
</Book>
</Library>
and parser code:
-(void)parser:(NSXMLParser *)parser didStartElement:(NSString *) elementName namespaceURI:(NSString *)namespaceURI qualifiedNam(NSString *)qName attributes:(NSDictionary *)attributeDict
{
if([elementName isEqualToString:#"Book"])
{
NSLog(#"%#", [attributeDict valueForKey:#"ID"]);
}
}
The result ID is null. Can you help me please?
Unfortunately, NSXMLParser doesn't work this way. It traverses over the elements in XML in document order, so by the time the "Book" element starts, it hasn't reached the "ID" element yet. Your code would work if the XML looked like
<Book Id="1">
...
</Book>
but I suppose you have no control over the XML. Then you need a more sophisticated solution. I believe the following would work:
Add these instance variables
NSString *currentElement, *bookID, *bookTitle;
NSMutableString *elementValue;
Implement the following methods:
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *) elementName namespaceURI:(NSString *)namespaceURI qualifiedNam(NSString *)qName attributes:(NSDictionary *)attributeDict {
currentElement = elementName;
elementValue = nil;
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
// Append characters to element value
if (!elementValue) elementValue = [NSMutableString stringWithCapacity:100];
[elementValue appendString:string];
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qualifiedName {
if ([#"Id" isEqualToString:elementName]) {
bookID = [elementValue copy];
} else if ([#"Title" isEqualToString:elementName]) {
bookTitle = [elementValue copy];
} else if ([#"Book" isEqualToString:elementName]) {
// end of Book element, do something with bookID and bookTitle
}
}
Follow the below code.You will understand.
In your .h part
//Step 1 : Add the Delegate classes
First of all you should add <NSXMLParserDelegate>
//Step 2 : Create necessary objects
NSXMLParser *parser;
NSMutableData *ReceviedData;
NSMutableString *currentStringValue;
NSMutableArray *arrayID;
In your .m part
//Step 3 - Allocate your all Arrays in your viewDidLoad method
arrayId = [NSMutableArray alloc]init];
//Step 4 - Create Connection in your viewDidLoad Like
[self createConnection:#"http://www.google.com"];//give your valid url.
-(void)createConnection:(NSString *)urlString
{
NSURL *url = [NSURL URLWithString:urlString];
//Step 5 - parser delegate methods are using NSURLConnectionDelegate class or not.
BOOL success;
if (!parser)
{
parser = [[NSXMLParser alloc] initWithContentsOfURL:url];
parser.delegate = self;
parser.shouldResolveExternalEntities = YES;
success = [parser parse];
NSLog(#"Success : %c",success);
}
}
-(void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
{
NSLog(#"Current Element Name : %#",elementName);
if ([elementName isEqualToString:#"ID"])
{
NSLog(#"The Result is==%#",elementName);
}
}
-(void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
currentStringValue = [[NSMutableString alloc] initWithString:string];
NSLog(#"Current String Value : %#",currentStringValue);
}
-(void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
if ([elementName isEqualToString:#"ID"])
{
[arrayResult addObject:currentStringValue];
}
currentStringValue = nil;
}

Imagesarray double when i back from detailview

I parse xml images urls from tableview to detailview when xml format is like
so I wrote like this
In below code the some content so i wrote the code like this.
this is another type of tag so wrote code like
if ([elementObj isEqualToString:#"media:thumbnail"]) {
[Imagesarray addObject:attributeDict[#"url"]];
}
In foundcharactor i dont use this because i got the array here
[Imagesarray addObject:attributeDict[#"url"]];
When i didnot use this in didendelement method because it does not have the attributedstring
-(void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
{
elementObj = elementName;
if ([elementObj isEqualToString:#"media:thumbnail"]) {
[Imagesarray addObject:attributeDict[#"url"]];
NSLog(#"%# it is images array",Imagesarray);
}
if ([elementObj isEqualToString:#"item"]) {
_item = [[NSMutableDictionary alloc] init];
titleObj = [[NSMutableString alloc] init];
pubdataObj= [[NSMutableString alloc] init];
DiscriptionObj=[[NSMutableString alloc]init];
}
}
When i click on back button of the detail view all the images add to the array again.How can i write code for this.
Please help me.
-(void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
if ([elementObj isEqualToString:#"title"]) {
[titleObj appendString:string];
}
else if ([elementObj isEqualToString:#"pubDate"]) {
[pubdataObj appendString:string];
}
else if ([elementObj isEqualToString:#"description"]){
[DiscriptionObj appendString:string];
-(void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
if ([elementName isEqualToString:#"item"]) {
[_item setObject:titleObj forKey:#"title"];
[_item setObject:pubdataObj forKey:#"pubDate"];
[_item setObject:DiscriptionObj forKey:#"description"];
[feedsArry addObject:_item];
[];
}
}
Try checking whether you are parsing the array from viewdidappear or viewwillappear method. if yes this method will be called whenever the view is opened. it would be better to move parsing to viewdidload which will be called only once when the view is loading.

EXC_BAD_ACCESS for NSXMLParser code

I have written the below code to parse RSS feeds. but i keep getting EXC_BAD_ACCESS in foundCharacter method when it tries to compare element with #"title".Any idea where am i going wrong?
NSMutableDictionary * item;
NSMutableString * title;
NSMutableString * link;
NSString *element;
NSMutableArray *feeds;
-(void) parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict{
element = elementName;
if ([element isEqualToString:#"item"]) {
item = [[NSMutableDictionary alloc]init];
title = [[NSMutableString alloc]init];
link = [[NSMutableString alloc] init];
}
}
-(void) parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName{
if ([elementName isEqualToString:#"item"]) {
[item setObject:title forKey:#"title"];
[item setObject:link forKey:#"link"];
[feeds addObject:[item copy]];
NSLog(#"feeds :: %#",feeds);
}
}
-(void) parser:(NSXMLParser *)parser foundCharacters:(NSString *)string{
if ([element isEqualToString:#"title"]) {
[title appendString:string];`enter code here`
}else if ([element isEqualToString:#"link"]){
[link appendString:string];
}
}
I think the mistake is in this line:
element = elementName;
You have to init the variable element. So write this one:
element = [[NSString alloc] initWithString:elementName];
Then it should work.

IOS NSXMLParser Not getting all the text from the element? [duplicate]

i have the following XMLParser but when i try to run it, it doesn't work properly.
- (void) parser:(NSXMLParser *)parser didStartElement:(NSString *)elementname namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
{
if ([elementname isEqualToString:#"results"])
{
currentJob = [SearchResult alloc];
}
}
- (void) parser:(NSXMLParser *)parser didEndElement:(NSString *)elementname namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
if ([elementname isEqualToString:#"jobTitle"])
{
currentJob.jobTitle = currentNodeContent;
}
if ([elementname isEqualToString:#"location"])
{
currentJob.shortAddress = currentNodeContent;
}
if ([elementname isEqualToString:#"companyName"])
{
currentJob.employer = currentNodeContent;
}
if ([elementname isEqualToString:#"results"])
{
[self.jobs addObject:currentJob];
currentJob = nil;
currentNodeContent = nil;
}
}
AND here is my foundCharakter Method:
- (void) parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
currentNodeContent = (NSMutableString *) [string stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
}
The output doesn't start from the beginning, it starts from the middle of the String...
I just can not understand, why some results look nice where some others don't.
What am i doing wrong ? How can i parse an xml properly ?
Any help will be appreciated.
Thx in advance
I used the following code and works now:
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string{
if(!elementContentString)
elementContentString = [[NSMutableString alloc] initWithString:string];
else
[elementContentString appendString:string];
}
I don't think there any problem in your code, it is working fine at my end. I am using the twitter api for getting xml and it is giving me proper output.

How can I set key-value pair in NSMutableDictionary as XML attribute-element values using NSXMLParser

I am using NSXMLParser to parse my XML with the following structure:
<characters>
<character>
<literal>本</literal>
<codepoint>
<cp_value cp_type="ucs">672c</cp_value>
<cp_value cp_type="jis208">43-60</cp_value>
</codepoint>
</character>
</characters>
I want to use the cp_value element's attribute_value as a key and the element value (e.g. 672c) as the value and place this key-value pair in my NSMutableDictionary *_codepoint. After parsing, I want the result (in the console) to look like this:
_codepoint: {
"ucs"=672c;
"jis208"=43-60;
}
As I have implemented the parser (code follows), I am getting this back in the console:
2013-01-22 22:12:46.199 MyApp[13391:c07] _codepoint: {
ucs = "\n \n ";
}
2013-01-22 22:12:46.201 MyApp[13391:c07] _codepoint: {
jis208 = "\n \n 672c\n ";
}
First - the values and keys are out-of-sync and second, the value for the jis208 element is not getting read-in. Second, I'm not sure what these \n and whitespaces are. Can anybody please give some advice?
The code I have written is:
- (void)parser:(NSXMLParser *)parser
didStartElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI
qualifiedName:(NSString *)qName
attributes:(NSDictionary *)attributeDict
{
if([elementName isEqualToString:#"characters"]) {
appDelegate.characters = [[NSMutableArray alloc] init];
} else if ([elementName isEqualToString:#"character"]) {
aCharacter = [[Character alloc] init];
} else if ([elementName isEqualToString:#"cp_value"]) {
if (!_codepoint) _codepoint = [[NSMutableDictionary alloc] init];
[_codepoint setValue:currentElementValue forKey:[attributeDict valueForKey:[[attributeDict allKeys] lastObject]]];
NSLog(#"_codepoint: %#", _codepoint);
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
if (!currentElementValue) {
currentElementValue = [[NSMutableString alloc] initWithString:string];
} else {
[currentElementValue appendString:string];
}
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
if ([elementName isEqualToString:#"characters"]
// cp_values will be copied from a local NSMutableDictionary *_codepoint
|| [elementName isEqualToString:#"codepoint"]
) return;
if ([elementName isEqualToString:#"character"]) {
[appDelegate.characters addObject:aCharacter];
[aCharacter release];
} else if ([elementName isEqualToString:#"cp_value"]){
[aCharacter.codepoint addObject:_codepoint];
}
}
Thank you very much for looking.
problem is that you are adding currentElementValue to _codepoint before reading actual value into currentElementValue i.e you are adding it in when cp_value is started. you should add currentElementValue to _codepoint in didEndElement: delegate method.Then you'll get expected result.Modify your code like this:
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
{
if([elementName isEqualToString:#"characters"]) {
appDelegate.characters = [[NSMutableArray alloc] init];
} else if ([elementName isEqualToString:#"character"]) {
aCharacter = [[Character alloc] init];
} else if ([elementName isEqualToString:#"cp_value"]) {
if (!_codepoint) _codepoint = [[NSMutableDictionary alloc] init];
currentAttributeKey = [[NSMutableString alloc]initWithString:[attributeDict valueForKey:[[attributeDict allKeys] lastObject]]];
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
if (!currentElementValue) {
currentElementValue = [[NSMutableString alloc] initWithString:string];
} else {
[currentElementValue appendString:string];
}
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
if ([elementName isEqualToString:#"characters"] || [elementName isEqualToString:#"codepoint"])
return;
if ([elementName isEqualToString:#"character"]) {
[appDelegate.characters addObject:aCharacter];
[aCharacter release];
} else if ([elementName isEqualToString:#"cp_value"]){
[_codepoint setValue:[[currentElementValue componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] componentsJoinedByString:#""] forKey:currentAttributeKey];
currentElementValue = [[NSMutableString alloc]init];
NSLog(#"_codepoint: %#", _codepoint);
[aCharacter.codepoint addObject:_codepoint];
}
}
where currentAttributeKey is NSMutableString that will store the attributes.In your case ucs and jis208

Resources