Cocoa/Obj-C simple XML file reader - need help - objective-c

I asked a question yesterday about a little app that I would like to make for OSX with Cocoa/Obj-C (Xcode).
The princip is easy:
Got an XML file like this one:
<?xml version="1.0" ?>
<Report>
<Date>20110311</Date>
<Title>The Title</Title>
<Description>Description sample<Description>
</Report>
When the app is opened, there is a window with three text fields.
When a file is loaded (File -> Open) the three text fields get the value of what is in the XML elements. For my example it will be:
TextFields 1 => 20110311TextFields 2 => The TitleTextFields 3 => Description sample
And that's it!
As you can see in my description, it's maybe easy...
But I tried a lot of things, I didn't successed :/
I'm a newbie in Cocoa developpment and there's a lot of dedicated things that I don't understand like how can I make links between CODE & GUI...
Now here is my demand:
If someone could make me an Xcode project similar to my example above, for see what's wrong with my different trys, or explain me how this app can be done (with codes examples)...
I've spend 4 long days on that project but didn't have results :(
Help... :(
Miskia

Two little things to consider:
You should definitely read into the Objective-C / Cocoa documentation.
Otherwise you will never be able to program something yourself.
In the end this will save you lots of time struggling with problems like these.
The things you ask are just the very basics of programming.
(Besides the XML part)
You should never ask people to write complete applications.
People on Stack Overflow are more then willing to help with specific problems,
but they do not work for you.
That being said, here my actual answer:
The XML code you provided contains a syntax error:
The second <Description> should be </Description>
For my example code below I used the following XML file:
<?xml version="1.0" ?>
<Report>
<Date>20110311</Date>
<Title>The Title</Title>
<Description>Description sample</Description>
</Report>
This quickly written example does everything you need.
Create a new application with XCode and open the .....AppDelegate.m file.
Simply paste the Objective-C code mentioned below within the following function:
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
// Paste Here
}
Next click 'Click build and Run'.
Select your file within the NSOpenPanel and click the open-button.
Now you should see a simple dialog with the results.
Hopefully this helps you understand how to parse the XML file.
I can imagine 4 days of struggling must be unpleasant :)
The Objective-C sample code:
NSOpenPanel *openPanel = [NSOpenPanel openPanel];
NSArray *fileTypes = [NSArray arrayWithObjects:#"xml",nil];
NSInteger result = [openPanel runModalForDirectory:NSHomeDirectory() file:nil types:fileTypes ];
if(result == NSOKButton){
NSString * input = [openPanel filename];
NSXMLDocument* doc = [[NSXMLDocument alloc] initWithContentsOfURL: [NSURL fileURLWithPath:input] options:0 error:NULL];
NSMutableArray* dates = [[NSMutableArray alloc] initWithCapacity:10];
NSMutableArray* titles = [[NSMutableArray alloc] initWithCapacity:10];
NSMutableArray* descriptions = [[NSMutableArray alloc] initWithCapacity:10];
NSXMLElement* root = [doc rootElement];
NSArray* dateArray = [root nodesForXPath:#"//Date" error:nil];
for(NSXMLElement* xmlElement in dateArray)
[dates addObject:[xmlElement stringValue]];
NSArray* titleArray = [root nodesForXPath:#"//Title" error:nil];
for(NSXMLElement* xmlElement in titleArray)
[titles addObject:[xmlElement stringValue]];
NSArray* descriptionArray = [root nodesForXPath:#"//Description" error:nil];
for(NSXMLElement* xmlElement in descriptionArray)
[descriptions addObject:[xmlElement stringValue]];
NSString * date = [dates objectAtIndex:0];
NSString * title = [titles objectAtIndex:0];
NSString * description = [descriptions objectAtIndex:0];
NSString *output = [NSString stringWithFormat:#"Date: %#\nTitle: %#\nDescription: %#", date, title, description];
NSRunAlertPanel( #"Result", output, #"OK", nil, nil );
[doc release];
[dates release];
[titles release];
[descriptions release];
}
Here some additional information:
http://developer.apple.com/library/ios/#documentation/Cocoa/Conceptual/XMLParsing/Articles/UsingParser.html

Sample project:
http://dd5.org/static/XML.zip
How to create a project like above:
- Create new project
- Add code to the header (.h) and implementation (.m) files
- Design the main window
- Finally add the correct bindings
See images below how to add the bindings (already done in the sample project).
Right-click on the App Delegate drag to the NSTextFied (Picture 1).
Release the button and select the correct entry in the ray menu (Picture 2).

Feel free to look at two easy XML parser classes I created.
http://www.memention.com/blog/2009/10/31/The-XML-Runner.html
Source with projects are available at github
https://github.com/epatel/EPXMLParsers

Related

iCloud NSMetadata query results are blank

I've been working on adding icloud to my project (which is quite a pain in the buns) and I'm able to save and remove files, but I can't get a list of the files stored in iCloud. I've tried solutions from about 10 different websites (including the Apple documentation). Whenever I call [self.query startQuery]; everything seems to be working: The correct methods get called, the methods execute exactly as they should. Then when I ask for an nsarray of the files in my app's iCloud Documents directory I get two parenthesis with nothing between them (when I view in NSLog): File List: ( ). I know for a fact that there are many different documents of all shapes, extensions, sizes, and names in my app's iCloud Documents directory because I've been using the iCloud Developer site to check if things are working. My first method to setup the query is as follows:
- (void)syncWithCloud {
self.query = [[NSMetadataQuery alloc] init];
NSURL *mobileDocumentsDirectoryURL = [[NSFileManager defaultManager] URLForUbiquityContainerIdentifier:nil];
[query setSearchScopes:[NSArray arrayWithObjects:NSMetadataQueryUbiquitousDocumentsScope, nil]];
//[query setPredicate:[NSPredicate predicateWithFormat:#"%K LIKE '*'", NSMetadataItemFSNameKey]];
[query setPredicate:[NSPredicate predicateWithFormat:[NSString stringWithFormat:#"%%K like \"%#*\"", [mobileDocumentsDirectoryURL path]], NSMetadataItemPathKey]];
//Pull a list of all the Documents in The Cloud
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(processFiles:)
name:NSMetadataQueryDidFinishGatheringNotification object:self.query];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(processFiles:)
name:NSMetadataQueryDidUpdateNotification object:self.query];
[self.query startQuery];
}
The process files method provided by Apple is next:
- (void)processFiles:(NSNotification*)aNotification {
NSMutableArray *discoveredFiles = [NSMutableArray array];
//Always disable updates while processing results.
[query disableUpdates];
//The query reports all files found, every time.
NSArray *queryResults = [query results];
for (NSMetadataItem *result in queryResults) {
NSURL *fileURL = [result valueForAttribute:NSMetadataItemURLKey];
NSNumber *aBool = nil;
// Don't include hidden files.
[fileURL getResourceValue:&aBool forKey:NSURLIsHiddenKey error:nil];
if (aBool && ![aBool boolValue])
[discoveredFiles addObject:fileURL];
}
//Update the list of documents.
[FileList removeAllObjects];
[FileList addObjectsFromArray:discoveredFiles];
//[self.tableView reloadData];
//Reenable query updates.
[query enableUpdates];
NSLog(#"File List: %#", FileList);
}
Why doesn't this give me a list of files or at least some kind of data? Am I defining the NSMetadata query wrong, maybe my predicate isn't formatted right? I know I'm doing something wrong because there's no way iCloud could be this complicated (or could it?).
Thanks for the help in advance!
Edit #1: I am continuing to try different approaches to this problem. Using one of the answers below I have changed the predicate filter as follows:
[query setPredicate:[NSPredicate predicateWithFormat:#"NSMetadataItemFSNameKey LIKE '*'"]];
I have also added the following lines before the [query enableUpdates] call:
for (NSMetadataItem *item in query.results) {
[FileList addObject:[item valueForAttribute:NSMetadataItemFSNameKey]];
}
In the processFiles method, I've tried placing all of the code on the background thread, but this makes no difference - as a matter of fact, when the code is not executed on the background thread FileList gives me this (null) instead of this ( ).
Could my problem have to do with thread management or memory allocation? Please note that I am using ARC.
Edit #2: The FileList variable is an NSMutableArray defined in my #interface and initialized in the -(id)init method before calling the processFiles method.
Edit #3: When testing my code with breakpoints I found that the following for-loop never gets run through - not even once. This leads me to believe that:
A. The proper directory isn't being connected with
B. iCloud can't see the files in the directory
C. My NSMetadataQuery isn't being setup properly
D. Something completely different
Here's the code that starts the for-loop which never gets run:
NSArray *queryResults = [query results];
for (NSMetadataItem *result in queryResults) {
Since you already set the search scope correct, there's no need to use special filters in the predicate.
Just use:
query.predicate = [NSPredicate predicateWithFormat:#"NSMetadataItemFSNameKey == '*'"];
And to get the array use:
NSMutableArray *array = [NSMutableArray array];
for (NSMetadataItem *item in query.results) {
[array addObject:[item valueForAttribute:NSMetadataItemFSNameKey]];
}
I've solved my problem. Getting the list of files in iCloud was just a matter of correctly defining, allocating, and initializing properties. SAE's answer and this SO posting helped me solve my problem and create this GitHub Repo called iCloud Document Sync. The iCloud Document Sync class simplifies the whole iCloud Document storage process down to a few lines of code. The commit linked here fixes the issues from my question.

Retrieving a specific data

I am new to xcode.. and I would love to learn about retrieving data from XML.. This is a draft code that I have been stucked with for days.. I manage to display a list of XML codes
XML CODE:
<find>
<set_number>038881</set_number>
<no_records>000138874</no_records>
<no_entries>000007000</no_entries>
</find>
However, now I have some difficulties in retrieving only the set_number from this xml... The URL I have left it blank due to confidential purposes.. so dont mind about it.. The last two codes has resulted my app to force close.. Help!!
NSString *URL = [NSString stringWithFormat:#""];
NSMutableData *receivedData = [[[NSMutableData alloc] initWithContentsOfURL:[NSURL URLWithString:URL] ]autorelease];
NSString *theRecord = [[[NSString alloc] initWithData:receivedData encoding:NSUTF8StringEncoding] autorelease];
NSString *path = [theRecord valueForKey: #"set_number"];
NSLog(#"File Data: %#", path);
I tried to add in this code at the bottom instead..
if ([theRecord isEqualToString:#"no_records"]){
NSLog(#"Contents of URL: %#", theRecord);
}
Then I also trying to debug my codes.. No error shown.. instead they display 0 for the output.. and I am wondering is it because my no_records is an integer?? But I have assign the record as a string.. is that why they couldnt display?
I tried to add in this code at the bottom instead..
`if ([theRecord isEqualToString:#"no_records"]){
NSLog(#"Contents of URL: %#", theRecord);
}`
Then I also trying to debug my codes.. No error shown.. instead they display 0 for the output.. and I am wondering is it because my no_records is an integer?? But I have assign the record as a string.. is that why they couldnt display?? Please help!!
To parse your XML use the NSXMLParser class.
NSString *path = [theRecord valueForKey: #"set_number"];
theRecord is a NSString instance that can not use valueForKey.
You should parse your xml string first and get the content you want from tag.
Or you should get substring in your string.

How to get data (select's lines) from web service to xcode?

I want to get all the results of a sql table's call (select *) in php, to send them to the iphone's app and use them there.
What steps would you recommend me?
I am a complete noob in xcode and php. I have some tests like this one:
NSString *miURL = [NSString stringWithFormat:#"http://hello.com/test.php];
NSString *myRawJson = [[NSString alloc] initWithContentsOfURL:[NSURL URLWithString:miURL]];
SBJsonParser *parser = [[SBJsonParser alloc] init];
NSArray *list = [NSArray alloc];
lista = [[parser objectWithString:myRawJson error:nil] copy];
And in the .php:
<?php
$conectID = mssql_connect("SERVIDOR\SQLEXPRESS","**","**");
mssql_select_db("Animals");
$result=mssql_query("select * from dbo.animals where name='jack'");
$row=mssql_fetch_array($result);
if ($row){
$myArray = array($row["name"], $row["type"], $row["colour"], $row["age"], $row["address"]);
echo json_encode($myArray);
}
All of this is good and quick for a simple line.. but for a lot of lines from a sql's select would be very inefficient, doesn't it?
Because I would like to execute for example: "select * from dbo.animals" and save each field of the table in its counterpart xcode's object's field. In xcode I would have a list of this:
#interface DataPerfil : NSObject {
NSString *name;
NSString *type;
NSString *colour;
NSInteger *age;
NSString *address;
}
....
I hope I have explained it well..
Sorry my bad english and thanks.
If you're talking real web service as in soap here is a tutorial I used :
http://www.devx.com/wireless/Article/43209/0/page/1
It's more complex than your example but the web service layer adds security and hides the access to data.

How to save apps data Xcode

I have been searching for many days on how to save my apps data. I found some stuff but it was very complicated and badly explained. I need that when I completely close my apps all the data I entered in the text field are still there when I open my apps again. I tried a tutorial but this only let me save about 8 textfields and I need to save thousands I am starting Objective-C and Xcode so if somebody want to give me an answer please make it very precise.
Alright, what I'd suggest would be putting all the data from your text fields into an array and saving that to a file, then loading it when you re-open the app.
The first thing you need is a save file. This function will create one for you.
-(NSString*) saveFilePath{
NSString* path = [NSString stringWithFormat:#"%#%#",
[[NSBundle mainBundle] resourcePath],
#"myfilename.plist"];
return path;}
Now that that's done you need to create your saving array. Hopefully you have your thousands of textfields already fitted into an array of some sort. If not, this will be a painful process regardless of how you tackle it. But anyway... (Here, labelArray will be the array of all your text fields/labels/etc.)
NSMutableArray* myArray = [[NSMutableArray alloc]init];
int i = 0;
while(i < labelArray.count){
[myArray addObject: [labelArray objectAtIndex: i].text];
i ++;
}
[myArray writeToFile:[self saveFilePath] atomically:YES];
[myArray release];
And the loading code would be something along the lines of
NSMutableArray* myArray = [[NSMutableArray arrayWithContentsOfFile:[self saveFilePath]]retain];
Then you'd simply load the data back into your array of text fields.
Hope this helps.
It sounds like your application architecture may be unsound if you are planning on saving thousands of text fields' data in the fraction of a second you get while your app is closing. It would probably be better to save these as the user enters the data instead of waiting to save all the data at once.
To get the path you are going to write ( or read from! ) to, you do the following:
NSString *writableDBPath = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0] stringByAppendingPathComponent:#"MyFile.extension"];
And then use a method like "writeToFile:automically:" of NSString or NSDictionary etc. to write to the path.

How do i grab numbers from a Table on a website in my Cocoa App?

Ok this is a more specific version of my last question.
So on a website there exists some data that is coded in HTML into a table.
In my Cocoa app, I want to download the html code of the website and then read through the html and snag the data from it. I was hoping someone could point out some useful classes/methods for accomplishing the retrieval of the website and putting it into some format where I can read through the code in my program?
Thanks in advance!
Try using hpple, it's an HTML parser for ObjC.
here's an example using it:
#import "TFHpple.h"
NSData *data = [[NSData alloc] initWithContentsOfFile:#"example.html"];
// Create parser
xpathParser = [[TFHpple alloc] initWithHTMLData:data];
//Get all the cells of the 2nd row of the 3rd table
NSArray *elements = [xpathParser search:#"//table[3]/tr[2]/td"];
// Access the first cell
TFHppleElement *element = [elements objectAtIndex:0];
// Get the text within the cell tag
NSString *content = [element content];
[xpathParser release];
[data release];