I have a custom class and I set specific properties of that class based on the xml node name coming in.
if([elementName isEqualToString:#"strap"])
{
parcelObj.strap = nodeContent;
}
else if([elementName isEqualToString:#"owner"])
{
parcelObj.owner=nodeContent;
}
etc. etc...
I wanna know if I can lose the else if's all together and do this (somehow)
parcelObj."elementName" = nodeContent;
Make sense? I am not sure how to pass the "elementName" as the property ya know?
This may be a bit more info then you are looking for, but check out my custom xml parser JHXMLParser class. It parses an xml file and creates an array of dictionaries. Each dictionary has the xml tags name as a key for the text value inside the tag. So, if the xml data looked like this:
<PHOTOS>
<PHOTO>
<ID>177</ID>
<THUMB><![CDATA[http://www.blah.com/thumbs/489650795.jpg]]></THUMB>
<IMAGE><![CDATA[http://www.blah.com/images/489650795.jpg]]></IMAGE>
</PHOTO>
<PHOTO>
<ID>178</ID>
<THUMB><![CDATA[http://www.blah.com/thumbs/489650798.jpg]]></THUMB>
<IMAGE><![CDATA[http://www.blah.com/images/489650798.jpg]]></IMAGE>
</PHOTO>
</PHOTOS>
It would create an array with 2 dictionary elements. The first dictionary would have 3 keys ("ID", "THUMB", "IMAGE") and 3 values ("117", "http://www.blah.com/thumbs/489650795.jpg", and "http://www.blah.com/images/489650795.jpg") respectively.
Here are the important methods (_key, _previousTag, _currentTag, _elementText, and _parsedData are ivars and _key is a string that would be #"PHOTO" for the above XML):
- (void)parserDidStartDocument:(NSXMLParser *)parser {
_parsedData = [[NSMutableArray alloc] init];
}
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qualifiedName attributes:(NSDictionary *)attributeDict {
_currentTag = [[NSString alloc] initWithString:elementName];
if ([elementName isEqualToString:_key]) {
NSMutableDictionary *tmpDict = [[NSMutableDictionary alloc] init];
[_parsedData addObject:tmpDict];
[tmpDict release];
}
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
if ([_previousTag isEqualToString:_currentTag]) {
[_elementText appendString:[string stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]];
} else {
_elementText = [[NSMutableString alloc] initWithString:[string stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]];
}
if (![_previousTag isEqualToString:_currentTag]) {
_previousTag = [[NSString alloc] initWithString:_currentTag];
}
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {
if ([_previousTag isEqualToString:elementName]) {
[[_parsedData lastObject] setObject:_elementText forKey:elementName];
} else {
_previousTag = [[NSString alloc] initWithFormat:#""];
}
}
Related
I want to set string "EMPTY"for empty tag XML in NSXMLParse. Exm: my xml:
<STATE>0</STATE>
<MEMO/>
In above XML, MEMO tag is empty. I want to when NSXMLParse parse into tag, if it is empty,get string "EMPTY" in label. I used bellow code to parse xml:
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qualifiedName attributes:(NSDictionary *)attributeDict
{
NSLog(#"Did start element");
if ( [elementName isEqualToString:#"FILENAME"])
{
XML_FIELD = FILENAME_CLOUD2;
NSLog(#"found rootElement");
return;
}
else if ( [elementName isEqualToString:#"MEMO"])
{
NSLog(#"found rootElement");
XML_FIELD = MEMO;
return;
}
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
NSLog(#"Did end element");
if ([elementName isEqualToString:#"FILENAME"])
{
NSLog(#"rootelement end");
}
[strMemoEmpty setString:#"EMPTY"];
XML_FIELD = UNIMPORTANT2;
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
//NSString *tagName = #"USER_NAME";
if (XML_FIELD == FILENAME_CLOUD2)
{
NSLog(#"Value %#",string);
[FileCompletedArray insertObject:string atIndex:0];
}
else if (XML_FIELD == MEMO)
{
NSLog(#"Value %#",string);
if (string != nil) {
[strMemoEmpty setString:#""];
[strMemoEmpty appendString: string];
NSLog(#"foundResults: %#",strMemoEmpty);
}
[MemoArray insertObject:string atIndex:0];
}
}
I used above code but it not check MEMO tag is empty. It missed when parse. Do you have any suggestions? Thanks in advance
The construction of your code is a bit strange and messy, you should reorganise so:
didStartElement creates new storage for the starting element and sets any flags
foundCharacters doesn't have logic, it just appends the received string to a mutable buffer (it could be called multiple times for the same tag)
didEndElement contains the logic (and checks the length of the found characters and substitutes your empty value if required)
The way you have it now means that partial data may be saved in foundCharacters and, because that method isn't called for empty tags, some of your logic is being set but never actually saved.
I have an xml file that looks like this:
<result>
<trip duration="03:30">
<takeoff date="2010-06-19" time="18:40" city="Moscow"/>
<landing date="2010-06-19" time="20:10" city="Novgorod"/>
<flight carrier="Rossiya" number="8395" eq="320"/>
<price>13429.00</price>
</trip>
<trip duration="03:40">
<takeoff date="2010-06-19" time="09:20" city="Omsk"/>
<landing date="2010-06-19" time="11:15" city="Paris"/>
<flight carrier="AirFrance" number="1145" eq="320"/>
<price>13229.00</price>
</trip>
<trip duration="03:50">
<takeoff date="2010-06-19" time="07:20" city="Omsk"/>
<landing date="2010-06-19" time="14:15" city="Barcelona"/>
<flight carrier="AirFrance" number="1100" eq="320"/>
<price>13329.00</price>
</trip>
</result>
I'd like to get all the parameters and place them in 3 UITableViewCells. As you can see there are 3 flights and the data about them.
I've been trying to parse it in a TableView but I only managed to get the <price> thing going.
How would you deal with parsing complex-structured parameters within an XML file? I mean how would I get takeoff date parameter and so on and so forth?
As far as I could get you can't apply the tactics I'm using like this one:
- (void) parser:(NSXMLParser *)parser didEndElement:(NSString *)elementname namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
if ([elementname isEqualToString:#"price"])
{
currentTweet.dateCreated = currentNodeContent;
}
Any help would be highly appreciated. Thanks in advance.
This is the code that I frequently use to build a dictionary from an XML file that follows this basic model of some well defined repeating element (in this case, "trip"), and a series of data elements within that, some of which I'm reading the attributes of the tag (in this case, "takeoff", "landing" and "flight"), and others I'm reading the data between the opening and closing tags (in this case, just "price").
I have the following ivars:
#interface XmlParserViewController () <NSXMLParserDelegate>
{
NSMutableArray *trips;
NSMutableDictionary *currentTrip;
NSMutableString *currentElement;
}
#end
And then the code looks like:
- (void)viewDidLoad
{
[super viewDidLoad];
trips = [[NSMutableArray alloc] init];
// I'm getting my xml from my bundle. You get it however you're currently getting it.
NSString *filename = [[NSBundle mainBundle] pathForResource:#"results" ofType:#"xml"];
NSData *data = [NSData dataWithContentsOfFile:filename];
NSXMLParser *parser = [[NSXMLParser alloc] initWithData:data];
parser.delegate = self;
[parser parse];
}
#pragma mark - NSXMLParserDelegate methods
#define kRowElementTag #"trip"
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qualifiedName attributes:(NSDictionary *)attributeDict
{
NSArray *attributeElementNames = #[#"takeoff", #"landing", #"flight"];
NSArray *foundCharacterElementNames = #[#"price"];
if ([elementName isEqualToString:kRowElementTag])
{
currentTrip = [[NSMutableDictionary alloc] init];
[trips addObject:currentTrip];
if (attributeDict)
[currentTrip setObject:attributeDict forKey:elementName];
}
else if (currentTrip)
{
if ([attributeElementNames containsObject:elementName])
{
if (attributeDict)
[currentTrip setObject:attributeDict forKey:elementName];
}
else if ([foundCharacterElementNames containsObject:elementName] && currentElement == nil)
{
// you can change this to just grab a few fields ... add whatever fields you want to this
currentElement = [[NSMutableString alloc] init];
[currentTrip setObject:currentElement forKey:elementName];
}
}
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
if ([elementName isEqualToString:kRowElementTag])
{
currentTrip = nil;
}
else if (currentElement)
{
currentElement = nil;
}
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
if (currentElement)
{
[currentElement appendString:string];
}
}
- (void)parser:(NSXMLParser *)parser parseErrorOccurred:(NSError *)parseError
{
NSLog(#"%s error=%#", __FUNCTION__, parseError);
// we should handle the error here
}
- (void)parserDidEndDocument:(NSXMLParser *)parser
{
NSLog(#"%s trips=%#", __FUNCTION__, trips);
// generally I immediately kick off the reload of the table, but maybe
// you want to grok the trips dictionary first.
//
// [self.tableView reloadData];
}
As you can guess, I'm trying to end up with that sort of nested array/dictionary structure that we've gotten used to parsing JSON files. Clearly, I don't like the fact that I have to identify some of the structure of the XML file up front in my code (the fact that the outer array has "trip" tags, that "takeoff", "landing", and "flight" have attributes but "price"` doesn't), etc. But this is a little better than my first attempts at XML parsing that hardcoded values all over the place. Sigh.
You have to manage didStartElement too. This is a sample metacode could be good for you:
-(void)parser:(NSXMLParser*)parser didStartElement:(NSString *)elementName namespaceURI:(NSString*)namespaceURI qualifiedName:(NSString*)qualifiedName attributes:(NSDictionary*)attributeDict {
if([elementName isEqualToString:#"trip"]) {
currentTweet.tripDuration = [attributeDict objectForKey:#"duration"];
} else if ([elementName isEqualToString:#"takeoff"]) {
currentTweet.takeoffDate = [attributeDict objectForKey:#"date"];
currentTweet.takeoffTime = [attributeDict objectForKey:#"time"];
currentTweet.takeoffCity = [attributeDict objectForKey:#"city"];
} else if ([elementName isEqualToString:#"landing"]) {
...............
} else if ...........
}
Please anybody help me.i am in great trouble....Now my Problem is...
Using xml parser i have parsed some attribute and value of the attribute.
using this i am getting the element name:
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes: (NSDictionary *)attributeDict
Now using this i am getting value of the attribute from the xml:
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string{
NSLog(#"found characters: %# %#", currentElement,string);
suppose my xml data are something like that...
-<list>
−<ProductData HASH="838557843">
<id>1</id>
<productNumber>a91cc0f4c7</productNumber>
<name>Product 1</name>
<seoTitle>product-1</seoTitle>
<viewCount>0</viewCount>
<lowStock>0.0</lowStock>
<image>5e928bbae358c93caedf6115fa7d178b.jpg</image>
<dateCreated>2011-10-06T16:08:45</dateCreated>
<dateUpdated>2011-10-06T10:08:45</dateUpdated>
<isDummy>true</isDummy>
<isInventory>false</isInventory>
</ProductData>
-<ProductData HASH="681596439">
<id>2</id>
<productNumber>d8287e2e51</productNumber>
<name>Product 2</name>
<seoTitle>product-2</seoTitle>
−<description>
<p>Lorem ipsum dolor sit amet, consectetuer adipiscing elit,....</p>
</description>
<viewCount>0</viewCount>
<availableStock>100.0</availableStock>
<lowStock>0.0</lowStock>
<image>8bbd8dfff3cdd28285d07810a4fe7c32.jpg</image>
<basePrice>10.0</basePrice>
<costPrice>10.0</costPrice>
<height>1.0</height>
<width>1.0</width>
<depth>1.0</depth>
<weight>3.0</weight>
<status>A</status>
<quantityOrderMin>1.0</quantityOrderMin>
<productIsCall>false</productIsCall>
<quantityOrderMax>20.0</quantityOrderMax>
<priceByAttribute>false</priceByAttribute>
<dateCreated>2011-10-06T16:08:45</dateCreated>
<dateUpdated>2011-10-06T10:08:45</dateUpdated>
<isDummy>true</isDummy>
<isInventory>false</isInventory>
</ProductData>
</list>`
Now when i will get the id attribute then it will store in an array then all of the attribute after first id until next id i want to store the attribute and its value in the dictionary,when i will get second id then i want to continue previous process...then according to the value of id i want to display the value in a UIView or UITableView. its not neccesary where i want to display it.
My question is how can i store data in array and dictionary and display it any time in my viewcontroller. Please help me. its becoming a great trouble for me. if you can please give me a sample code as an example. please please anybody help me...
Thanks in Advance
If you change your XML to
<list>
<Object>
<id>1</id>
<product>name</product>
<image>imagename.jpg</image>
<dateCreated>date</dateCreated>
<productleft>10</productleft>
</Object>
<Object>
<id>2</id>
<product>name</product>
<image>imagename.jpg</image>
<dateCreated>date</dateCreated>
<productleft>30</productleft>
</Object>
</list>
Or if your XML looks something like above its easy to use SAX parser ( NSXMLParser you've used ). Otherwise if you want to stick to XML you have posted use DOM style parsing.
Here is the code for the XML after formatting using NSXMLParser.
// these are ivars
NSMutableArray * objectsArray;
NSMutableDictionary * productDict;
NSMutableString * currentString;
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qualifiedName attributes:(NSDictionary *)attributeDict
{
if([elementName isEqualToString:#"Object"])
{
objectsArray = [[NSMutableArray alloc] init];
productDict = [[NSMutableDictionary alloc] init];
}
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
if(!currentString)
{
currentString = [[NSMutableString alloc] init];
}
[currentString appendString:string];
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
if([elementName isEqualToString:#"id"])
{
[productDict setObject:currentString forKey:#"id"];
[currentString release],currentString = nil;
return;
}
if([elementName isEqualToString:#"product"])
{
[productDict setObject:currentString forKey:#"product"];
[currentString release],currentString = nil;
return;
}
if([elementName isEqualToString:#"image"])
{
[productDict setObject:currentString forKey:#"image"];
[currentString release],currentString = nil;
return;
}
if([elementName isEqualToString:#"dateCreated"])
{
[productDict setObject:currentString forKey:#"dateCreated"];
[currentString release],currentString = nil;
return;
}
if([elementName isEqualToString:#"productleft"])
{
[productDict setObject:currentString forKey:#"productleft"];
[currentString release],currentString = nil;
return;
}
if([elementName isEqualToString:#"Object"])
{
[objectsArray addObject:productDict];
[productDict release],productDict = nil;
}
[currentString release], currentString = nil;
}
I'm using NSXMLParser to parse an XML file. I'm doing this several times in my app for different purposes. I have one which parses annotations for a store locator, one that parses al the movies from a certain YouTube channel and the last one parses a self made XML file.
All parsers work great except the last one. For some kind of reason it parses i.e. the first node good, but then overwrites it.
Here is my parser code:
//Standard function parser: reading open tag
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
attributes:(NSDictionary *)attributeDict{
currentElement = [elementName copy];
if ([elementName isEqualToString:#"item"]) {
xmlArray = [[NSMutableDictionary alloc] init];
}
}
//Standard function parser: reading string
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string{
if ([currentElement isEqualToString:#"created_time"]){
[xmlArray setObject:string forKey:currentElement];
NSLog(#"test 1 %#", string);}
}
//Standard function parser: reading close tag
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI
qualifiedName:(NSString *)qName{
if ([elementName isEqualToString:#"item"]) {
Post *newPost = [[Post alloc] init];
NSLog(#"test %#", xmlArray );
newPost.created_time = [xmlArray objectForKey:#"created_time"];
[containerArray addObject:newPost];
[xmlArray release];
}
}
The XML looks like this:
<?xml version="1.0" encoding="UTF-8" ?>
<items>
<item>
<created_time>test</created_time>
<message>blabla</message>
<picture>http://www.trentshow.com/images/tada.jpg</picture>
</item>
</items>
And the log outputs the following:
2011-06-10 10:43:24.446 TabbedCalculation[1502:207] test 1 test
2011-06-10 10:43:24.448 TabbedCalculation[1502:207] test 1
2011-06-10 10:43:24.449 TabbedCalculation[1502:207] test 1
2011-06-10 10:43:24.450 TabbedCalculation[1502:207] test {
"created_time" = "\n";
}
I'm not getting why the parser loops 3 times over the created_time node. Any help would be great!
Try by following solution -- should work.
foundCharacters can be called for multiple time for each key value --- basically you should append all found character list.
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string{
if ([currentElement isEqualToString:#"created_time"]){
NSString *valueKey = [xmlArray ValueForKey:forKey:currentElement];
if(nil != valueKey)
{
valueKey = [valueKey stringByAppendingString:string];
}else
{
valueKey = string;
}
[xmlArray setObject:valueKey forKey:currentElement];
NSLog(#"test 1 %#", string);}
}
I am new to iphone development.I am parsing an XML page and displaying the content in a tableview.In some block in the XML page , the child element is missing , i want to add a value o in my array, when the child element is not fond in the particular block.My XML file is like
<entry>
<id>xxx </id>
<title>xxxxx</title>
<gd:ratings numRaters="2"/>
</entry> ..................................>first block
<entry>
<id>xxx </id>
<title>xxxxx</title>
</entry> ....................................>Second block
<entry>
<id>xxx </id>
<title>xxxxx</title>
<gd:ratings numRaters="2"/>
</entry> .....................................>Third block
I am parsing the gd:ratings tag and display its attribute numRates value in a tableview. I am having an mutable array which stores the value of numRates.I have to add object "O" in the array when the second block is parsed because it doesnot contain gd:ratings tag.Since the value is present in a attribute tag, for retrieving the content and adding it to the mutable array is done in NSXML parser DidStartElement method.
- (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"])
{ currentImage = [[NSMutableString alloc] init];
if(myUrl == nil){
myUrl = [NSString stringWithString:[attributeDict objectForKey:#"url"]];
}
[currentImage appendString:myUrl];
[stories1 addObject:currentImage];
myUrl=nil;
} else if([elementName isEqualToString:#"gd:rating"])
{
currentRating=[[NSMutableString alloc]init];
myRatings=[NSString stringWithString:[attributeDict objectForKey:#"numRaters"]];
[currentRating appendString:myRatings];
[stories2 addObject:currentRating];
}
}
Since there are 25 blocks of entry tags and in that 10 block doesnot have gd rating element .So the array stories2 array has only 15 values.So i cannot display it in the tableview in order.Is there any way out to retrieve the attribute tag in "found characters" method . Please help me out.Thanks.
You can use the didEndElement method: when the outer element ended, check if the child element was added to the array.
You could use an iVar BOOL entryHasRating and do the following:
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict{
currentElement = [elementName copy];
if ([elementName isEqualToString:#"entry"]) {
entryHasRating = NO;
...
} else if ([elementName isEqualToString:#"gd:rating"]){
entryHasRating = YES;
...
}
}
Then when an element ends:
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {
if ([elementName isEqualToString:#"entry"]&& !entryHasRating) {
[stories2 addObject:#"No Rating"];
entryHasRating = YES;
}
...
}
If you know all of the data fields that you'll be expecting, you could build a dictionary with placeholders for all of your expected values before you parse the XML; as you parse the XML just replace the placeholders with real values.