iphone using NSXML parser how to parse the attributes - iphone

I want to know how to parse the attributes in below xml file
<ROOT_ELEMENT><RESPONSE READ_TAG="LEVEL_LIST" RESULT="" TEXT=""/><USER USER_NAME="newadmin01" TOKEN_ID="0.766003221016982" FULL_NAME="newadmin01, newadmin01"/><DATETIME UNFORMATTED_TEXT="Aug 10 2011 12:25PM" FORMATTED_TEXT="10 Aug 12:25"/><BREADCRUMB/><LEVEL_LIST><LEVEL ID="4519" NAME="Mega Mart" CHILD_EXISTS="Y" ADD_EDIT_PRIVILEGE="Y"/></LEVEL_LIST></ROOT_ELEMENT>
here it is my parser code
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict {
elemName = [[NSString alloc] initWithString:elementName];
NSLog(#"element Name = %#", elementName);
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
if ([elemName isEqualToString:#"RESPONSE"]) {
if (!currentValueString) {
currentValueString = [[NSMutableString alloc] initWithCapacity:1024];
}
[currentValueString appendString:string];
}
else if ([elemName isEqualToString:#"USER"]) {
if (!currentValueString) {
currentValueString = [[NSMutableString alloc] initWithCapacity:1024];
}
[currentValueString appendString:string];
}
if ([elemName isEqualToString:#"DATETIME"]) {
if (!currentValueString) {
currentValueString = [[NSMutableString alloc] initWithCapacity:1024];
}
[currentValueString appendString:string];
}
else if ([elemName isEqualToString:#"BREADCRUMB"]) {
if (!currentValueString) {
currentValueString = [[NSMutableString alloc] initWithCapacity:1024];
}
[currentValueString appendString:string];
}
else if ([elemName isEqualToString:#"LEVEL"]) {
if (!currentValueString) {
currentValueString = [[NSMutableString alloc] initWithCapacity:1024];
}
[currentValueString appendString:string];
}
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {
if ([elemName isEqualToString:#"RESPONSE"]) {
[tableDataArray addObject:currentValueString];
[currentValueString release];
currentValueString = nil;
[elemName release];
elemName = nil;
}
else if ([elemName isEqualToString:#"USER"]) {
[tableDataArray addObject:currentValueString];
[currentValueString release];
currentValueString = nil;
[elemName release];
elemName = nil;
}
else if ([elemName isEqualToString:#"DATETIME"]) {
[tableDataArray addObject:currentValueString];
[currentValueString release];
currentValueString = nil;
[elemName release];
elemName = nil;
}
else if ([elemName isEqualToString:#"BREADCRUMB"]) {
[tableDataArray addObject:currentValueString];
[currentValueString release];
currentValueString = nil;
[elemName release];
elemName = nil;
}
else if ([elemName isEqualToString:#"LEVEL"]) {
[tableDataArray addObject:currentValueString];
[currentValueString release];
currentValueString = nil;
[elemName release];
elemName = nil;
}
}

Look at the NSXMLParserDelegate's message declaration
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qualifiedName attributes:(NSDictionary *)attributeDict
It has an attributeDict for the element you currently parse.
Iterate over the key-value pairs and deal with them as you like.
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict {
elemName = [[NSString alloc] initWithString:elementName];
NSLog(#"element Name = %#", elementName);
NSEnumerator *keyEnumerator = attributeDict.keyEnumerator()
// for each element the parser encounters:
// create a new dictionary to hold the attributes
NSMutableDictionary *myAttributes = [[NSMutableDictionary alloc] init];
// go through each attribute for the elementName tag
while ( (id aKey = [keyEnumerator nextObject]) )
// and store the attribute to the dictionary by copying over the values
[myAttributes setObject:[attributesDict objectForKey:aKey] forKey:aKey];
// after we caught all attributes and copied them into our own data structure
// put them into an instance dicionary to get a structure which holds
// all attributes for any element tag we encounter
// accessible by the elementName as key
[self.attributesByElementDictionary setObject:myAttributes forKey:elementName];
[myAttributes release];
}
Practically this would produce a dictionary for the - example! - RESPONSE tag:
The dictionary would look like:
{
"READ_TAG": "LEVEL_LIST",
"RESULT": "",
"TEXT": ""
}
For a more general solution you would not use a flat dictionary but rather form some kind of tree structure. This is a little bit more work and more robust - but this little example should give you the idea to extract the attributes from a tag and process them afterwards

Related

Not getting data after XML Parser

I am using XML parser to get my data.
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
currentNodeContent = (NSMutableString *) [string stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
if ( [elementName isEqualToString:#"country"] )
{
x++;
[messages addObject:[NSDictionary dictionaryWithObjectsAndKeys:Id,#"ID",Name,#"NAME",Image,#"IMAGE",nil]];
//**111**
NSLog(#"Data in Message : %#", [messages objectAtIndex:(x-1)]);
[Id setString:#""];
[Name setString:#""];
[Image setString:#""];
}
if ( [elementName isEqualToString:#"id"] )
{
[Id appendString:currentNodeContent];
}
if ( [elementName isEqualToString:#"name"] )
{
[Name appendString:currentNodeContent];
}
if ( [elementName isEqualToString:#"im"] )
{
[Image appendString:currentNodeContent];
}
}
//At //*111* the message is printed but when I do this after calling the xml parser, it doesn't print:
chatParser = [[NSXMLParser alloc] initWithData:receivedData];
[chatParser setDelegate:self];
[chatParser parse];
NSLog(#"\n\nMessages...\n\n%#", messages); //here there is no data printing
at this point it is printing empty..
Messages.
(
{
ID = "";
IMAGE = "";
NAME = "";
},
{
ID = "";
IMAGE = "";
NAME = "";
},
{
ID = "";
IMAGE = "";
NAME = "";
},
{
ID = "";
IMAGE = "";
NAME = "";
},
{
ID = "";
IMAGE = "";
NAME = "";
},
)
I have define message properties and also sythesize it.
In viewDidLoad I have did this
messages=[[NSMutableArray alloc] init];
Thank you for help..
Your problem is that you use same objects Id, Name, Image all the time and with the lines
[Id setString:#""];
[Name setString:#""];
[Image setString:#""];
set their values to "" at the end of each country element.
It better should look like this (not tested, maybe some typos):
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
currentNodeContent = (NSMutableString *) [string stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
if ([elementName isEqualToString:#"id"] )
{
[lastMessage setObject:currentNodeContent forKey:"ID"];
}
else if ( [elementName isEqualToString:#"name"] )
{
[lastMessage setObject:currentNodeContent forKey:"NAME"];
}
else if ( [elementName isEqualToString:#"im"] )
{
[lastMessage setObject:currentNodeContent forKey:"IMAGE"];
}
else if ( [elementName isEqualToString:#"country"] )
{
NSLog(#"Data in Message : %#", lastObject);
[messages addObject:lastMessage];
[lastMessage release];
}
}
-(void) parser:(NSXMLParser *)parser didStartElement:(NSString *)elName namespaceURI:(NSString *)uri
{
if ( [elementName isEqualToString:#"country"] )
{
lastMessage = [[NSMutableDictionary alloc]init];
}
}
Use the Below Code.Where Table is NSObject Class with the CaseId,PartyId,CartId as a properties in this class.If you have the xml url just called loadXMLByURL method with URl.After parsing you will get Each Object in TableArray which have the Table object with above properties.
NSMutableString *currentNodeContent;
NSXMLParser *parser;
Tweet *currentTweet;
bool isStatus;
-(id) loadXMLByURL:(NSString *)urlString
{
_tweets = [[NSMutableArray alloc] init];
NSURL *url = [NSURL URLWithString:urlString];
NSData *data = [[NSData alloc] initWithContentsOfURL:url];
parser = [[NSXMLParser alloc] initWithData:data];
parser.delegate = self;
[parser parse];
return self;
}
- (void) parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
currentNodeContent = (NSMutableString *) [string stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
}
- (void) parser:(NSXMLParser *)parser didStartElement:(NSString *)elementname namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
{
if ([elementname isEqualToString:#"Table"])
{
currentTable = [Table alloc];
isStatus = YES;
}
}
- (void) parser:(NSXMLParser *)parser didEndElement:(NSString *)elementname namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
if (isStatus)
{
if ([elementname isEqualToString:#"CaseId"])
{
currentTable.CaseId = currentNodeContent;
}
if ([elementname isEqualToString:#"PartyId"])
{
currentTable.PartyId = currentNodeContent;
}
if ([elementname isEqualToString:#"CartId"])
{
currentTable.CartId = currentNodeContent;
}
}
if ([elementname isEqualToString:#"Table"])
{
[self.tableArray addObject:currentTable];
currentTable = nil;
currentNodeContent = nil;
}
}
Let me know if you have any doubt.

Parse 2 RSS feeds in app delegate

I'm following a tutorial and it's working fine but if I wanted to parse 2 RSS feeds it seems to overwrite one array instead of saving them in the respective arrays.
This is in my delegate:
NSURL *url2 = [[NSURL alloc] initWithString:#"myRSSFEED1"];
NSXMLParser *xmlParser1 = [[NSXMLParser alloc] initWithContentsOfURL:url2];
//Initialize the delegate.
XMLParser1 *parser1 = [[XMLParser1 alloc] initXMLParser];
//Set delegate
[xmlParser1 setDelegate:parser1];
//Start parsing the XML file.
BOOL successs = [xmlParser1 parse];
if(successs)
NSLog(#"No Errors");
else
NSLog(#"Error Error Error!!!");
//VIDS
NSURL *url = [[NSURL alloc] initWithString:#"MYRSSFEED2"];
NSXMLParser *xmlParser = [[NSXMLParser alloc] initWithContentsOfURL:url];
//Initialize the delegate.
XMLParser *parser = [[XMLParser alloc] initXMLParser];
//Set delegate
[xmlParser setDelegate:parser];
//Start parsing the XML file.
BOOL success = [xmlParser parse];
if(success)
NSLog(#"No Errors");
else
NSLog(#"Error Error Error!!!");
that parses feed 1, allocates it to the array then parses 2 and seems to overwrite the first insteaf of using the second array that are defined as
#synthesize pics;
#synthesize books;
And saved in my XMLParser & XMLParser1
I can't figure out how to stop it from overwriting.
Here is my XMLParsers too:
- (void)parsers:(NSXMLParser *)parsers didStartElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qualifiedName
attributes:(NSDictionary *)attributeDict {
if([elementName isEqualToString:#"Books"]) {
//Initialize the array.
appDelegate2.pics = [[NSMutableArray alloc] init];
}
else if([elementName isEqualToString:#"Book"]) {
//Initialize the book.
apics = [[BookPhoto alloc] init];
//Extract the attribute here.
apics.bookID = [[attributeDict objectForKey:#"id"] integerValue];
NSLog(#"Reading HAVid value :%i", apics.bookID);
}
NSLog(#"Processing Element: %#", elementName);
}
- (void)parsers:(NSXMLParser *)parsers foundCharacters:(NSString *)string {
if(!currentElementValue)
currentElementValue = [[NSMutableString alloc] initWithString:string];
else
[currentElementValue appendString:string];
NSLog(#"Processing Value: %#", currentElementValue);
}
- (void)parsers:(NSXMLParser *)parsers didEndElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {
if([elementName isEqualToString:#"Books"])
return;
//There is nothing to do if we encounter the Books element here.
//If we encounter the Book element howevere, we want to add the book object to the array
// and release the object.
if([elementName isEqualToString:#"Book"]) {
[appDelegate2.pics addObject:apics];
[apics release];
apics = nil;
}
else
[apics setValue:currentElementValue forKey:elementName];
[currentElementValue release];
currentElementValue = nil;
}
And my XMLParser.m
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qualifiedName
attributes:(NSDictionary *)attributeDict {
if([elementName isEqualToString:#"Books"]) {
//Initialize the array.
appDelegate.books = [[NSMutableArray alloc] init];
}
else if([elementName isEqualToString:#"Book"]) {
//Initialize the book.
aBook = [[Book alloc] init];
//Extract the attribute here.
aBook.bookID = [[attributeDict objectForKey:#"id"] integerValue];
NSLog(#"Reading id value :%i", aBook.bookID);
}
NSLog(#"Processing Element: %#", elementName);
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
if(!currentElementValue)
currentElementValue = [[NSMutableString alloc] initWithString:string];
else
[currentElementValue appendString:string];
NSLog(#"Processing Value: %#", currentElementValue);
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {
if([elementName isEqualToString:#"Books"])
return;
//There is nothing to do if we encounter the Books element here.
//If we encounter the Book element howevere, we want to add the book object to the array
// and release the object.
if([elementName isEqualToString:#"Book"]) {
[appDelegate.books addObject:aBook];
[aBook release];
aBook = nil;
}
else
[aBook setValue:currentElementValue forKey:elementName];
[currentElementValue release];
currentElementValue = nil;
}
Any help on this would be brilliant,
I suggest putting a breakpoint at the point where the array is not getting loaded, and seeing if (1) it even gets called, and (2), whether it is saving the data into the array at all.
my bad
seems i had extra s's in parser:
- (void)parsers:(NSXMLParser *)parsers foundCharacters:(NSString *)string {
if(!currentElementValue)
currentElementValue = [[NSMutableString alloc] initWithString:string];
else
[currentElementValue appendString:string];
NSLog(#"Processing Value: %#", currentElementValue);
}
should have been:
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
if(!currentElementValue)
currentElementValue = [[NSMutableString alloc] initWithString:string];
else
[currentElementValue appendString:string];
NSLog(#"Processing Value: %#", currentElementValue);
}
cheers for the help tho

Memory leak NSXMLParser [duplicate]

This question already has answers here:
NSXMLParser Leaking
(4 answers)
Closed 2 years ago.
My NSXMLParser is leaking and I don't know why! Instrument is saying, in the extended details, that the source is 100% from [Parser parse];
Picture: Instruments leaks
This is my code for allocating and releasing the NSXMLParser:
NSURL *xmlURL = [NSURL URLWithString:#"http://www.website.com/link.xml"];
NSData * dataXml = [[NSData alloc] initWithContentsOfURL:xmlURL];
Parser = [[NSXMLParser alloc] initWithData:dataXml];
[dataXml release];
Parser.delegate = self;
[Parser parse];
[Parser release];
The delegate methods
//Standard function parser: reading open tag
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
attributes:(NSDictionary *)attributeDict{
currentElement = elementName;
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"]){
valueKey = [xmlArray valueForKey:currentElement];
if(nil != valueKey)
{
valueKey = [valueKey stringByAppendingString:string];
}else
{
valueKey = string;
}
[xmlArray setObject:valueKey forKey:currentElement];
}
if ([currentElement isEqualToString:#"message"]){
valueKey = [xmlArray valueForKey:currentElement];
if(nil != valueKey)
{
valueKey = [valueKey stringByAppendingString:string];
}else
{
valueKey = string;
}
[xmlArray setObject:valueKey forKey:currentElement];
}
if ([currentElement isEqualToString:#"picture"]){
valueKey = [xmlArray valueForKey:currentElement];
if(nil != valueKey)
{
}else
{
valueKey = string;
}
[xmlArray setObject:valueKey forKey:currentElement];
}
}
//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];
newPost.created_time = [xmlArray objectForKey:#"created_time"];
newPost.message = [xmlArray objectForKey:#"message"];
newPost.picture = [xmlArray objectForKey:#"picture"];
[containerArray addObject:newPost];
[xmlArray release];
[newPost release];
}
}
I suspect that the leak is occurring inside your didStartElement or didEndElement callbacks. Please post these up so that we can check.

problem in parsing!

i m not able to get processing values beyond "iid". giving exception:
[ setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key iid.'
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qualifiedName
attributes:(NSDictionary *)attributeDict {
if([elementName isEqualToString:#"NewDataSet"])
{
appDelegate.books = [[NSMutableArray alloc] init];
}
else if([elementName isEqualToString:#"Table"])
{
if([elementName isEqualToString:#"id"])
{
{
aBook = [[Book alloc] init];
}
}
NSLog(#"Processing Element: %#", elementName);
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
if(!currentElementValue)
currentElementValue = [[NSMutableString alloc] initWithString:string];
else
{
[currentElementValue appendString:string];
NSLog(#"Processing Value: %#", currentElementValue);
}
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {
//if([elementName isEqualToString:#"Tablesreturn"])
//return;
if([elementName isEqualToString:#"Table"])
{
[appDelegate.books addObject:aBook];
[aBook release];
aBook = nil;
}
else
[aBook setValue:currentElementValue forKey:elementName];
[currentElementValue release];
currentElementValue = nil;
}
It's not finding the iid value. It's case sensitive, so check if you're using the wrong case in your label name.
If you're not looking for too many values maybe you can just do a manual if then else for all the xml nodes you're interested in.
something like -
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {
if([elementName isEqualToString:#"Table"])
{
[appDelegate.books addObject:aBook];
[aBook release];
aBook = nil;
}
else if([elementName isEqualToString:#"xyz"])
{
[aBook setValue:currentElementValue forKey:#"xyz"];
}
// and so on, for the rest of the nodes.
[currentElementValue release];
currentElementValue = nil;
}
in ur Book class verify all tags or fields specified in .h file.......reply me
like Table, Tablesreturn.......all of them.
and synthesize all of them

XMLParser and NSMutableArray

I have followed a tutorial and the XML parsing part is working all right.
My problem is that when printing out the values that I store into the object (in my case the object is a car) always remains null. I save all the objects into an NSMutableArray which always seems to have a length/count == 0...what am I doing wrong? The array is, as can be seen in the code, defined in the delegate class...
- (XMLParser *) initXMLParser {
[super init];
appDelegate = (Car2GoAppDelegate *) [[UIApplication sharedApplication]delegate];
currentElementValue = [[NSMutableString alloc]init];
return self;
}
- (void) parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qualifiedName attribute:(NSDictionary *)attributeDict {
if([elementName isEqualToString:#"kml"]) {
appDelegate.cars = [[NSMutableArray alloc]init];
}
else if([elementName isEqualToString:#"Placemark"]) {
aCar = [[Car alloc]init];
}
else
return;
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *) string {
[currentElementValue appendString:string];
}
- (void) parser:(NSXMLParser *)parser didEndElement:(NSString *) elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {
if([elementName isEqualToString:#"kml"])
return;
if([elementName isEqualToString:#"Style"])
return;
if([elementName isEqualToString:#"IconStyle"])
return;
if([elementName isEqualToString:#"Icon"])
return;
if([elementName isEqualToString:#"color"])
return;
if([elementName isEqualToString:#"colorMode"])
return;
if([elementName isEqualToString:#"scale"])
return;
if([elementName isEqualToString:#"href"])
return;
if([elementName isEqualToString:#"styleUrl"])
return;
if([elementName isEqualToString:#"a"])
return;
if([elementName isEqualToString:#"Placemark"]) {
[appDelegate.cars addObject:aCar];
[aCar release];
aCar = nil;
}
else if([elementName isEqualToString:#"name"]) {
[aCar setValue:currentElementValue forKey:elementName];
}
else if([elementName isEqualToString:#"description"]) {
[aCar setValue:currentElementValue forKey:elementName];
[currentElementValue setString:#""];
}
else if([elementName isEqualToString:#"coordinates"]) {
[aCar setValue:currentElementValue forKey:elementName];
[currentElementValue setString:#""];
NSLog(#"aCar coordinates:%#", [aCar coordinates]);
}
else
return;
}
- (void) dealloc {
[aCar release];
[currentElementValue release];
[super dealloc];
}
#end
/loop
Your code looks OK. Are you sure your XML contains element wrapped in Placemark tags??
Also is there more than one kml element in your xml? Could there be one that is empty which is causing your original array to be discarded and replaced with a new one of length 0?
Don't you need to use the initWithCapacity method, in order to initialize the mutableArray properly ?
Instead of using directly appDelegate.cars, try with a local MutableArray, and see if something is different ?