I have got following xml which I need to parse using TouchXML.
<?xml version="1.0"?>
<categories>
<category0>
<title>Alcoholic Drinks</title>
<description>Buy beers, wines, sprits and champagne from the top online alocholic drink stores.
Whatever your tipple you are sure to find a drinks supplier from our top shops below:
</description>
<status>1</status>
<popularStatus></popularStatus>
<order></order>
<link>alcoholic-drinks</link>
<id>1</id>
</category0>
<category1>
<title>Art and Collectibles</title>
<description>Are you looking to buy contemporary or fine art, or do you prefer to make your own artwork?&#
Whether type of artwork or craft materials you are looking for, you are certain to find one of the shops below more than helpful:
</description>
<status>1</status>
<popularStatus></popularStatus>
<order></order>
<link>art-and-collectibles</link>
<id>2</id>
</category1>
<category2>
<title>Auctions</title>
<description>Are you looking for the UK's biggest and best Auction Sites?
The team at safebuyer.co.uk have scoured the web to find the UK's favourite auctions, so why wait, start your bidding now!
</description>
...
...
...
I am thinking to create two loops from root node in order to fetch title and link but coudnt figure out how to do it. Can anybody help please.
If you can change your XML file and make all the category tag same. You can put all ... Instead of ... and ....
So that would be pretty easy to parse. You just need to make category class and all the tag would be parse automatically if you have correct xml parsing code.
CXMLNode *node;
for(i=0; i<10 ; i++){
NSString *xpath = [NSString stringWithFormat:#"//category%d/title", i];
NSArray *title = [[node nodesForXPath:xpath] stringValue];
}
Use the above code..
CXMLElement *element;
NSArray *titleItems = [[NSArray alloc] initWithArray:[element nodesForXPath:#"//category" error:nil]];
for(CXMLElement *item in titleItems){
NSString *title = [[item selectSingleNode:#"title"] stringValue];
}
Note: category node should be repeating.....
The code below gives you a dictionary where keys are titles and data are the links. Of course, if your XML document is "big", this is not the best way to do it.
CXMLDocument *doc = [[[CXMLDocument alloc] initWithXMLString:theXML options:0 error:nil] autorelease];
NSArray *categories = nil;
NSMutableDictionary* results = nil;
categories = [doc nodesForXPath:#"/categories/*[starts-with(name(), 'category')]" error:nil];
if (categories != nil && [categories count] > 0)
{
results = [NSMutableDictionary dictionaryWithCapacity:[categories count]];
for (CXMLElement *category in categories)
{
NSArray* titles = [category elementsForName:#"title"];
if ([titles count] >0)
{
NSArray* links = [category elementsForName:#"link"];
[result setObject:([links count]>0?[[links objectAtIndex:0] stringValue]:nil;
forKey:[[titles objectAtIndex:0] stringValue]];
}
}
}
Related
How would I pick out certain part of NSMutableArray?
One fielding array from server is 2012-09-01 09:00:00 America/Los_Angeles
I am trying to get just the time.
I was thinking turning it into a string and then getting it and then back into NSMutablearray to populate to tableview cells.
I am still looking at documentation
Options I am thinking of:
-subarrayWithRange:
componentsSeparatedByString:
UPDATE:
Here is what I am doing now to get the field of appointments
NSDictionary *json = [NSJSONSerialization JSONObjectWithData:responseData options:NSJSONReadingMutableContainers error:&error];
NSDictionary* myslots =[json objectForKey:#"slots"];
self.timesArray = [[NSMutableArray alloc] init];
NSLog(#"allslots: %#", myslots);
for (NSString *slotKey in myslots.allKeys) {
NSDictionary *slot = [myslots valueForKey:slotKey];
for (myDays in slot){
if ([[self.myDays objectForKey:#"isReservable"] isEqualToNumber:[NSNumber numberWithInt:1]])
[self.timesArray addObject:[self.myDays objectForKey:#"begin"]];
//NSLog(#"This is the times count: %#", timesArray.count);
}
}
NSLog(#"These are the times avail: %#", self.timesArray);
[self.tableView reloadData];
}
All I want eventually is an array of just the times. I am sorry if I am not being clear. I am trying to. Please let me know what information I can provide to paint a clearer picture
I'd save it as a string first
NSString *someString = [myArray objectAtIndex:index];
and then use something like NSMakeRange to get just that bit
[someString substringWithRange:NSMakeRange(11,18)];
I used to have trouble parsing json, before I found a really good tutorial which I could follow. When I have been building my own webservices to parse json from I have followed the same steps, but now when I'm trying to parse twitters json-feed I'm drawing blanks. Here's my code.
NSError* error;
NSDictionary* json = [NSJSONSerialization
JSONObjectWithData:responseData //1
options:kNilOptions
error:&error];
NSArray* itemNumber = [json objectForKey:#"posts"]; //2
NSUInteger numObjects = [itemNumber count];
arrayTweets = [[NSMutableArray alloc] init];
arrayTimes = [[NSMutableArray alloc] init];
if (numObjects != 0) {
int i = 0;
do
{
NSDictionary* loan = [itemNumber objectAtIndex:i];
NSString* text = [(NSDictionary*)loan objectForKey:#"text"];
[arrayTweets addObject:text];
NSString *time = [(NSDictionary*)loan objectForKey:#"created_at"];
[arrayTweets addObject:time];
i++;
} while (i < numObjects);
} else {
NSLog(#"Nej");
}
[tableTweet performSelectorOnMainThread:#selector(reloadData) withObject:nil waitUntilDone:NO];
Notice the "NSArray* itemNumber = [json objectForKey:#"posts"];". Since my old json-feed used to look something like this...
{"status":"ok","count":4,"count_total":4,"pages":1,"posts":[{"id":58,"type":
it was working since I had the "posts" before :[, but now with the twitter feed it just starts right into:
[{"created_at":"Mon Aug 06 19:16:42 +0000 2012","id":232555817835048961,"...
And I have no idea what to do. I realize this is stupid, but I don't think I'm going to learn unless someone explains it to me.
Any help appreciated!
Aah, there is a small problem with your code. The root object of your previous feed used to be a dictionary. You can see this by the { sign at the beginning. Your new feed instantly gives you an array back [. So you don't have to parse your data as a dictionary but as as NSArray. Without further ado, explanation here: https://stackoverflow.com/a/8356919/341358
I have a method where I fetch GDataFeedBase entries and return these as an array to another function
NSMutableArray *tempFeedArray = [NSMutableArray array];
NSURL *feedURL = [[NSURL alloc] initWithString:escapedUrlString];
NSData *data = [NSData dataWithContentsOfURL:feedURL];
GDataFeedBase *feedBase = [[GDataFeedBase alloc] initWithData:data];
[tempFeedArray addObjectsFromArray:[feedBase entries]];
[feedURL release];
[feedBase release];
return tempFeedArray;
.....
I have another function where I retrieve required values from tempFeedArray object that is GDataEntryYouTubeVideo
for(int count = 0; count < loopCount; count ++){
NSMutableDictionary *feedBaseEntryDict = [[NSMutableDictionary alloc] init];
entry = [tempFeedArray objectAtIndex:count];
youTubeUrl = [[entry alternateLink] href];
if ([entry statistics]!= nil) {
noOfVws= [[[entry statistics] viewCount] intValue];
}
duratn = [[[entry mediaGroup] duration] stringValue];
descr = [[[entry mediaGroup] mediaDescription] stringValue];
authorName = [[[entry authors] objectAtIndex:0] name];
publishedDt = [[entry publishedDate] stringValue];
rating = [[[entry rating] average] stringValue];
imageURL = [[[[entry mediaGroup] mediaThumbnails] objectAtIndex:0] URLString];
videoTitle = [[[entry mediaGroup] mediaTitle] stringValue];
.....
}
......
For the first time everything works fine. But the next time, it shows memory leak at
GDataXMLNode stringFromXMLString:
Did anyone else face this issue?
I found similar issue raised in gdata developer forum:
http://groups.google.com/group/gdata-objectivec-client/browse_thread/thread/f88de5a7bb784719/cab328a8725ee6c5
but the solution doesn't solve the issue.
Any help is much appreciated.
Looks like it might not be your code but the client library there were a few other threads on the same issue. This one has a work around, but I have not tried it myself.
The other options you have would be to upgrade to latest version (1.12 was released on Apr 11th 2011), take a look at the source and try to track down your problem, or submit an issue (it looks like the project is still actively developed).
Since the code is "stealing" entries from the feed, leaving them pointing to their parent feed (rather than copying the entries, which would create independent versions) there may be an issue with the strings cache. Try disabling the cache by commenting out -addStringsCacheToDoc in GDataXMLNode.m
i want to populate the tablecell with title and imageurl from xml list.
i manage to store the title (NSMutableDictonary *sections )and imageURL (NSMutableDictonary *sectionsImg) into 2 NSMutableDictionary respectively.
/*******This is in viewDidLoad***/
Directory *allDirectory = [appDelegate.directories objectAtIndex:0];
for (allDirectory in appDelegate.directories)
{
NSDictionary *dica = [NSDictionary dictionaryWithObject:allDirectory.dirTitle forKey:#"dirTitle"];
NSDictionary *dico = [NSDictionary dictionaryWithObject:allDirectory.imageURL forKey:#"imageURL"];
[dirName addObject:dica];
[dirImage addObject:dico];
//NSLog(#"dic of items : %#",dirImage);
}
for (allDirectory in appDelegate.directories)
{
//retrieve the first letter from every directory title (dirTitle)
NSString * c = [allDirectory.dirTitle substringToIndex:3];
NSString * m = allDirectory.imageURL;
found = NO;
find = NO;
for (NSString *str in [self.sections allKeys])
{
if ([str isEqualToString:c])
{
found = YES;
}
}
for (NSString *stra in [self.sectionsImg allKeys])
{
if([stra isEqualToString:m])
{
find = YES;
}
}
if (!found)
{
[self.sections setValue:[[NSMutableArray alloc]init] forKey:c ];
[self.sectionsImg setValue:[[NSMutableArray alloc]init] forKey:m];
}
if (!find)
{
[self.sectionsImg setValue:[[NSMutableArray alloc]init] forKey:m];
}
}
for (NSDictionary *directory in dirName)
{
[[self.sections objectForKey:[[directory objectForKey:#"dirTitle"] substringToIndex:3]] addObject:directory];
//NSLog(#"hehehe have : %#",sections);
}
for (NSDictionary *directoryImg in dirImage)
{
//[[self.sectionsImg objectForKey:[[directoryImg objectForKey:#"imageURL"] substringFromIndex:0]] addObject:directoryImg];
[[self.sectionsImg objectForKey:[directoryImg objectForKey:#"imageURL"]] addObject:directoryImg];
//NSLog(#"HOHOHO have : %#",sectionsImg);
}
And on cellForRowAtIndexPath i declare a dictionary
NSDictionary *dictionary = [[self.sections valueForKey:[[[self.sections allKeys] sortedArrayUsingSelector:#selector(localizedCaseInsensitiveCompare:)] objectAtIndex:indexPath.section]] objectAtIndex:indexPath.row];
cell.textLabel.text = [dictionary objectForKey:#"dirTitle"];
but when i tried to declare a dictionary for imageURL
NSDictionary *dictionaryImg = [[self.sectionsImg valueForKey:[[[self.sectionsImg allKeys] sortedArrayUsingSelector:#selector(localizedCaseInsensitiveCompare:)] objectAtIndex:indexPath.section]] objectAtIndex:indexPath.row];
it gives me a error :
Terminating app due to uncaught exception 'NSRangeException', reason: '* -[NSMutableArray objectAtIndex:]: index 1 beyond bounds [0 .. 0]'
any idea why? the logic is supposed to be the same where xml title and url can be retrieve and be displayed. Title is retrievable but imageURL is not. Help is deeply appreciated !
You are trying to sort an array... except for the fact your array isn't an array, but a NSDictionary.
Your code isn't the best at the moment. Your getting the idea of Dictionaries wrong and may be confusing them with arrays, so my best guess is your quite new to programming into objective-c.
You have two lists of things, if I'm not mistaken. The first list is the list of names, and the second list is an image corresponding with that name.
Below I'm going to do two things:
Firstly, I'm giving you two ways on how to fix your problem. It has a sample code included and gives you a small explanation with it. The possibility exist you don't understand parts of what I describe. In that case, you should;
Check out the link I described below the two solutions. It has a tutorial which makes you understand everything about arrays, dictionaries, tables and, as a bonus, XML-parsing.
So, in my opinion, you can do two things:
The first one is using an array of NSDictionaries. You'd be using a code which looks like:
NSMutableDictionary *itemOne = [[NSMutableDictionary alloc] init];
NSMutableDictionary *itemTwo = [[NSMutableDictionary alloc] init];
NSMutableArray *listOfAll = [[NSmutableArray alloc] init];
NSString *itemOneName = [[NSString alloc] initWithFormat:#"This is picture 1"];
NSString *itemTwoName = [[NSString alloc] initWithFormat:#"This is picture 2"];
NSData *imageOneData = [[NSData alloc] initWithContentsOfURL: [NSURL URLWithString: #"http://myurl/mypic1.jpg"]];
NSData *imageTwoData = [[NSData alloc] initWithContentsOfURL: [NSURL URLWithString: #"http://myurl/mypic2.jpg"]];
UIImage *itemOneImage = [UIImage imageWithData: imageOneData];
UIImage *itemTwoImage = [UIImage imageWithData: imageTwoData];
[itemOne setObject:itemOneNameString forKey:#"Name"];
[itemOne setObject:itemOneImage forKey:#"Image"];
[itemTwo setObject:itemTwoNameString forKey:#"Name"];
[itemTwo setObject:itemTwoImage forKey:#"Image"];
[listOfAll addObject:itemOne];
[listOfAll addObject:itemTwo];
Anything can be filled using that array. Just use something with a for-loop to iterate through your array.
for (int i = 0; i < [listOfAll count]; i++)
{
NSMutableDictionary *currentItem = [[NSMutableDictionary alloc] initWithDictionary:[listOfAll objectAtIndex:i]];
//Do something with that current item
}
You can also use that index in your tableView. In that case, you have to use your variable section instead of i to get your desired index.
The second one is using two arrays. Imagine you get an image named imageOne with the text imageName. Then you should use:
NSMutableArray *nameList = [[NSMutableArray alloc] init];
[nameList addObject: imageName];
NSMutableArray *imageList = [[NSMutableArray alloc] init];
[imageList addObject: imageOne];
If you want to use a certain item out of those lists, you just have to use the same indexnumber.
For example:
[theTitleLabel setText:[[NSString alloc] initWithFormat:#"%#", [nameList objectAtIndex:x]]];
[theImageView setImage:[imageList objectAtIndex:x]];
Make sure the x's are the same number.
I understand this is all a lot of information, especially if you're new to Objective - C. A tutorial exists which gives you a lot of information about how to use arrays, dictionaries and table views. As a bonus, you get to know a little about XML-parsing.
I suggest you walk through that tutorial and do everything and read everything it says. This should give you a nice start into the world of programming in iPhones.
Good luck!
I'm in the making of an application where I'm using TouchXML to parse an XML containing airport flight information.
The XML looks like this:
<?xml version="1.0" encoding="iso-8859-1"?>
<airport xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://flydata.avinor.no/XmlFeed.xsd" name="OSL">
<flights lastUpdate="2010-10-03T12:29:43">
<flight uniqueID="1273306">
<airline>DY</airline>
<flight_id>DY246</flight_id>
<dom_int>D</dom_int>
<schedule_time>2010-10-03T10:45:00</schedule_time>
<arr_dep>D</arr_dep>
<airport>TOS</airport>
<check_in>D</check_in>
<gate>18</gate>
<status code="D" time="2010-10-03T10:42:00"/>
</flight>
<flight uniqueID="1273799">
<airline>SK</airline>
<flight_id>SK263</flight_id>
<dom_int>D</dom_int>
<schedule_time>2010-10-03T10:50:00</schedule_time>
<arr_dep>D</arr_dep>
<airport>BGO</airport>
<check_in>EF</check_in>
<gate>23</gate>
</flight>
</flights>
</airport>
The TouchXML documentation tells me how to fetch attributes, which works for flights's lastUpdate attribute, but not for status's code and time attribute.
In addition, not all flight XML entries contain the status element, but I'm doing a check for this.
Currently, the code I have is the following:
-(void)grabXML {
flightEntries = [[NSMutableArray alloc] init];
NSURL *url = [NSURL URLWithString:#"http://flydata.avinor.no/XmlFeed.asp?TimeFrom=0&TimeTo=2&airport=OSL&direction=D"];
CXMLDocument *xmlParser = [[[CXMLDocument alloc] initWithContentsOfURL:url options:0 error:nil] autorelease];
NSArray *resultNodes = NULL;
resultNodes = [xmlParser nodesForXPath:#"//flight" error:nil];
for (CXMLElement *resultElement in resultNodes) {
NSMutableDictionary *flightItem = [[NSMutableDictionary alloc] init];
int counter;
for (counter = 0; counter < [resultElement childCount]; counter++) {
[flightItem setObject:[[resultElement childAtIndex:counter] stringValue] forKey:[[resultElement childAtIndex:counter] name]];
// Check if the node has the <status> element
if ([[[resultElement childAtIndex:counter] name] isEqualToString:#"status"]) {
// Fetch the code and time attribute here
}
}
// This gives me <flight uniqueID="*">
[flightItem setObject:[[resultElement attributeForName:#"uniqueID"] stringValue] forKey:#"uniqueID"];
[flightEntries addObject:[flightItem copy]];
}
}
The documentation does not tell how to parse multiple attributes, so I was hoping someone had a clue on how to do it?
First off, I have to say that your XML will be difficult to work with because you are trying to use a specific tag for each item in a list. For example:
<airline>DY</airline>
<flight_id>DY246</flight_id>
<dom_int>D</dom_int>
<schedule_time>2010-10-03T10:45:00</schedule_time>
<arr_dep>D</arr_dep>
<airport>TOS</airport>
<check_in>D</check_in>
<gate>18</gate>
the tags named , don't make sense as XML is intended to describe your data, not define it. If you have an entity called an item, you should probably just call it item and make the XML look like this:
<level1_items>
<level1_item>
<item index="1">text</item_1>
<item index="2">text</item_2>
</level1_item>
<level1_item>
<item index="1">some text</item_1>
<item index="2">some more text</item_2>
</level1_items>
Where each item has an index. For that matter, you could just load the document in your TouchXML CXMLDocument and grab the nodes you need with XPath and assume they're in the correct order ignoring the index= parameter I specified.
The next issue is that converting XML to an NSDictioanry or NSArray of dictionaries is a pretty involved task and what you gain isn't worth the effort. Just load your XML into a CXMLDocument and then start obtaining nodes using XPath. Something like this:
CXMLDocument *doc = [[CXMLDocument alloc] initWithXMLString:xmlString options:0 error:nil];
// Returns all 'level1_item' nodes in an array
NSArray *nodes = [[doc rootElement] nodesForXPath:#"//response/level1_items/level1_item" error:nil];
for (CXMLNode *itemNode in nodes)
{
for (CXMLNode *childNode in [itemNode children])
{
NSString *nodeName = [childNode name]; // should contain item_1 in first iteration
NSString *nodeValue = [childNode stringValue]; // should contain 'text' in first iteration
// Do something with the node data.
}
}
suggest trying to use the XML this way and then come back here and ask specific questions if you have problems.
hope that helps.
PK