I am having a pretty big xml file (17 MB) on a webserver, which is constantly updated (once or twice a month). I take the XML and parse it to Core data, when the user triggers an update. Now I want to check during my Apps wake/start up if the locally parsed database is up to date or if there is a newer xml on the server.
The xml is created by a non-IT-company via MS Office, so I can't really expect them to do many changes to the xml. right now i only have the
<dataroot xmlns:od="urn:schemas-microsoft-com:officedata" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="someXML.xsd" generated="2012-06-28T12:53:12">
generated Attribute of dataroot.
Any tips on how to get the date the file was created in a fast and neat way?
I have am giving you the important code. I am taking a string variable in .h file and initializing the string in parse didstartelement method of parsing. Check the below code.
#interface TestViewController: UIViewController <NSXMLParserDelegate> {
NSString *generatedDate;
}
#end
#import "TestViewController.h"
#implementation TestViewController
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict {
if ( [elementName isEqualToString:#"dataroot"] ) {
generatedDate = [[NSString alloc]initWithFormat:#"%#",[[attributeDict objectForKey:#"generated"] retain]];
}
}
#end
Can you not just store and check the created or modified date on the server and compare it to a value you have stored? That way if it is the same you don't even need to bother to read the XML.
You could get a false positive (date changed but data hasn't), but you wouldn't get a false negative (data changed but date hasn't), so it would cut down a lot of processing.
Once you have decided it has changed you can either pass the XML to check for the date, of if it is in a specific place of the file (ie, the beginning), just read that much of the file and search for the string
you can get your generated time using NSXMPParser. use following
NSXMLParser *parser = [[NSXMLParser alloc] initWithData:yourXMLData];
[parser setDelegate:self];
[parser parse];
This will call your delegate methods. You need to handle following delegate method to get your date
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qualifiedName attributes:(NSDictionary *)attributeDict {
NSString *generatedDate = [attributeDict objectForKey:#"generated"];
}
Hope this helps
Related
I have table with data taken from NSDictionary. For example Each row of table contains Currency Name and rate which are linked using NSDictionary. Now i want to take rate value from XML file over the network.
I have made XML file and web server.
Is it possible?
How can i accomplish this.
Is it secure.
Thanks in advance
After you parse your xml file, use the reference to your dictionary and do the following:
Assuming the xml will have <Currency> conversionrate </currency> format. In your didendelement you can change the value of dictionary items as below:
- (void) parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
[dictionary setValue:parseditem forKey:elementName];
}
parsedItem can be got from the method :
- (void) parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
Here you have to take care that the element name has to be unique. You can also use attributes to do the same and add a if condition before adding it to the dictionary.
I am quite new to iphone development. I was going through tutorials on XML parsing for which NSXMLParser is used. Are there other parsers we can use for parsing XML. How do we decide which parser to use?
Regards,
Stone
Standard parsers are NSXMLParser or c-based libxml. But there is plenty of 3rd party parsers available. Check this blog post where some of the most popular parsers reviewed and compared.
- (void)connectionDidFinishLoading:(NSURLConnection *)theConnection
{
[self parseXMLFile:xmlFile];
unsigned char byteBuffer[[xmlFile length]];
[xmlFile getBytes:byteBuffer];
NSLog(#"Output: %s", (char *)byteBuffer);
NSLog(#"Succeeded! Received %d bytes of data",[xmlFile length]);
[xmlFile release];
xmlFile = [[NSMutableData data] retain];
}
- (void)parseXMLFile:(NSData *)adatok {
if (adatok != nil) {
BOOL success;
if (addressParser)
[addressParser release];
addressParser = [[NSXMLParser alloc] initWithData:adatok];
[addressParser setDelegate:self];
[addressParser setShouldResolveExternalEntities:YES];
success = [addressParser parse];
}
}
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict { here You enter the node }
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string { here you get the content CDDATA}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName { here you end node }
hope it helps
This is a sample code from Apple.. It shows the difference between All XML parsers available..
http://developer.apple.com/library/ios/#samplecode/XMLPerformance/Introduction/Intro.html
For a newbie it will be real helpfull..Feel free to use it..
I find many tutorial and many post on this problem.
There are many tutorial that don't works!!!!!
I found this
http://gigaom.com/apple/tutorial-build-a-simple-rss-reader-for-iphone/
and i undstend how NSXMLparser work
Personally if you're using XML and have access to the feed I would always convert the feed into plist format. This is a much better format to use with the iPhone and will save you huge amounts of time and effort.
There is also https://github.com/robbiehanson/KissXML which gives you a similar makeup to the missing NSXML classes. Its done in a way that means that if apple ever do put those classes into the iOS sdk it won't conflict at all.
If you're going to use HTML, hpple is worth trying. It's very easy to use and is going to support full XML soon.
Check this link for parse xml parse
NSString *url=#"http://www.lancers.jp/work/search/.rss";
NSData *data=[NSData dataWithContentsOfURL:[NSURL URLWithString:url]];
NSDictionary *dict=[XMLReader dictionaryForXMLData:data error:nil];
Click on this link
Demo code of XML
I'm currently parsing an xml file that has a string like this between two elements:
Hello & bye
When the foundCharacters delegate gets called it parses the information like this....
it parses:
Hello
&
bye
It makes 3 calls to parse that element and I end up with 3 strings as opposed to 1 string. Is there some way to detect this with out having to append a string together and keep a counter of how many times the delegate was called?
Any help is very appreciated...
Short answer : No. It's only chance that it's returning three strings, it might return 11 strings all one character long if it wanted to. It's up to you to join the strings together.
Long answer : You need to append a string. There's nothing you can do about it. however, I don't understand why you need to keep a count of the number of times the delegate has been called - I think that this code should do what you want :
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qualifiedName attributes:(NSDictionary *)attributeDict {
// Make a new string to hold the data
[currentString release];
currentString = [NSMutableString alloc] init];
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
// Add the string to our current string
[currentString appendString:string];
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {
// In here, current string should be it's entire contents,
NSLog(#"%#", currentString);
}
You will need a member in your class to hold the data - a mutable string is easiest one:
#interface MyClass : NSObject {
NSMutableString *currentString;
}
#end
(It doesn't need to be a property but you do need to remember to release it in your dealloc method)
I am currently working on a software to control aMule status of my server through the iPhone,
i created a socket that spits out xml which should be parsed out, but because NSXMLParser is event-drive, i'm having problems in understanding how this could work...
I thought of this type of XML structure, if you have ideas of a better way to structure it please tell me!! :D
<root type="donwloads"> <-- specifies downloads or search results
<file name="Ubuntu_9_10.iso" status="[11,6%]" />
<file name="Fedora 12.iso" status="[56,2%]" />
</root>
What i was thinking is, as i want to put this in a tableview, most probably i will need a NSMutableArray with lots of NSDictionaries based on the results, every dict should be a file.. what do you guys propose?? how should i handle this situation?
Thanks
Write a parser class that turns nodes into Core Data managed objects and saves them to the managed object context, when a parser callback event is fired.
Use an NSFetchedResultsController to access the Core Data store. As the managed objects come in and are saved, the results controller updates the table view with whatever results it fetches.
An NSMutableArray of NSDictionary seems like a reasonable approach for your in-memory data structure.
You'll basically have a series of callbacks that build up that array as NSXMLParser runs through your XML file:
- (void) parseXML:(NSString *) filename {
NSURL *xmlURL = [NSURL fileURLWithPath:filename];
NSXMLParser *xmlParser = [[NSXMLParser alloc] initWithContentsOfURL:xmlURL];
[xmlParser setDelegate:self];
[xmlParser parse];
// Check for errors.
NSError *errorCode = [xmlParser parserError];
if (errorCode) {
// handle error here
NSLog(#"%#", [errorCode localizedDescription]);
}
[xmlParser release];
}
And your main delegate:
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)qualifiedName attributes:(NSDictionary *)attributeDict
{
// If certain elements are found initialize the object
if ([elementName isEqualToString:"#file"]) {
NSMutableDictionary *currentFile = [[NSMutableDictionary alloc] init];
// Look through the attributes add stuff to your dictionary
// Add it to your array.
}
}
Since all of your data is returned in attributes you can do it this way. Otherwise you'd need to store the file and build it up (the foundCharacters delegate) finally adding it to your array when the file's tag occurs in the didEndElement delegate.
Thanks a lot for your answers :D fortunately i resolved the problem 10 minutes after :D
ill post what i did:
XML:
<root>
<downloads>
<file type="text" name="fdsdf" />
<file type="text" name="sdfsdfssds" />
</downloads>
</root>
NSXMLParser delegates:
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qualifiedName attributes:(NSDictionary *)attributeDict{
if([elementName isEqualToString:#"downloads"] || [elementName isEqualToString:#"results"]){
NSLog(#"starting or downloads or results");
if(xmlArray){
xmlArray= nil;
}
self.xmlArray= [[NSMutableArray alloc] init];
}
else if([elementName isEqualToString:#"file"]){
NSLog(#"found file...");
[self.xmlArray addObject:attributeDict];
}
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName{
if([elementName isEqualToString:#"downloads"] || [elementName isEqualToString:#"results"]){
if([elementName isEqualToString:#"downloads"]){
NSLog(#"downloads found: %#... reloading table", xmlArray);
}
}
}
I hope this can possibly help someone which has my same problem :D
In my iPhone application, I have the following NSString:
NSString *myxml=#"<students>
<student><name>Raju</name><age>25</age><address>abcd</address>
</student></students>";
How would I parse the XML content of this string?
Download:
https://github.com/bcaccinolo/XML-to-NSDictionary
Then you simply do :
NSDictionary *dic = [XMLReader dictionaryForXMLString:myxml error:nil];
Result is a NSDictionary *dic with dictionaries, arrays and strings inside, depending of the XML:
{
students = {
student = {
address = abcd;
age = 25;
name = Raju;
};
};
}
You should use the NSXMLParser class
Here's a link to the documentation for that class:
http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSXMLParser_Class/Reference/Reference.html
Your code should look something like this:
#implementation MyClass
- (void)startParsing {
NSData *xmlData = (Get XML as NSData)
NSXMLParser *parser = [[[NSXMLParser alloc] initWithData:xmlData] autorelease];
[parser setDelegate:self];
[parser parse];
}
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qualifiedName attributes:(NSDictionary *)attributeDict {
NSLog(#"Started %#", elementName);
}
Another answer is: Don't use XML. Use a plist instead, which is written using XML but more easily parsable in Objective-C into distinct data types (NSArray for example has a method to convert a file or NSData plist into an NSArray).
Like #Jon Hess mentioned, just create a wrapping class for the "optional" methods of the NSXMLParserDelegate. These methods help you separate the tasks that you might find useful when you parse your xml.
One really good online journal file I found is Elegant XML parsing with Objective-C. Phil Nash really took his time to show the basics of the parsing options at your reach. It can take a new programmer and guide him/her through the whole setup.
Loading the xml can be a modification of #Jon Hess method.
You can setup the:
-(void)parser:(NSXMLParser *)parser
didStartElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI
qualifiedName:(NSString *)qName
attributes:(NSDictionary *)attributeDict{
}
to handle events on certain elements.
Also implement the:
-(void)parser:(NSXMLParser *)parser
foundCharacters:(NSString *)string {
}
to place the strings found into a collection of objects.
I think the best equivalent to XMLDocument is AbacigilXQ Library. You should look at it. I'm using it.
http://code.google.com/p/abacigilxq-library/