I am using the NSXMLParser to get new RSS stories from a feed and am displaying them in a UITableView. However now I want to take ONLY the images, and display them in a UIScrollView/UIImageView (3 images side-by side). I am completely lost. I am using the following code to obtain 1 image from a URL.
NSURL *theUrl1=[NSURL URLWithString:#"http://farm3.static.flickr.com/2586/4072164719_0fa5695f59.jpg"];
JImage *photoImage1=[[JImage alloc] init];
[photoImage1 setContentMode:UIViewContentModeScaleAspectFill];
[photoImage1 setFrame:CGRectMake(0, 0, 320, 170)];
[photoImage1 initWithImageAtURL:theUrl1];
[imageView1 addSubview:photoImage1];
[photoImage1 release];
This is all I have accomplished, and it works, for one image, and I have to specify the exact URL. What would you recommend I do to accomplish this?
Further to my other answer, which uses some helper classes and kinda assumes you're storing stuff with Core Data, here's a pure NSXMLParser way to do it.
In this example I'm assuming you have three UIImageViews setup with tags (100,101,102) so we can access them. First off, the code that starts the parser:
// Set the URL with the images, and escape it for creating NSURL
NSString *rssURLString = #"http://feeds.gettyimages.com/channels/RecentEditorialEntertainment.rss";
NSString *escapedURL = [rssURLString stringByAddingPercentEscapesUsingEncoding:NSASCIIStringEncoding];
NSURL *rssURL = [NSURL URLWithString:escapedURL];
// rssParser is an NSXMLParser instance variable
if (rssParser) [rssParser release];
rssParser = [[NSXMLParser alloc] initWithContentsOfURL:rssURL];
[rssParser setDelegate:self];
success = [rssParser parse]; // return value not used
At this point the parsing starts and NSXMLParser will fire off calls to it's delegate methods as it finds different start and end elements in the XML.
In this example I am only writing the didStartElement method:
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
{
// look for an attribute called url
if ([attributeDict objectForKey:#"url"]) {
currentString = [attributeDict objectForKey:#"url"];
NSLog(#"Image URL: %#", currentString);
NSString* escapedURL = [currentString stringByAddingPercentEscapesUsingEncoding:NSASCIIStringEncoding];
UIImage *image = [[UIImage alloc] initWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:escapedURL]]];
UIImageView * tmpImageView = (UIImageView*)[scrollView viewWithTag:100+imageCount];
[tmpImageView setImage:image];
NSLog(#"images found: %d", imageCount);
imageCount++;
if (imageCount>2) [rssParser abortParsing];
}
}
Here we look to see if the attributeDict (an NSDictionary object) contains a url attribute. If so, we grab it into currentString and then escape it, just incase it has characters that NSURL will barf on. Then we create an image from that URL and set the appropriate UIImageView image based on the tag numbers. imageCount is a counter; once we've done three images we tell the NSXMLParser to abort parsing the XML.
If your XML puts the URL inside element tags like:
<image>http://example.com/image.jpg</image>
You'll need to do a bit more work with didEndElement and foundCharacters. See the quite excellent Introduction to Event-Driven XML Programming Guide for Cocoa.
I knocked together a quick and dirty app to demo this, you can grab it here.
it sounds like you need to first identify the xml tag that identifies the images in your xml document. you should be able to do this by typing whatever API call you're using into a browser address bar.
once you've done that you can make an array of image urls from the nsxmlparser delegate method that receives new data.
once you have the array of image url's you can do something similar to what you are doing above except that you would use NSURL *theUrl1=[myArray objectAtIndex:...
you can arrange the images just by changing their centre location: image.center = CGPointMake(160,240)..
hope that helps. there are apple docs for nsxmlparser.
You can also try dictionary implementation while fetching data from API call. First you have to identify xml tag that identifies images in xml document, then you can assign each image with its corresponding story as image's key into a dictionary. It will make sure that for particular story only its associated image will be displayed. Then u can use this information later in your application as the requirement varies.
NSMutableDictionary *mutDict = [[NSMutableDictionary allloc]init];
if([elementName isEqualToString:#"story_image"])
{
[mutDict setObject:currentImage forKey:currentStory];
}
I want to suggest you to use JSON instead of xml as it is lightweight data-interchange
format. It would save lot of formatting and effort also.
You can visit this page
http://code.google.com/p/json-frame
It is definitely going to help you.
You have to just download the framework and then use in your application.
To get the live data you have to do same thing as in XMLParsing
NSString *jsonString = [NSString stringWithContentsOfURL:url encoding:NSUTF8StringEncoding error:nil];
NSDictionary *JDict = [jsonString JSONValue];
or
NSArray * JArr = [jsonString JSONValue];
depending upon what your data-feed contains.
I've been using NSXMLParser myself and storing the results using CoreData. I use a version of Björn Sållarp's Parser class from his CoreData example code.
My images end up as NSData/Binary in a SQLite database, but they might just as well get put into an array of UIImage for immediate display.
Extract from Parser.m: (from Björn Sållarp)
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
if ([elementName isEqualToString:#"imagetag"])
{
UIImage *newImage = [[UIImage alloc] initWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:currentString]]];
NSData *imageData = UIImagePNGRepresentation(newImage);
[currentSearchResult setImage:imageData];
currentString = nil;
return;
}
Called from my view with:
NSString *searchURL = #"http://www.feedurl.com/feed/address/feed.xml";
NSURL *xmlURL = [NSURL URLWithString:searchURL];
Parser *xmlParse = [[Parser alloc] initWithContext:managedObjectContext];
[xmlParse parseXMLFileAtURL:xmlURL parseError:&parseError];
That code assumes your XML document contains image URLs with the tag format:
<imagetag>http://example.com/path/to/image.png</imagetag>
Even if you're not using CoreData, working through the example at that link would be instructional for processing XML with NSXMLParser.
Related
I have nearly 15 and more xml file inside of one folder if possible to parse all file one by one? I set path like this below if I want to parse multiple files. how can I set path of that folder file?
this code for single file xml parser it's working fine.
NSString *playlistfilePath = [[NSBundle mainBundle] pathForResource:#"CT8OkzhF8qmEYGe2" ofType:#"xml"];
NSData *playlistfileData = [NSData dataWithContentsOfFile:playlistfilePath];
NSString *playlistxmlFile = [[NSString alloc] initWithData:playlistfileData encoding:NSASCIIStringEncoding];
//parsing the XML
PlaylistXmlParser *playlistparser = [[PlaylistXmlParser alloc] init];
[playlistparser parseXMLFile:playlistxmlFile];
that all the XML files are having same structure and same element.
On the basis of the NSXMLParser object write the logic of the parsing:-
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict {
//check with switch or if else condition which NSXMLParser object is using this delegate.
}
As like above all the delegates of NSXMLParser have a parameter as an NSXMLParser object.
try this:
NSXMLParser *xmlParser = [[[NSXMLParser alloc] initWithData:playlistfileData]autorelease];
PlaylistXmlParser *parser = [[PlaylistXmlParser alloc] initXMLParser:#"xmlname"];
[xmlParser setDelegate:parser];
in PlaylistXmlParser.m file
- (PlaylistXmlParser *) initXMLParser:(NSString *)name {
[super init];
xmlname =name;
return self;
}
now in every methods in PlaylistXmlParser.m file :
if ([xmlname isEqualToString:#"xmlname"]) {
//store data
}
else if([xmlname isEqualToString:#"xmlname_1"]){
//store data
}
#moorthy use pathForResourcesType:inDirectory on NSBundle method to get array of paths, Then for every single path inside the array create an instance for the parser class and parse the file.
[[NSBundle mainbundle]pathForResourcesType:#"xml" inDirectory:"Your directory Path"]
This will return an array ...... Hope it helps you
I have a xml file in following format.
<Category id="CIBA_VISION" image="Choose_Page\CON_PNG\Ciba_Vision.png">
<Product id="CON_CIBA_01" image="Buy_Page\Eye_CON_PNG\CIBAVision\List_01.png">
<Detail image="Buy_Page\Eye_CON_PNG\CIBAVision\Buy_01.png"/>
</Product>
where images contains image path in specified folder which is in resource folder of project.
My question is: After parsing this xml file, will the image tag pick the values from the folder or it will show only path after parsing.
Thanks in advance.
NSString *imaegeString = #"Ciba_Vision.png";
NSArray *pathComponents = [imaegeString componentsSeparatedByString:#"_"];
NSString *imageName=[pathComponents lastObject];
UIImage *img8 = [UIImage imageWithContentsOfFile:[[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:imageName]];
try this code
It will only contain the values you see there, except you add the base to URLs while parsing yourself.
And picking completely depends on your context, how do you like the code to pick?
yes you can get the image by the following code in your imageView You can try this:-
NSString *imaegeString = #"Choose_Page\CON_PNG\Ciba_Vision.png";
NSArray *pathComponents = [imaegeString componentsSeparatedByString:#"_"];
NSString *imageName=[pathComponents lastObject];
UIImage *img8 = [UIImage imageWithContentsOfFile:[[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:imageName]];
Hope this might help you...If this work you can do same for another strings in your parsing...
you ll get only path after parsing it wont do anything with that path.we have use that path and do our work thats it
some sample is
-(void)parser:(NSXMLParser *)parser
didStartElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI
qualifiedName:(NSString *)qName
attributes:(NSDictionary *)attributeDict
{
if([elementName isEqualToString: #"Detail"]){
//get all the attributes of from the dictionary(attributeDict)
}
}
i am getting images from the .net web server by passing xml parameters.
i am getting more that 20 images and i am saving images in iphone simulator documents one by one like this.
-(void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
if( [elementName isEqualToString:#"photo"])
{
recordResults_photo = FALSE;
NSData *decode = [Base64 decode:resultData_photo];
NSString *theXML = [[NSString alloc] initWithData:decode encoding:NSUTF8StringEncoding];
NSData *decodedimage = [Base64 decode:theXML];
UIImage *image = [UIImage imageWithData:decodedimage];
NSString *docDir = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSLog(#"saving msg image %d",i);
NSString *pngFilePath = [NSString stringWithFormat:#"%#/image%d.png",docDir,i];
NSData *data1 = [NSData dataWithData:UIImagePNGRepresentation(image)];
[data1 writeToFile:pngFilePath atomically:YES];
}
}
then images are saving like this image0.png,image1.png,image2.png.....
and i am displaying these images in table view like this.
NSString *docDir = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *pngFilePath = [NSString stringWithFormat:#"%#/image%d.png",docDir,indexPath.row];
UIImageView *img = [[UIImageView alloc]initWithFrame:CGRectMake(250, 05, 30, 30)];
img.image = [UIImage imageWithContentsOfFile:pngFilePath];
[cell.contentView addSubview:img];
then images are displayed well.
But now i have a problem here.
I am getting some more new images from the web server and i need to display them at the top of the table view.
As per my implementation i need to change all the image names.
That's not the proper way,is there any alternate way or better way than me.
can any one please help me.
Thank u in advance
See this answer:
how to add new elements in array at the top of the table view
It's much better than my answer to the same question but both would work.
I just confirmed that this does shift the objects down by one, so this should work.
EDIT: I'm sorry, I misread your question. As for changing the image names, the only way I see thats possible is by iterating through the array and changing the names once new objects are added.
I am needing to parse an XML file for my app and I dont have any clue how to do it. I went through one XMLParser tutorial, and it worked fine but the XML file in the tutorial was very simple and my XML file is quite a bit more complex.
here is a snippet of the xml file:
<?xml version="1.0" encoding="UTF-8"?>
<digital_tpp cycle="1003" from_edate="0901Z 03/11/10" to_edate="0901Z 04/08/10">
<state_code ID="AK" state_fullname="Alaska">
<city_name ID="ADAK ISLAND" volume="AK-1">
<airport_name ID="ADAK" military="N" apt_ident="ADK" icao_ident="PADK" alnum="1244">
<record>
<chartseq>10100</chartseq>
<chart_code>MIN</chart_code>
<chart_name>TAKE-OFF MINIMUMS</chart_name>
<useraction></useraction>
<pdf_name>AKTO.PDF</pdf_name>
<cn_flg>N</cn_flg>
<cnsection></cnsection>
<cnpage></cnpage>
<bvsection>C</bvsection>
<bvpage></bvpage>
<procuid></procuid>
<two_colored>N</two_colored>
<civil> </civil>
<faanfd15></faanfd15>
<faanfd18></faanfd18>
<copter></copter>
</record>
<record>
<chartseq>10200</chartseq>
<chart_code>MIN</chart_code>
<chart_name>ALTERNATE MINIMUMS</chart_name>
<useraction></useraction>
<pdf_name>AKALT.PDF</pdf_name>
<cn_flg>N</cn_flg>
<cnsection></cnsection>
<cnpage></cnpage>
<bvsection>E</bvsection>
<bvpage></bvpage>
<procuid></procuid>
<two_colored>N</two_colored>
<civil> </civil>
<faanfd15></faanfd15>
<faanfd18></faanfd18>
<copter></copter>
</record>
</airport_name>
</city_name>
</state_code>
</digital_tpp>
What I'm needing to do is search the XML file for the <...icao_ident> that the user specifies, then create a dictionary containing the <pdf_name> and <chart_name> for each <record> . I will then create a UI that displays the pdf files.
Can someone direct me to a good tutorial or explanation of how XML parser works? Or if I'm going about this the wrong way I'd be open to suggestions too.
(the XML file is about 8MB)
You might find that my blog post about wrapping NSXMLParser gives you what you need - and possibly a higher level alternative (my wrapper).
For example, using my technique, you'd write methods like:
-(void) handleElement_chartname: (NSDictionary*) attributes;
I suggest you to read the Event-Driven XML Programming Guide for Cocoa. In your specific case, what you need to do is:
In the parser:didStartElement: check for the element name: "airport_name", initialize a new array to store all the record elements (or you can define your own data structure to store the record element), a dictionary to store all element in the record, one string variable to store the current text
In the parser:foundCharacters: append the string to the current text
In the parser:didEndElement: save the dictionary to the array, release the array, save the results.
UPDATED
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict {
if ( [elementName isEqualToString:#"airport_name"]) {
if (!airports)
airports = [[NSMutableArray alloc] init];
NSString *str_icao_ident = [attributeDict objectForKey:#"icao_ident"];
//do something
return;
// ... continued ...
}}
i know this isn't the best way...
I struggled for 2 days trying to adapt the XML parser to my situation. I couldnt grasp it, probably because I'm just so used to doing this in C# and obj-c is new to me...
So what I did was parsed the whole thing as a string.
I converted the entire XML file to a NSString, then used substringToIndex and substringFromIndex to isolate the section I needed (the airport). I then used the </record> tag to create an array of <records>, then wrote a for loop that took the values I needed out of the each array object just by getting the range of the tags.
Like I said, it was a crazy solution, but I did it all in 26 lines of code and it works great.
NSString *path = [[NSBundle mainBundle] pathForResource:#"dttps" ofType:#"xml"];
NSData *data = [[NSData alloc]initWithContentsOfFile:path];
NSString *xmlString = [[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding];
NSRange range = [xmlString rangeOfString:searchedAirport];
xmlString = [xmlString substringFromIndex:range.location];
range = [xmlString rangeOfString:#"/airport_name"];
xmlString = [xmlString substringToIndex:range.location];
NSMutableArray *chartNames = [[NSMutableArray alloc]initWithCapacity:100] ;
NSMutableArray *pdfNames = [[NSMutableArray alloc]initWithCapacity:100] ;
NSArray *charts = [xmlString componentsSeparatedByString:#"</record>"];
NSString *tempString = [[NSString alloc]initWithFormat:#""];
int chartsCount = [charts count]-1;
int x;
for (x=0; x < chartsCount; x=x+1) {
tempString = [charts objectAtIndex:x];
range = [tempString rangeOfString:#"<chart_name>"];
tempString = [tempString substringFromIndex:range.location+12];
range = [tempString rangeOfString:#"</chart_name>"];
tempString = [tempString substringToIndex:range.location];
[chartNames addObject:tempString];
tempString = [charts objectAtIndex:x];
range = [tempString rangeOfString:#"<pdf_name>"];
tempString = [tempString substringFromIndex:range.location+10];
range = [tempString rangeOfString:#"</pdf_name>"];
tempString = [tempString substringToIndex:range.location-4];
[pdfNames addObject:tempString];
}
followed by cleanup...
The default XML parsing on the iPhone is pretty tragic compared with contemporary scripting languages. If you are doing serious parsing with complex objects with multiple levels of child objects, then god help you with NSXMLParser.
I would recommend checking out TouchXML which offers a much more civilized solution that is closer to what you might see in a language like Python or Actionscript in terms of its implementation within your own source.
I am new to iphone development .I want parse an image url from a xml file and display it in a RSS feed.There are three image url but i want to retrieve only one url and display it.
<entry>
<id>xxxxx</id>
<title>xxx xxxx xxxx</title>
<content>xxxxxxxxxxx</content>
<media:group>
<media:thumbnail url="http://tiger.jpg"/>
<media:thumbnail url="http://lion.jpg"/>
<media:thumbnail url="http://elephan.jpg"/>
</media:group>
</entry>
for parsing it
- (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"])
{
NSString* myUrl = [NSString stringWithString:[attributeDict objectForKey:#"url"]];
}
}.
I want to retrieve only tiger image.Please help me out.Thanks.
In this perticular instance you could set a class variable instead of the current local myUrl and once you get a value in it. In the code below this assumes you never initialize myURL anywhere else.
if (myURL == nil)
myUrl = [attributeDict objectForKey:#"url"];
However this will only work the way you expect if you always want the first thumbnail URL. Unless you have some guarantee (which you haven't mentioned) that you will always want the first URL then there really isn't anything you can do to catch cases when you don't want the first URL since all of the thumbnail URLs tags and attributes are the same save for the URL.