In my
- (void)parser:(NSXMLParser *)parser
didStartElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI
qualifiedName:(NSString *)qualifiedName
attributes:(NSDictionary *)attributeDict {
// ...
}
I check to see if one of my XML attributes is equal to a value I store in my plist. If it's not then I want it to execute normally and get the latest information. If it is the same value though I don't want to waste the processing time of getting all the data again. So if I have code like below how can I terminate the parsing process if the values are the same?
if (lastUpdated == [attributeDict valueForKey:#"last_updated"]) {
// Terminate the xml parsing because data is up to date
}
You can use [parser abortParsing] but note that this is intended for XML errors rather than "I don't want this data" situations and can cause your parser:parseErrorOcurred: method to be called a couple of times, in my experience.
Call [parser abortParsing] to cancel parsing from current point.
Just note that there is a bug in iOS 6.0 and abortParsing will cancel the parser but will not call parser:parseErrorOccurred and will not set 'parserError'.
Related
I have searched the internet for several days, but I cannot find a consise answer. I want to make a simple practice weather app that shows the temperature for a hardcoded zip code.
Here is the XML
<data>
<request>
<type>Zipcode</type>
<query>08003</query>
</request>
<current_condition>
<observation_time>08:29 PM</observation_time>
<temp_C>11</temp_C>
<temp_F>52</temp_F>
<weatherCode>143</weatherCode>
<weatherIconUrl>
<![CDATA[
http://www.worldweatheronline.com/images/wsymbols01_png_64/wsymbol_0006_mist.png
]]>
</weatherIconUrl>
<weatherDesc>
<![CDATA[ Mist ]]>
</weatherDesc>
<windspeedMiles>4</windspeedMiles>
<windspeedKmph>7</windspeedKmph>
<winddirDegree>210</winddirDegree>
<winddir16Point>SSW</winddir16Point>
<precipMM>0.0</precipMM>
<humidity>87</humidity>
<visibility>5</visibility>
<pressure>1013</pressure>
<cloudcover>100</cloudcover>
</current_condition>
<weather>
<date>2012-12-08</date>
<tempMaxC>13</tempMaxC>
<tempMaxF>55</tempMaxF>
<tempMinC>9</tempMinC>
<tempMinF>48</tempMinF>
<windspeedMiles>6</windspeedMiles>
<windspeedKmph>9</windspeedKmph>
<winddirection>W</winddirection>
<winddir16Point>W</winddir16Point>
<winddirDegree>260</winddirDegree>
<weatherCode>122</weatherCode>
<weatherIconUrl>
<![CDATA[
http://www.worldweatheronline.com/images/wsymbols01_png_64/wsymbol_0004_black_low_cloud.png
]]>
</weatherIconUrl>
<weatherDesc>
<![CDATA[ Overcast ]]>
</weatherDesc>
<precipMM>3.1</precipMM>
</weather>
</data>
ALL I want to do is to extract the *temp_F* and store it in a NSString.
If all you want is a single value for a single element that only appears once in the XML then I would do some simple string search instead of bothering with a full blown XML parser.
Get the range of the substring #"<temp_F>" and the substring #"</temp_F>" and grab the value in between.
Since you already mentioned using NSXMLParser, just go with that. Set your delegate to implement the protocol
#interface MyClass : NSObject <NSXMLParserDelegate>
Watch for the opening tag of your xml entry (looks to be in this case) with something like
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qualifiedName attributes:(NSDictionary *)attributeDict {
if ( [elementName isEqualToString:#"temp_F"] ) {
// Set flag and reset string
self.foundTargetElement = true;
if ( self.myMutableString ) {
self.myMutableString = nil;
self.myMutableString = [[NSMutableString alloc] init];
}
}
}
Next implement
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
if ( self.foundTargetElement ) {
[self.myMutableString appendString:string];
}
}
and using the same pattern as above, watch for your tag, () and append its value to your string, or do whatever else you want with the data:
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {
self.foundTargetElement = false;
// Do something with your result, or
// Wait until entire document has been parsed.
}
Let me know if that works out for you.
how to parse 2 URL's using NSXMLParser in the same file? I have tried it like this:
[self parseXMLFileAtURL:url1];
[self parseXMLFileAtURL:url2];
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict{
//here both url's returns the same data (element names are same), so how will I differentiate data between first URL & second URL.
if(url1 data) {
//do something
}
if(url2 data) {
//do something
}
}
so help me to find a way to differentiate.
I wouldn't. It's unnecessary. I would have 2 separate NSXMLParserDelegate handling each one. Or i would modify your current class to handle one file at a time, and have 2 instances of it.
You could create a separate delegate class within that class if that's what you like.
eg:
#implementation YourCurrentClass
#end
#interface ParserDelegate : NSObject <NSXMLParserDelegate>
#end
#implementation ParserDelegate
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI: (NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict{
}
#end
Use multiple ParserDelegate instances to be the delegates of the parsing. Then have some other code that checks them for the result after they are finished processing.
I'm not sure but you can firstly add your URL objects to an array and later control by the elements of array instead of URL1 & URL2. You can try this:
NSString *obj;
NSMutableArray *urlArray;
[urlArray addObject:url1];
[urlArray addObject:url2];
in your parser method:
int i=[[urlArray objectAtIndex:obj] intValue];
switch(i){
case 0:
// we have url1 here
//do something with it
break;
case 1:
// we have url2 here
//do something...
break
}
i hope this point of view helps..
The first parameter called parser is the current parser instance used.
This is the way to know which file you are currently parsing.
Alloc/init two separate instances of NSXMLParser, and start parsing your two files with.
Assuming they are ivar a simple == test would tell you which one is used.
Here is a link to similar question.
Create 2 separate objects of NSXMLParser and assign tags and in delegate function check there tag and assign value according to tags.
See the XML below
http://sosmoths.com/.xml/moths.xml
This XML having multiple images name, I have to show the different title(There are four title) in their respective Controller.
I have 4 controller, and have to show each moth value in different Controller, along with their multiple images values, how can I do it?
I can make single object of should I make four objects?
I am a bit confused in it, please help me.
This XML having multiple images name, I have to show the different
title(There are four title) in their respective Controller. I have 4
controller, and have to show each moth value in different Controller,
along with their multiple images values, how can I do it?
This sounds less like an XML parsing problem and more like an app architecture problem.
That XML basically describes some data and said data would typically be represented by objects in your application. You could go with a CoreData based solution whereby you parse the XML into a local CoreData store (in memory or on disk, matters not) and then display the managed objects as per usual.
Or, assuming that is representative of a typical set of data, you could parse it into your own hand rolled objects (or, even, dictionaries and arrays), then display from there.
There are dozens of questions about parsing XML on SO (and via Google).
The second part of your question hasn't been addressed. Basically, you need to properly layer your app into the model-view-controller pattern. Your model layer would parse the XML and create an object graph that represents the data. Each controller would have a reference to that single model.
This will work fine as long as your app is read only. If the various controllers are expected to also edit the object graph, then it'll need to be a bit more complex in that you'll have to deal with change propagation (this is where CoreData shines; it makes change management, propagation, validation, and undo relatively straightforward).
With TBXML you can easily parse the xml and it will convert it into objects to use:
http://www.tbxml.co.uk/TBXML/TBXML_Free.html
and libxml2 is also that you can use easily to parse.
try this it worked properly
-(void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qualifiedName attributes:(NSDictionary *)attributeDict{
NSLog(#"%#",elementName);
if([elementName isEqualToString:#"moths"]){
mytblarray=[[NSMutableArray alloc] init];
} else if([elementName isEqualToString:#"moth"]){
tmpdic=[[NSMutableDictionary alloc] init];
}
else if([elementName isEqualToString:#"images"]){
imgArray=[[NSMutableArray alloc] init];
}
}
-(void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string{
if(tmpstr!=nil && [tmpstr retainCount]>0){ [tmpstr release]; tmpstr=nil; }
tmpstr=[[NSString alloc] initWithString:string];
}
-(void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName{
if([elementName isEqualToString:#"moth"]){
[mytblarray addObject:tmpdic];
[tmpdic release];
}if([elementName isEqualToString:#"images"]){
[tmpdic setValue:imgArray forKey:elementName];
}
else if([elementName isEqualToString:#"image"]){
[imgArray addObject:tmpstr];
}
else if([elementName isEqualToString:#"id"] || [elementName isEqualToString:#"title"]||[elementName isEqualToString:#"description"]){
[tmpdic setValue:tmpstr forKey:elementName];
}
}
-(void)parserDidEndDocument:(NSXMLParser *)parser{
NSLog(#"%#",[imgArray description]);
NSLog(#"%#",[mytblarray description]);
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
//get value like it
NSString *cellValue = [[mytblarray objectAtIndex:indexPath.row] valueForKey:#"id"];
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
//get value like it
NSMutableDictionary *dict=[[NSMutableDictionary alloc]initWithDictionary:
[mytblarray objectAtIndex:indexPath.row]];
}
I have a element that is repeating and i need to read it's attributes and send them to the delegate
the xml is:
<special>
<day date="22/04/2011" name="Easter Friday">Closed</day>
<day date="23/04/2011" name="Easter Saturday">10:00-16:00</day>
<day date="24/04/2011" name="Easter Sunday">Closed</day>
<day date="25/04/2011" name="Anzac Day">13:00-17:00</day>
<day date="26/04/2011" name="Easter Tuesday">09:00-18:00</day>
</special>
i only get to past the last attributes for date and name to the delegate and i know why is this happening but i dont know how to fix it. can someone help me
here is my objective C code
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qualifiedName
attributes:(NSDictionary *)attributeDict {
if ([elementName isEqualToString:#"special"]) {
storeAppDelegate.openingHoursSpecialDelegate = [[NSMutableArray alloc] init];
}else if ([elementName isEqualToString:#"day"]) {
openingHoursView = [[OpeningHoursView alloc] init];
openingHoursView.name = [attributeDict objectForKey:#"name"];
openingHoursView.date = [attributeDict valueForKey:#"date"];
}
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {
if ([elementName isEqualToString:#"special"])
return;
if ([elementName isEqualToString:#"day"]){
[storeAppDelegate.openingHoursSpecialDelegate addObject:openingHoursView];
[openingHoursView release];
openingHoursView = nil;
}
}
openingHoursSpecialDelegate is a mutable array in the app delegate and OpeningHoursView is a NSObject that has name and date as strings in it in another class. They also get the value of the app delegate and it is also only the last read value for "date" and "name" attributes from the XML file .
I'm working with NSXML parser
so again my question is how to get "openingHoursView.name" and "openingHoursView.date" to write every value they get to openingHoursSpecialDelegate and not overwrite them as it happens now
I can't find anything wrong with the code. I've put the above code into a small test project (with minor changes to make it run standalone), and it runs fine for me.
Array (
"Easter Friday, 22/04/2011",
"Easter Saturday, 23/04/2011",
"Easter Sunday, 24/04/2011",
"Anzac Day, 25/04/2011",
"Easter Tuesday, 26/04/2011" )
Example project
You'll need to change the path I've hardcoded in the class test2AppDelegate, to point to a file containing the XML you posted above.
Already i have workout this problem in my project.But i am using libxml2.
The problem is (day node) you have to set the 5 different value to same key (day) thats why you get last attribute .
I display List of date's on my table view....
based on the date's.. i need to search location. and title
"with the help of url".
example
String *url=#"http://compliantbox.com/party_temperature/djsearch.php?date=?"
for the selected date.
i appended the date value to the string url.
So i need to parse again same xml parser. with date search.
<root>
<event title="event_title"location="new york"date="12/01/2011"/>
<event title="event_title2"location="california"date="13/01/2011"/>
<event title="event_title3"location="new york"date="14/01/2011"/>
</root>
here my array get's Re-Initialization.
so i get conflict. when displaying data....
I need to not re-Initialization my array again. and again...
I need to initialize my array only once in entire application.
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qualifiedName
attributes:(NSDictionary *)attributeDict{
if ([elementName isEqualToString:#"root"]){
dateListArray=[[NSMutableArray alloc] init];
}
}
I Hope you people understand my problem.
Please help me out .
#Thanks to All.
One way that you should trying here,
if([dateListArray count] > 0)
{
[dateListArray removeAllObjects];
[dateListArray release];
}
dateListArray=[[NSMutableArray alloc] init];
And other way you should also be trying,
dateListArray=[[NSMutableArray alloc] init];
above statement write down in -(void)viewDidLoad event and
if([dateListArray count] > 0)
{
[dateListArray removeAllObjects];
}
above write down in your required function.
I guess:
NSMutableArray:-removeAllObjects
may help~