How to parse XML to iPhone correctly - iphone

I have an XML file, but do not know what I have done wrong as the app crashed, I do not know how to solve it. Can anyone help giving me some comments.
<list>
<section name="Texts">
<item>
<postID>26</postID>
<title>A sample quiz</title>
<url>http://yahoo.com</url>
<score>20</score>
</item>
<item>
<postID>230</postID>
<title>A sample quiz</title>
<url>http://www.yahoo.com</url>
<score>20</score>
</item>
</section>
<section name="Images">
<item>
<postID>27</postID>
<title>A sample image quiz</title>
<url>www.google.com</url>
<score>10</score>
</item>
<item>
<postID>27</postID>
<title>A sample image quiz</title>
<url>www.google.com</url>
<score>10</score>
</item>
</section>
</list>
Code I have used:
-(allChallengeParser *)initXMLParser
{
self = [super init];
appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
appDelegate.allChallengeArray = [[NSMutableArray alloc]init];
xmlChallengeRoot =[[NSMutableArray alloc]init];
return self;
}
-(void)parser:(NSXMLParser *)parser
didStartElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI
qualifiedName:(NSString *)qName
attributes:(NSDictionary *)attributeDict {
//Implement method called NSXMLParser when it hits the start of an element:
if([elementName isEqualToString:#"list"])
{
NSLog(#"list root element found – create a new instance of challenge OBj...");
allChallengeObj = [[allChallenge alloc] init];
//We do not have any attributes in the user elements, but if
// if have can extract them here:
// user.att = [[attributeDict objectForKey:#"<att name>"] ...];
}
else if([elementName isEqualToString:#"section"])
{
allChallengeObj = [[allChallenge alloc] init];
allChallengeObj.section = [attributeDict valueForKey:#"name"];
NSLog(#"allChallengeObj.section %#", allChallengeObj.section);
}
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
if(!currentElementValue)
// init the ad hoc string with the value
currentElementValue = [[NSMutableString alloc] initWithString:string];
else
// append value to the ad hoc string
[currentElementValue appendString:string];
NSLog(#"Processing Value for: %#", currentElementValue);
}
- (void)parser:(NSXMLParser *)parser
didEndElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI
qualifiedName:(NSString *)qName {
if ([elementName isEqualToString:#"list"]) {
return;
}
if ([elementName isEqualToString:#"section"]) {
// We are done with user entry – add the parsed user
// object to our user array
[xmlChallengeRoot addObject:allChallengeObj];
// release user object
allChallengeObj = nil;
}
else
{
// The parser hit one of the element values.
// This syntax is possible because User object
// property names match the XML user element names
NSLog(#"elementName %#",elementName);
NSLog(#"current Element Value %#",currentElementValue);
[allChallengeObj setValue:currentElementValue forKey:elementName];
}
currentElementValue = nil;
}

Could you give us error message?
For parsing on iPhone you can use external libraries. Here are some test related to them http://www.raywenderlich.com/553/how-to-chose-the-best-xml-parser-for-your-iphone-project NSXMLParser is really simple event parser.

Related

xml parsing in iOS with too many tags with the same name

I have got the xml parsing, but a bit difficult to parse the xml below
thanks for your suggestions
<?xml version="1.0" encoding="UTF-8"?>
<AllJobs>
<Mainjobs>
<job1 name="simple">
<Group name="one">
<item name>"itemone"</item name>
<item name>"itemtwo"</item name>
<item name>"itemthree"</item name>
</Group>
<Group name="two">
<item name>"itemfour"</item name>
<item name>"itemfive"</item name>
<item name>"itemsix"</item name>
</Group>
</job1>
<job2 name="medium" />
</job2>
<job3 name="hard" />
</job3>
</Mainjobs>
</AllJobs>
from the above xml i am trying to parse the below item names that are "itemFour,item five,item six" and displaying them in a tableview
<Group name="two">
<item>"itemfour"</item>
<item>"itemfive"</item>
<item>"itemsix"</item>
i am parsing like this but it is retrieving all the items names in every group tag
-(void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict {
if([elementName isEqualToString:#"Alljobs"]){
jobNameArray=[[NSMutableArray alloc]init];
}else if([elementName isEqualToString:#"Mainjobs"]){
// self.itemDict = [[NSMutableDictionary alloc] init];
object=[[parseObject alloc]init];
dict=[[NSMutableDictionary alloc] init];
}
else if([elementName isEqualToString:#"Group"])
{
if ([str isEqualToString:#"Two"]) {
currentElement=nil;
currentElement=[[NSMutableString alloc]init];
}
}
else if([elementName isEqualToString:#"item"])
{
str=[attributeDict objectForKey:#"name"];
NSLog(#"the attribute string is %#",[attributeDict objectForKey:#"name"]);
}
}
-(void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
if(string){
[currentElement appendString:string];
NSLog(#" the element00000000%#", currentElement);
}
}
-(void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI: (NSString *)namespaceURI qualifiedName:(NSString *)qName {
if([elementName isEqualToString:#"Mainjobs"]){
NSLog(#"the array count is %i",[jobNameArray count]);
}
else if([elementName isEqualToString:#"Job1"])
{
}
if([elementName isEqualToString:#"</item>"])
{
NSLog(#"element ---------%#",elementName);
[jobNameArray addObject:str];
}
By using NSXmlParser this is more difficult because it finds the characters by distinguished tags. I have also faced the same issue way back . That time I solved this by maintaining the depth variable.By looking towards your xml that job attribute is not seems to be ok for me because if you have n numbers of the job then on which basis you gone compare those ? But in your case I think you can achieve as follow:
Make a class named job.
job class having following properties:
jobName:NSString;
groupName:NSString;
items:NSMutableArray;
Add this Job object to the array .

HTML code disappears in String iOS

I am parsing XML file with RSS from an URL. In the XML, there is a tag as description.
<description>
<![CDATA[
<img width="150" height="150" src="http://www.ipadia.co/wp-content/uploads/2012/02/sayfada-bul-150x150.png" class="attachment-thumbnail wp-post-image" alt="sayfada bul" title="sayfada bul" />Yine çok kişinin dikkatinden kaçan ama faydalı bir araç Bulunduğunuz sayfada arama yapmak bazen çok gerekli olabiliyor Bunun için google arama tabınıkullanacağız Google aramatab ına tıklayin Resimdeki gibi Arama listesinin sonunda bu sayfada bul çıkacak Arama yapmak istediğiniz kelimeyi yazın … Continue reading <span class="meta-nav">→</span>
]]>
</description>
I am using this code as NSString. As you see, there is an image link at the beginning of description tag. I want to take the image link from this string. But when I parse this, It is giving me just the text, not HTML code. When I write this with NSLog, I can't see the image link in it. In short, Xcode doesn't give me the HTML code in the string.
I tried to load this code in UIWebView assuming that it can show the image. But the image didn't be shown in WebView either. Just the text was displayed.
When I look the RSS in browser, I can see the image code in it, but in Xcode, I can't see HTML code, it just gives me the plain text. How can I solve this problem?
Thank you very much.
EDIT: I think the CDATA may cause the issue. How can I challenge with that?
These are my XMLParser methods.
-(void) parser: (NSXMLParser *) parser didStartElement: (NSString *) elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
{
if([elementName isEqualToString:#"channel"])
if (!ItemA)
{
ItemA = [[NSMutableArray alloc] init];
}
if([elementName isEqualToString:#"item"]){
// NSLog(#"ITEM OLUŞTURULDU.");
anItem= [[Item alloc] init];
}
}
-(void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
if (!currentElementValue)
currentElementValue = [[NSMutableString alloc] initWithString:string];
else
[currentElementValue appendString:string];
// NSLog(#"PRCOSSING VALUE :%#", currentElementValue);
}
-(void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
if([elementName isEqualToString:#"channel"])
return;
if ([elementName isEqualToString:#"item"])
{
// NSLog(#"qqqqqq:%#", anItem.title);
[ItemA addObject:anItem];
counter++;
// NSLog(#"kkk:%i", ItemA.count);
// NSLog(#" -*-*-*-*-* COUNTER: %d",counter);
anItem = nil;
return;
}
if ([elementName isEqualToString:#"title"])
{
anItem.title=currentElementValue;
// NSLog(#"kkk-title:%#", anItem.title);
}
if ([elementName isEqualToString:#"description"])
{
anItem.description=currentElementValue;
// NSLog(#"kkkkkk-desc:%#", anItem.description);
}
if ([elementName isEqualToString:#"link"])
{
anItem.link=currentElementValue;
// NSLog(#"kkkkkk-link:%#", anItem.link);
}
if ([elementName isEqualToString:#"pubDate"])
{
anItem.pubDate=currentElementValue;
// NSLog(#"kkkkkk-pubdate:%#", anItem.pubDate);
}
if ([elementName isEqualToString:#"category"])
{
anItem.category=currentElementValue;
// NSLog(#"kkkkkk-category:%#", anItem.category);
}
currentElementValue = nil;
}

NSMutableArray and NSDictionary using for parsed xml data

Please anybody help me.i am in great trouble....Now my Problem is...
Using xml parser i have parsed some attribute and value of the attribute.
using this i am getting the element name:
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes: (NSDictionary *)attributeDict
Now using this i am getting value of the attribute from the xml:
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string{
NSLog(#"found characters: %# %#", currentElement,string);
suppose my xml data are something like that...
-<list>
−<ProductData HASH="838557843">
<id>1</id>
<productNumber>a91cc0f4c7</productNumber>
<name>Product 1</name>
<seoTitle>product-1</seoTitle>
<viewCount>0</viewCount>
<lowStock>0.0</lowStock>
<image>5e928bbae358c93caedf6115fa7d178b.jpg</image>
<dateCreated>2011-10-06T16:08:45</dateCreated>
<dateUpdated>2011-10-06T10:08:45</dateUpdated>
<isDummy>true</isDummy>
<isInventory>false</isInventory>
</ProductData>
-<ProductData HASH="681596439">
<id>2</id>
<productNumber>d8287e2e51</productNumber>
<name>Product 2</name>
<seoTitle>product-2</seoTitle>
−<description>
<p>Lorem ipsum dolor sit amet, consectetuer adipiscing elit,....</p>
</description>
<viewCount>0</viewCount>
<availableStock>100.0</availableStock>
<lowStock>0.0</lowStock>
<image>8bbd8dfff3cdd28285d07810a4fe7c32.jpg</image>
<basePrice>10.0</basePrice>
<costPrice>10.0</costPrice>
<height>1.0</height>
<width>1.0</width>
<depth>1.0</depth>
<weight>3.0</weight>
<status>A</status>
<quantityOrderMin>1.0</quantityOrderMin>
<productIsCall>false</productIsCall>
<quantityOrderMax>20.0</quantityOrderMax>
<priceByAttribute>false</priceByAttribute>
<dateCreated>2011-10-06T16:08:45</dateCreated>
<dateUpdated>2011-10-06T10:08:45</dateUpdated>
<isDummy>true</isDummy>
<isInventory>false</isInventory>
</ProductData>
</list>`
Now when i will get the id attribute then it will store in an array then all of the attribute after first id until next id i want to store the attribute and its value in the dictionary,when i will get second id then i want to continue previous process...then according to the value of id i want to display the value in a UIView or UITableView. its not neccesary where i want to display it.
My question is how can i store data in array and dictionary and display it any time in my viewcontroller. Please help me. its becoming a great trouble for me. if you can please give me a sample code as an example. please please anybody help me...
Thanks in Advance
If you change your XML to
<list>
<Object>
<id>1</id>
<product>name</product>
<image>imagename.jpg</image>
<dateCreated>date</dateCreated>
<productleft>10</productleft>
</Object>
<Object>
<id>2</id>
<product>name</product>
<image>imagename.jpg</image>
<dateCreated>date</dateCreated>
<productleft>30</productleft>
</Object>
</list>
Or if your XML looks something like above its easy to use SAX parser ( NSXMLParser you've used ). Otherwise if you want to stick to XML you have posted use DOM style parsing.
Here is the code for the XML after formatting using NSXMLParser.
// these are ivars
NSMutableArray * objectsArray;
NSMutableDictionary * productDict;
NSMutableString * currentString;
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qualifiedName attributes:(NSDictionary *)attributeDict
{
if([elementName isEqualToString:#"Object"])
{
objectsArray = [[NSMutableArray alloc] init];
productDict = [[NSMutableDictionary alloc] init];
}
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
if(!currentString)
{
currentString = [[NSMutableString alloc] init];
}
[currentString appendString:string];
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
if([elementName isEqualToString:#"id"])
{
[productDict setObject:currentString forKey:#"id"];
[currentString release],currentString = nil;
return;
}
if([elementName isEqualToString:#"product"])
{
[productDict setObject:currentString forKey:#"product"];
[currentString release],currentString = nil;
return;
}
if([elementName isEqualToString:#"image"])
{
[productDict setObject:currentString forKey:#"image"];
[currentString release],currentString = nil;
return;
}
if([elementName isEqualToString:#"dateCreated"])
{
[productDict setObject:currentString forKey:#"dateCreated"];
[currentString release],currentString = nil;
return;
}
if([elementName isEqualToString:#"productleft"])
{
[productDict setObject:currentString forKey:#"productleft"];
[currentString release],currentString = nil;
return;
}
if([elementName isEqualToString:#"Object"])
{
[objectsArray addObject:productDict];
[productDict release],productDict = nil;
}
[currentString release], currentString = nil;
}

NSXML parsing loops 3 times over 1 node

I'm using NSXMLParser to parse an XML file. I'm doing this several times in my app for different purposes. I have one which parses annotations for a store locator, one that parses al the movies from a certain YouTube channel and the last one parses a self made XML file.
All parsers work great except the last one. For some kind of reason it parses i.e. the first node good, but then overwrites it.
Here is my parser code:
//Standard function parser: reading open tag
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
attributes:(NSDictionary *)attributeDict{
currentElement = [elementName copy];
if ([elementName isEqualToString:#"item"]) {
xmlArray = [[NSMutableDictionary alloc] init];
}
}
//Standard function parser: reading string
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string{
if ([currentElement isEqualToString:#"created_time"]){
[xmlArray setObject:string forKey:currentElement];
NSLog(#"test 1 %#", string);}
}
//Standard function parser: reading close tag
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI
qualifiedName:(NSString *)qName{
if ([elementName isEqualToString:#"item"]) {
Post *newPost = [[Post alloc] init];
NSLog(#"test %#", xmlArray );
newPost.created_time = [xmlArray objectForKey:#"created_time"];
[containerArray addObject:newPost];
[xmlArray release];
}
}
The XML looks like this:
<?xml version="1.0" encoding="UTF-8" ?>
<items>
<item>
<created_time>test</created_time>
<message>blabla</message>
<picture>http://www.trentshow.com/images/tada.jpg</picture>
</item>
</items>
And the log outputs the following:
2011-06-10 10:43:24.446 TabbedCalculation[1502:207] test 1 test
2011-06-10 10:43:24.448 TabbedCalculation[1502:207] test 1
2011-06-10 10:43:24.449 TabbedCalculation[1502:207] test 1
2011-06-10 10:43:24.450 TabbedCalculation[1502:207] test {
"created_time" = "\n";
}
I'm not getting why the parser loops 3 times over the created_time node. Any help would be great!
Try by following solution -- should work.
foundCharacters can be called for multiple time for each key value --- basically you should append all found character list.
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string{
if ([currentElement isEqualToString:#"created_time"]){
NSString *valueKey = [xmlArray ValueForKey:forKey:currentElement];
if(nil != valueKey)
{
valueKey = [valueKey stringByAppendingString:string];
}else
{
valueKey = string;
}
[xmlArray setObject:valueKey forKey:currentElement];
NSLog(#"test 1 %#", string);}
}

How add a default value to an array when child element is not found in xml parsing?

I am new to iphone development.I am parsing an XML page and displaying the content in a tableview.In some block in the XML page , the child element is missing , i want to add a value o in my array, when the child element is not fond in the particular block.My XML file is like
<entry>
<id>xxx </id>
<title>xxxxx</title>
<gd:ratings numRaters="2"/>
</entry> ..................................>first block
<entry>
<id>xxx </id>
<title>xxxxx</title>
</entry> ....................................>Second block
<entry>
<id>xxx </id>
<title>xxxxx</title>
<gd:ratings numRaters="2"/>
</entry> .....................................>Third block
I am parsing the gd:ratings tag and display its attribute numRates value in a tableview. I am having an mutable array which stores the value of numRates.I have to add object "O" in the array when the second block is parsed because it doesnot contain gd:ratings tag.Since the value is present in a attribute tag, for retrieving the content and adding it to the mutable array is done in NSXML parser DidStartElement method.
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict{
currentElement = [elementName copy];
if ([elementName isEqualToString:#"entry"]) {
entry = [[NSMutableDictionary alloc] init];
currentTitle = [[NSMutableString alloc] init];
currentDate = [[NSMutableString alloc] init];
NSLog(#"inside image1 ");
}else if([elementName isEqualToString:#"media:thumbnail"])
{ currentImage = [[NSMutableString alloc] init];
if(myUrl == nil){
myUrl = [NSString stringWithString:[attributeDict objectForKey:#"url"]];
}
[currentImage appendString:myUrl];
[stories1 addObject:currentImage];
myUrl=nil;
} else if([elementName isEqualToString:#"gd:rating"])
{
currentRating=[[NSMutableString alloc]init];
myRatings=[NSString stringWithString:[attributeDict objectForKey:#"numRaters"]];
[currentRating appendString:myRatings];
[stories2 addObject:currentRating];
}
}
Since there are 25 blocks of entry tags and in that 10 block doesnot have gd rating element .So the array stories2 array has only 15 values.So i cannot display it in the tableview in order.Is there any way out to retrieve the attribute tag in "found characters" method . Please help me out.Thanks.
You can use the didEndElement method: when the outer element ended, check if the child element was added to the array.
You could use an iVar BOOL entryHasRating and do the following:
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict{
currentElement = [elementName copy];
if ([elementName isEqualToString:#"entry"]) {
entryHasRating = NO;
...
} else if ([elementName isEqualToString:#"gd:rating"]){
entryHasRating = YES;
...
}
}
Then when an element ends:
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {
if ([elementName isEqualToString:#"entry"]&& !entryHasRating) {
[stories2 addObject:#"No Rating"];
entryHasRating = YES;
}
...
}
If you know all of the data fields that you'll be expecting, you could build a dictionary with placeholders for all of your expected values before you parse the XML; as you parse the XML just replace the placeholders with real values.