XML file parsing delegate issues - ios

i have xml file to which i'm parsing through the delegates method of NSXML parser. I have three delegates method didStart , FoundCharacters and didEndElement. When i parse the file and when it goes in found characters method it shows me all the string data from xml file in console, but i'm trying to take only the given tag data value. Its showing me all the string data from xml file . My xml file is this,
<?xml version="1.0" encoding="UTF-8"?>
<QF id="AB2001" topic="Alertness" category="C&M" ni_exempt="no">
<question>
<xref>DES s4, DES s9, HC r159-161</xref>
<text>Before you make a U-turn in the road, you should</text>
<graphic></graphic>
<prompt>Mark one answer</prompt>
<voice id="AB2001-1"/>
<explanation>
<text>If you want to make a U-turn, slow down and ensure that the road is clear in both directions. Make sure that the road is wide enough to carry out the manoeuvre safely.</text>
<voice id="AB2001-2"/>
</explanation>
</question>
<answers>
<answer correct="no">
<text>give an arm signal as well as using your indicators</text>
<graphic></graphic>
</answer>
<answer correct="no">
<text>signal so that other drivers can slow down for you</text>
<graphic></graphic>
</answer>
<answer correct="yes">
<text>look over your shoulder for a final check</text>
<graphic></graphic>
</answer>
<answer correct="no">
<text>select a higher gear than normal</text>
<graphic></graphic>
</answer>
</answers>
The methods are these through which i'm parsing,
-(void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *) namespaceURI qualifiedName:(NSString *)qName
attributes: (NSDictionary *)attributeDict
{
if([elementName isEqualToString:#"QF"]) {
NSLog(#"ID %#",[attributeDict objectForKey:#"id"]);
NSLog(#"Topic %#",[attributeDict objectForKey:#"topic"]);
}
if( [elementName isEqualToString:#"question"])
{
_foundValue = [[NSMutableString alloc] init];
}
}
-(void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string{
// Store the found characters if only we're interested in the current element.
if([_currentElement isEqualToString:#"xref"]){
// init the ad hoc string with the value
_currentElement = [[NSMutableString alloc] initWithString:string];
NSLog(#"Hello");
} else {
// append value to the ad hoc string
[_currentElement stringByAppendingString:string];
NSLog(#"Hi");
}
NSLog(#"Processing value for : %#", string);
}
-(void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName{
if( [elementName isEqualToString:#"QF"])
{
[_foundValue setString:elementName];
NSLog(#"rr %#",_foundValue);
}
if( [elementName isEqualToString:#"xref"])
{
[_foundValue setString:elementName];
}
_currentElement = nil;
}
In console i'm getting all the string data, from and even from answer tag but i haven't given that tag to parse. I'm confused that why it isn't getting value from the tag which i have given?

If I am understanding correctly what you want (to get xref element's value), first declare a NSMutableString* tmpString to which you will append xref's value in foundCharacters method. Then this should do it:
-(void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *) namespaceURI qualifiedName:(NSString *)qName attributes: (NSDictionary *)attributeDict
{
_currentElement = [[NSMutableString alloc]initWithString:elementName];
if([elementName isEqualToString:#"QF"]) {
NSLog(#"ID %#",[attributeDict objectForKey:#"id"]);
NSLog(#"Topic %#",[attributeDict objectForKey:#"topic"]);
}
if( [elementName isEqualToString:#"xref"])
{
_tmpString = [[NSMutableString alloc] init];
}
}
-(void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string{
if([_currentElement isEqualToString:#"xref"]){
[_tmpString appendString:string];
}
}
-(void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName{
if( [elementName isEqualToString:#"QF"])
{
[_foundValue setString:elementName];
}
if( [elementName isEqualToString:#"xref"])
{
NSLog(#"xref %#",_tmpString);
[_foundValue setString:elementName];
}
_currentElement = nil;
}
Output is:
ID AB2001
Topic Alertness
xref DES s4, DES s9, HC r159-161
FoundCharacters method is one capturing text between start and end tag of an element. So we keep track of current element, and if it is element we are interested in, we get its text inside foundCharacters method.

Related

Parse the Anchor tags and the content using NSXMLParse

I want to parse the html tags inside the "comparison" node
<comparison>
Amazon.com
($34.36) |
Walmart.com
($34.36) |
Rakuten.com
($34.36) |
BestBuy.com
($34.36)
</comparison>
The output I am getting is:
BestBuy.com ($34.36)
The expected output:
Amazon.com ($34.36)
Walmart.com ($34.36)
Rakuten.com ($34.36)
BestBuy.com ($34.36)
But I want to display all the four items.
CODE
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qualifiedName attributes:(NSDictionary *)attributeDict {
currentElementValue = [NSMutableString string];
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
if ([elementName isEqualToString:#"item"]) {
dealsListObj = [[DealsParsingObjects alloc] init];
}
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
[currentElementValue appendString:string];
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {
if ([elementName isEqualToString:#"short_title"]) {
dealsListObj.itemTitle = currentElementValue;
currentElementValue = nil;
}
else if ([elementName isEqualToString:#"final_price"]) {
dealsListObj.price = currentElementValue;
currentElementValue = nil;
}
//Detail view
else if ([elementName isEqualToString:#"merchant"]) {
dealsListObj.itemMerchant = currentElementValue;
currentElementValue = nil;
}
else if ([elementName isEqualToString:#"getdeal"]) {
dealsListObj.itemGetDeal = currentElementValue;
currentElementValue = nil;
}
//comparison
else if ([elementName isEqualToString:#"comparison"]) {
dealsListObj.comparison = currentElementValue;
currentElementValue = nil;
}
else if ([elementName isEqualToString:#"item"]) {
[resultArray addObject:dealsListObj];
[dealsListObj release];
dealsListObj = nil;
currentElementValue = nil;
}
}
It appears you have a DealsParsingObjects class with an NSMutableArray called commentsArray. You instantiate that array, when the parsing begins reading the <comparison> element.
But when the parser has read a <comparison> element, you assign the value to a property called comparison; it doesn't get added to the array. Being an default NSString property (assumption on my part), it simply gets reassigned each time the parser is done reading a <comparison> element.
Edit:
parser:didStartElement:... is called every time a new element is read. This also holds for the <a> tags. In that method you reset currentElementValue. So for each <a> the value is basically reset to an empty string. Only the last read value remains, which is the value of the last <a> tag plus the trailing text.

malloc: error for object: double free

I have been trying to debug this error, and I can't find the issue. From what I have researched, I think that this is telling me that I am trying to release an object that has already been real eased, although I am not sure. I have a object that acts as the delegate for a NSXMLParser object, and I have a property of type NSMutableString that I use to hold the characters of each element. Here is my code:
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
{
self.stringBuffer = [NSMutableString string];
if ([elementName isEqualToString:#"item"])
self.parsingPodcast = YES;
if (attributeDict)
self.currentAttributesDict = attributeDict;
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
if (string) [self.stringBuffer appendString:string];
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
if (self.parsingPodcast)
{
if ([elementName isEqualToString:#"title"])
{
self.currentPodcastObject.title = self.stringBuffer;
}
else if ([elementName isEqualToString:#"pubDate"])
{
self.currentPodcastObject.publishDate = self.stringBuffer;
}
else if ([elementName isEqualToString:#"summary"])
{
self.currentPodcastObject.summary = self.stringBuffer;
}
else if ([elementName isEqualToString:#"imageurl"])
{
self.currentPodcastObject.imgURL = self.stringBuffer;
}
else if ([elementName isEqualToString:#"enclosure"])
{
self.currentPodcastObject.audioURL = [self.currentAttributesDict objectForKey:#"url"];
self.currentPodcastObject.audioType = [self.currentAttributesDict objectForKey:#"type"];
}
else if ([elementName isEqualToString:#"itunes:duration"])
{
self.currentPodcastObject.duration = self.stringBuffer;
}
else if ([elementName isEqualToString:#"item"])
{
parserCompletionBlock(self.currentPodcastObject);
}
}
}
I've enabled zombies in the scheme, and used the zombie tool to try and find any over released object, but I haven't been able to find anything. Here is the output on the console
:malloc: *** error for object 0x10e7531f0: double free
*** set a breakpoint in malloc_error_break to debug
I have added the malloc_error_break breakpoint
The breakpoint stops on the setter method for the self.stringBuffer property. Can anyone help me out? I must be missing something. Thanks in advance for your help!
[NSMutableString string] is autorelease. you should retain when assigning it on self.stringBuffer.
self.stringBuffer = [NSMutableString string] retain]
I actually got this error because the memory in my phone was almost full. Once i cleared some apps in my phone, the error went away. Not sure if this is useful, but it definitely helped me.

How can I parse this xml in iOS 7?

I want to parse this XML:
<?xml version="1.0" encoding="UTF-8"?>
<eventdata>
<rev></rev>
<event>
<id> </id>
<name></name>
<thumb> </thumb>
<eimage></eimage>
<artists></artists>
<date></date>
<time> </time>
<cost> </cost>
<discount> </discount>
<gmap> </gmap>
<web> </web>
<desc> </desc>
<file>
<src> </src>
<size> </size>
</file>
<vtype></vtype>
<address></address>
<area></area>
<city></city>
<pcode></pcode>
<lmark></lmark>
<likes></likes>
<hl></hl>
<pref></pref>
<img> <src> </src>
<size> </size></img>
<vid> <src> </src>
<size> </size></vid>
</event>
<event>
<id> </id>
<name></name>
<thumb> </thumb>
<eimage></eimage>
<artists></artists>
<date></date>
<time> </time>
<cost> </cost>
<discount> </discount>
<gmap> </gmap>
<web> </web>
<desc> </desc>
<file>
<src> </src>
<size> </size>
</file>
<vtype></vtype>
<address></address>
<area></area>
<city></city>
<pcode></pcode>
<lmark></lmark>
<likes></likes>
<hl></hl>
<pref></pref>
<img> <src> </src>
<size> </size></img>
<vid> <src> </src>
<size> </size></vid>
</event>
</eventdata>
I tried this code:
- (void)viewDidLoad
{
[super viewDidLoad];
_currentParsedCharacterData = [[NSMutableString alloc] init];
NSString *path = [[NSBundle mainBundle] pathForResource:#"NewYearPartyData" ofType:#"xml"];
NSData *data = [[NSData alloc] initWithContentsOfFile:path];
NSXMLParser *parser = [[NSXMLParser alloc] initWithData:data];
[parser setDelegate:self];
// parsing...
BOOL success = [parser parse];
// test the result
if (success) {
//NSLog(#"No errors - user count : %i", [parser [users count]]);
NSLog(#"Success");
// get array of users here
// NSMutableArray *users = [parser users];
} else {
NSLog(#"Error parsing document!");
}
}
#pragma mark - NSXMLParser delegate methods
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict {
if ([elementName isEqualToString:#"event"]) {
NSLog(#"user element found – create a new instance of User class...");
//user = [[User alloc] init];
//We do not have any attributes in the user elements, but if
// you do, you can extract them here:
// user.att = [[attributeDict objectForKey:#"<att name>"] ...];
NSLog(#"Event Name = %#", [attributeDict objectForKey:#"name"]);
NSLog(#"attributeDict = %#", attributeDict);
}
if ([elementName isEqualToString:#"name"]) {
NSLog(#"attributeDict = %#", attributeDict);
NSLog(#"Event Name = %#", [attributeDict objectForKey:#"name"]);
NSLog(#"elementName = %#", elementName);
}
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {
NSLog(#"didEndElement");
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
NSLog(#"value of element %#", string);
}
- (void)parser:(NSXMLParser *)parser parseErrorOccurred:(NSError *)parseError {
}
Someone who is good in NSXMLParser - I request them to explain to me the flow.
My basic question is "How to access data of event i.e., id, name, thumb etc?"
NSXMLParsing is the easiest way to parse data. You can easily access data of event i.e., id, name, thumb etc using the delegate method
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {
}
You can create a NSOBject class named Event.
Here is my code
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {
if ([elementname isEqualToString:#"id"])
{
event.id = currentNodeContentChapters;
}
if ([elementname isEqualToString:#"name"])
{
event.name = currentNodeContentChapters;
}
if ([elementname isEqualToString:#"thumb"])
{
event.thumb = currentNodeContentChapters;
}
if ([elementname isEqualToString:#"eiimage"])
{
event.eiimageUrl = currentNodeContentChapters;
}
-------------------
---------------
}
Hopefully it will work for you .

Objective-C:How to read an attribute value in XML

Hi friends am new to iphone app developing. Actually i have to parse XML file and have display it in a tableviewcontroller. Am using storyboards. i have parsed Xml successfully and parsed data and displayed it. But i cannot able to read this attribute <Event count="-1"> i have read this value and have to display it on the tab bar i have to set badge value as -1
Pls help me How to do it. Thanks in advance.. Here is my Xml file
<boards>
<board count="-1">
<newboard>
<id>9</id>
<invitationdet>qweq</invitationdet>
<readflag>1</readflag>
<responseflag>1</responseflag>
</newboard>
<newboard>
<id>8</id>
<invitationdet>asd</invitationdet>
<readflag>1</readflag>
<responseflag>1</responseflag>
</newboard>
</board>
<back count="0">
<backboard>
<id>2</id>
<feedbackdet>Meeting with Clients</feedbackdet>
<readflag>1</readflag>
<responseflag>0</responseflag>
</backboard>
<backboard>
<id>1</id>
<feedbackdet>Board Meeting with employees</feedbackdet>
<readflag>1</readflag>
<responseflag>0</responseflag>
</backboard>
</back>
<letter count="3">
<newletter>
<id>4</id>
<letterdet>NewsLetter for the month of October 2013</letterdet>
<readflag>1</readflag>
</newletter>
<newletter>
<id>3</id>
<letterdet>Newsletter for the month of September 2013</letterdet>
<readflag>0</readflag>
</newletter>
<newletter>
<id>2</id>
<letterdet>Newsletter for the month of August 2013</letterdet>
<readflag>0</readflag>
</newletter>
<newletter>
<id>1</id>
<letterdet>Newsletter For the month of July 2013</letterdet>
<readflag>0</readflag>
</newletter>
</letter>
</boards>
And Here is my XMLParser File
-(void) parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qualifiedName attributes:(NSDictionary *)attributeDict
{
if([elementName isEqualToString:#"boards"]) {
rssOutputData = [[NSMutableArray alloc] init];
}
if([elementName isEqualToString:#"board"]) {
//Initialize the array.
aEvent.count = [attributeDict objectForKey:#"count"];
NSLog(#"Reading count value :%#", aEvent.count);
}
else if([elementName isEqualToString:#"newboard"]) {
//Initialize the book.
aEvent = [[Eventlist alloc] init];
//Extract the attribute here.
aEvent.id = [[attributeDict objectForKey:#"userid"] integerValue];
NSLog(#"Reading id value :%d", aEvent.id);
}
NSLog(#"Processing Element: %#", elementName);
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
if(!nodecontent)
nodecontent = [[NSMutableString alloc] initWithString:string];else
[nodecontent appendString:string];
NSLog(#"Processing Value: %#", nodecontent);
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {
if([elementName isEqualToString:#"boards"])
return;
if([elementName isEqualToString:#"board"])
return;
if([elementName isEqualToString:#"newboard"]) {
[rssOutputData addObject:aEvent];
[aEvent release];
aEvent= nil;
}
else
[aEvent setValue:nodecontent forKey:elementName];
[nodecontent release];
nodecontent = nil;
}
I can read datas correctly but i cannot able to read Attribute values pls help me friends
Try like the below
- (void)parser:(NSXMLParser *)parser
didStartElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI
qualifiedName:(NSString *)qualifiedName
attributes:(NSDictionary *)attributeDict
{
// just do this for item elements
if(![elementName isEqual:#"letter"])
return;
// then you just need to grab each of your attributes
int count = [attributeDict objectForKey:#"count"];
}
In the following method you have noticed that, there is a parameter attributeDict which holds all the attributes of tag
-(void) parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qualifiedName attributes:(NSDictionary *)attributeDict
{
if([attributeDict valueForKey:#"count"]) {
NSLog(#"%#", [attributeDict valueForKey:#"count"]);
}
}
You can read it as defined in the above code. just log whole attributeDict and you will get your answer. - Good Luck

NSXMLParser strange behavior with \n

I'm developing an iOS 4 application that parses a XML file. A piece of XML is:
<?xml version="1.0" encoding="utf-8" ?>
<cards>
<card id ="0">
<name lang="es">The Mad</name>
<description lang="es">...</description>
</card>
...
</cards>
I use the following method to parse <name lang="es">The Mad</name>.
#pragma mark -
#pragma mark NSXMLParserDelegate methods
- (void)parser:(NSXMLParser *)parser
didStartElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI
qualifiedName:(NSString *)qName
attributes:(NSDictionary *)attributeDict
{
NSLog(#"DidStartElement: %#", elementName);
if ([elementName isEqualToString:#"card"])
{
currentCard = [[Card alloc] init];
NSString* arcaneNumber = [attributeDict objectForKey:#"id"];
currentCard.Number = arcaneNumber;
return;
}
if ([elementName isEqualToString:#"name"])
{
if ([[attributeDict objectForKey:#"lang"] isEqualToString:userLanguage])
{
currentProperty = kNameProperty;
return;
}
}
if ([elementName isEqualToString:#"description"])
{
if ([[attributeDict objectForKey:#"lang"] isEqualToString:userLanguage])
{
currentProperty = kDescriptionProperty;
return;
}
}
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
if (!currentStringValue)
{
// currentStringValue is an NSMutableString instance variable
currentStringValue = [[NSMutableString alloc] initWithCapacity:50];
}
[currentStringValue appendString:string];
}
- (void) parser:(NSXMLParser *)parser
didEndElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI
qualifiedName:(NSString *)qName
{
NSLog(#"DidEndElement: %#", elementName);
if ([elementName isEqualToString:#"card"])
{
[cards setObject:currentCard forKey:currentCard.Number];
[currentCard release];
currentCard = nil;
return;
}
if (currentProperty == kNameProperty)
{
currentProperty = kNoneProperty;
currentCard.Name = [currentStringValue stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
[currentStringValue release];
currentStringValue = nil;
return;
}
if (currentProperty == kDescriptionProperty)
{
currentProperty = kNoneProperty;
currentCard.Description = currentStringValue;
[currentStringValue release];
currentStringValue = nil;
return;
}
}
After, parsing , I get on currentStringValue the following:
\n\nThe Mad
How can avoid these two '\n'? Why am I getting these two '\n'?
This xml file came from a Windows system, and I've used TextWrangler to covert it to Classic Mac format.
The foundCharacters delegate method also gets called for whitespace in between elements. It will get called if there is say a newline between <cards> and <card id=....
I suggest clearing currentStringValue at the top of didStartElement to discard any characters found before the start of the current element and to make sure only the characters inside the current element (not between) are captured by foundCharacters.
At the top of didStartElement, add:
[currentStringValue release];
currentStringValue = nil;
It is possible for an element's value to contain whitespace (so removing them in didEndElement could result in saving values that don't match the xml content).
On your end element method you can try stripping these out yourself from the current text string. Simply try searching for them on the string and replace them with #"". I like replacing these and unwanted blank entries.
Try this it work for me ,
NSString *data= [str stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
Use above line of code in foundCharacters method .
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string;
{
NSString *data= [string stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
if(dString == nil){
dString = [[NSMutableString alloc] initWithString:data];
}else
{
[dString appendString:data];
}
}
Hope this will help for some one .

Resources