I have a xml to parse:
<media:content url='http://www.youtube.com/v/x5cBBXXFAPQ?version=3&f=playlists&app=youtube_gdata' type='application/x-shockwave-flash' medium='video' isDefault='true' expression='full' duration='391' yt:format='5'/><media:content url='rtsp://r5---sn-4g57kuee.c.youtube.com/CiULENy73wIaHAn0AMV1BQGXxxMYDSANFEgGUglwbGF5bGlzdHMM/0/0/0/video.3gp' type='video/3gpp' medium='video' expression='full' duration='391' yt:format='1'/><media:content url='rtsp://r5---sn-4g57kuee.c.youtube.com/CiULENy73wIaHAn0AMV1BQGXxxMYESARFEgGUglwbGF5bGlzdHMM/0/0/0/video.3gp' type='video/3gpp' medium='video' expression='full' duration='391' yt:format='6'/><media:description type='plain'>Bohemian Rhapsody
how can i get the first url from content ?
First you need to refer the Apple Documention
https://developer.apple.com/library/ios/documentation/Cocoa/Reference/Foundation/Classes/NSXMLParser_Class/index.html
- (void)viewDidLoad
{
NSURL *url = [[NSURL alloc]initWithString:#"yourURL"];
NSXMLParser *parser = [[NSXMLParser alloc]initWithContentsOfURL:url];
[parser setDelegate:self];
BOOL result = [parser parse];
}
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qualifiedName attributes:(NSDictionary *)attributeDict
{
NSLog(#\"Did start element\");
if ( [elementName isEqualToString:#"media:content"])
{
NSLog(#"found URL",[attributeDict objectForKey:#"url"]);//here u will get the url u want
return;
}
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
NSLog(#"Did end element");
if ([elementName isEqualToString:#"media"])
{
NSLog(#"rootelement end");
}
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
NSLog(#"Value %#",string);
}
It just overview about the delegate methods of XML not the solution..Refer the Document..
runnable sample:
edited based on comment...
#import <Foundation/Foundation.h>
#interface MyClass : NSObject<NSXMLParserDelegate>
#end
#implementation MyClass
- (instancetype)init {
self = [super init];
id xml = #"<media:content url='http://www.youtube.com/v/x5cBBXXFAPQ?version=3&f=playlists&app=youtube_gdata' type='application/x-shockwave-flash' medium='video' isDefault='true' expression='full' duration='391' yt:format='5'/><media:content url='rtsp://r5---sn-4g57kuee.c.youtube.com/CiULENy73wIaHAn0AMV1BQGXxxMYDSANFEgGUglwbGF5bGlzdHMM/0/0/0/video.3gp' type='video/3gpp' medium='video' expression='full' duration='391' yt:format='1'/><media:content url='rtsp://r5---sn-4g57kuee.c.youtube.com/CiULENy73wIaHAn0AMV1BQGXxxMYESARFEgGUglwbGF5bGlzdHMM/0/0/0/video.3gp' type='video/3gpp' medium='video' expression='full' duration='391' yt:format='6'/><media:description type='plain'>Bohemian Rhapsody";
id d = [xml dataUsingEncoding:NSUTF8StringEncoding];
NSXMLParser *p = [[NSXMLParser alloc] initWithData:d];
p.delegate = self;
[p parse];
return self;
}
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict {
if([elementName isEqualToString:#"media:content"]) {
static BOOL first = YES;
if(first) {
NSLog(#"%#", attributeDict[#"url"]);
first = NO;
}
}
}
#end
int main(int argc, const char * argv[]) {
#autoreleasepool {
id c = [[MyClass alloc] init];
}
return 0;
}
Related
I am new to iOS development. I want to parse my xml web-service array. My xml response is like,
<BookList>
<Book>
<BookID>int</BookID>
<BookName>string</BookName>
<Pages>string</Pages>
<Price>string</Price>
</Book>
<Book>
<BookID>int</BookID>
<BookName>string</BookName>
<Pages>string</Pages>
<Price>string</Price>
</Book>
</BookList>
Here is the code i am using to parse the response,
-(void)connectionDidFinishLoading:(NSURLConnection *)connection {
NSString *theXML = [[NSString alloc] initWithBytes:
[self.webResponseData mutableBytes] length:[self.webResponseData length] encoding:NSUTF8StringEncoding];
//now parsing the xml
NSXMLParser *xmlParser = [[NSXMLParser alloc] initWithData: self.webResponseData];
xmlParser.delegate = self;
// Run the parser
#try{
BOOL parsingResult = [xmlParser parse];
}
#catch (NSException* exception)
{
UIAlertView* alert = [[UIAlertView alloc]initWithTitle:#"Server Error" message:[exception reason] delegate:self cancelButtonTitle:#"OK" otherButtonTitles: nil];
[alert show];
return;
}
}
//Implement the NSXmlParserDelegate methods
-(void) parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI qualifiedName:
(NSString *)qName attributes:(NSDictionary *)attributeDict
{
currentElement = elementName;
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
// NSLog(#"String : %#", string);
if ([currentElement isEqualToString:#"BookID"]) {
NSLog(#"BookID : %#", string);
}else if ([currentElement isEqualToString:#"BookName"]) {
NSLog(#"BookName : %#", string);
}else if ([currentElement isEqualToString:#"Pages"]) {
NSLog(#"Pages : %#", string);
}else if ([currentElement isEqualToString:#"Price"]) {
NSLog(#"Price : %#", string);
}
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
// NSLog(#"Current Element: %# ",currentElement);
}
Using this code I can view the results, But i can get the number of books.
You can add this in to .h file
NSMutableDictionary *dictBook;
NSMutableArray *arrBook;
NSMutableString *elementValue;
Now use the below code to get the total book counts.
//Implement the NSXmlParserDelegate methods
-(void) parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI qualifiedName:
(NSString *)qName attributes:(NSDictionary *)attributeDict
{
currentElement = elementName;
if ([currentElement isEqualToString:#"BookList"]) {
arrBook = [[NSMutableArray alloc] init];
}
else if ([currentElement isEqualToString:#"Book"]) {
dictBook = [[NSMutableDictionary alloc] init];
}
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
if(!elementValue)
elementValue = [[NSMutableString alloc] initWithString:string];
else
elementValue = string; //[elementValue appendString:string];
NSLog(#"elementValue : %#",elementValue);
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
// NSLog(#"Current Element: %# ",currentElement);
if ([elementName isEqualToString:#"BookID"] ||
[elementName isEqualToString:#"BookName"] ||
[elementName isEqualToString:#"Pages"] ||
[elementName isEqualToString:#"Price"])
{
[dictBook setObject:elementValue forKey:elementName];
}
else if ([elementName isEqualToString:#"Book"])
{
[arrBook addObject:dictBook];
}
// [elementValue setString:#""];
}
- (void)parserDidEndDocument:(NSXMLParser *)parser {
NSLog(#"Arr Book Count : %lu", (unsigned long)arrBook.count);
}
Hope this will help you.
I am trying NSXMLParser for getting values from an XML for first time. But I have a problem.
Below my XML:
<Library>
<Book>
<ID>1</ID>
<TITLE>Test</TITLE>
</Book>
</Library>
and parser code:
-(void)parser:(NSXMLParser *)parser didStartElement:(NSString *) elementName namespaceURI:(NSString *)namespaceURI qualifiedNam(NSString *)qName attributes:(NSDictionary *)attributeDict
{
if([elementName isEqualToString:#"Book"])
{
NSLog(#"%#", [attributeDict valueForKey:#"ID"]);
}
}
The result ID is null. Can you help me please?
Unfortunately, NSXMLParser doesn't work this way. It traverses over the elements in XML in document order, so by the time the "Book" element starts, it hasn't reached the "ID" element yet. Your code would work if the XML looked like
<Book Id="1">
...
</Book>
but I suppose you have no control over the XML. Then you need a more sophisticated solution. I believe the following would work:
Add these instance variables
NSString *currentElement, *bookID, *bookTitle;
NSMutableString *elementValue;
Implement the following methods:
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *) elementName namespaceURI:(NSString *)namespaceURI qualifiedNam(NSString *)qName attributes:(NSDictionary *)attributeDict {
currentElement = elementName;
elementValue = nil;
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
// Append characters to element value
if (!elementValue) elementValue = [NSMutableString stringWithCapacity:100];
[elementValue appendString:string];
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qualifiedName {
if ([#"Id" isEqualToString:elementName]) {
bookID = [elementValue copy];
} else if ([#"Title" isEqualToString:elementName]) {
bookTitle = [elementValue copy];
} else if ([#"Book" isEqualToString:elementName]) {
// end of Book element, do something with bookID and bookTitle
}
}
Follow the below code.You will understand.
In your .h part
//Step 1 : Add the Delegate classes
First of all you should add <NSXMLParserDelegate>
//Step 2 : Create necessary objects
NSXMLParser *parser;
NSMutableData *ReceviedData;
NSMutableString *currentStringValue;
NSMutableArray *arrayID;
In your .m part
//Step 3 - Allocate your all Arrays in your viewDidLoad method
arrayId = [NSMutableArray alloc]init];
//Step 4 - Create Connection in your viewDidLoad Like
[self createConnection:#"http://www.google.com"];//give your valid url.
-(void)createConnection:(NSString *)urlString
{
NSURL *url = [NSURL URLWithString:urlString];
//Step 5 - parser delegate methods are using NSURLConnectionDelegate class or not.
BOOL success;
if (!parser)
{
parser = [[NSXMLParser alloc] initWithContentsOfURL:url];
parser.delegate = self;
parser.shouldResolveExternalEntities = YES;
success = [parser parse];
NSLog(#"Success : %c",success);
}
}
-(void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
{
NSLog(#"Current Element Name : %#",elementName);
if ([elementName isEqualToString:#"ID"])
{
NSLog(#"The Result is==%#",elementName);
}
}
-(void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
currentStringValue = [[NSMutableString alloc] initWithString:string];
NSLog(#"Current String Value : %#",currentStringValue);
}
-(void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
if ([elementName isEqualToString:#"ID"])
{
[arrayResult addObject:currentStringValue];
}
currentStringValue = nil;
}
I have an XML file somewhere on the web with a couple of profiles inside it and I want the number of profiles to be displayed in a textfield.
I have a textfield called: numberOfProfiles.. so what should I do in viewDidLoad?
numberOfProfiles.Text = ???
The XML file is being parsed like this:
NSMutableString *currentNodeContent;
NSXMLParser *parser;
ViewController *currentProfile;
bool isStatus;
ViewController *xmlParser;
-(id)loadXMLByURL:(NSString *)urlString
{
profile = [[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:#"firstname"])
{
currentProfile = [ViewController alloc];
isStatus = YES;
}
if([elementName isEqualToString:#"lastname"])
{
currentProfile = [ViewController alloc];
isStatus = YES;
}
if([elementName isEqualToString:#"email"])
{
currentProfile = [ViewController alloc];
isStatus = YES;
}
if([elementName isEqualToString:#"address"])
{
currentProfile = [ViewController alloc];
isStatus = YES;
}
}
-(void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
if([elementName isEqualToString:#"firstname"])
{
currentProfile->firstName = currentNodeContent;
NSLog(#"%#",currentProfile->firstName);
[profile addObject:currentProfile];
}
if([elementName isEqualToString:#"lastname"])
{
currentProfile->lastName = currentNodeContent;
NSLog(#"%#",currentProfile->lastName);
[profile addObject:currentProfile];
}
if([elementName isEqualToString:#"email"])
{
currentProfile->eMail = currentNodeContent;
NSLog(#"%#",currentProfile->eMail);
[profile addObject:currentProfile];
}
if([elementName isEqualToString:#"address"])
{
currentProfile->address = currentNodeContent;
NSLog(#"%#",currentProfile->address);
[profile addObject:currentProfile];
}
if([elementName isEqualToString:#"profiles"])
{
[self->profile addObject:currentProfile];
currentProfile = nil;
currentNodeContent = nil;
setText:currentProfile->lastName;
}
}
- (void)viewDidLoad
{
[super viewDidLoad];
xmlParser = [[ViewController alloc] loadXMLByURL:#"http://dierenpensionlindehof.nl/profiles.xml"];
}
Thanks in advance!
for just count of element you can have an instance variable like of int type numberOfProfilesCount and you can increment this in
-(void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {
numberOfProfilesCount++;
}
and in
- (void)parserDidEndDocument:(NSXMLParser *)parser {
numberOfProfiles.Text = [NSString stringWithFormate:#"%d", numberOfProfilesCount];
}
to show your element count
Assuming profile is a global variable, use [profile count] to get the number of profiles.
The try: [numberOfProfiles setText:[[profile count] stringValue]
I am trying to parse xml response and want data in NSDictionary.how can I get data in dictionary instead of NSMutableArray. Please help me ,getting response like :
<NewDataSet>
<Table>
<ID>105</ID>
<pk3>Apr 05, 2013</pk3>
<YEAR>2013</YEAR>
<TIME>09:10:46 PM</TIME>
</Table>
</NewDataSet>
Thanks in advance.
You can try with this..
.h /////////////////
#interface LoginWithTauky:UIViewController<NSXMLParserDelegate,NSURLConnectionDelegate>
{
NSXMLParser *xmlParser;
NSMutableString *soapResults;
BOOL xmlResults;
}
.m //////////////
-(void)Viewdidload
{
xmlParser = [[NSXMLParser alloc] initWithData:XMLdata];
[xmlParser setDelegate: self];
[xmlParser setShouldResolveExternalEntities: YES];
[xmlParser parse];
}
-(void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *) namespaceURI qualifiedName:(NSString *)qName
attributes: (NSDictionary *)attributeDict
{
NSLog(#"fsdfsd");
if( [elementName isEqualToString:#"Table"]||[elementName isEqualToString:#"ID"]||[elementName isEqualToString:#"pk3"]||[elementName isEqualToString:#"YEAR"]||[elementName isEqualToString:#"TIME"])
{
if(!soapResults)
{
soapResults = [[NSMutableString alloc] init];
}
xmlResults = YES;
}
}
-(void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
if( xmlResults )
{
[soapResults appendString: string];
NSLog(#"soap result %#",soapResults);
}
}
-(void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
if( [elementName isEqualToString:#"Table"])
{
xmlResults = FALSE;
[user_idArray addObject:soapResults];
soapResults = nil;
}
if( [elementName isEqualToString:#"ID"])
{
xmlResults = FALSE;
[IDArray addObject:soapResults];
soapResults = nil;
}
if( [elementName isEqualToString:#"pk3"])
{
xmlResults = FALSE;
[IDArray addObject:soapResults];
soapResults = nil;
}
if( [elementName isEqualToString:#"YEAR"])
{
xmlResults = FALSE;
[IDArray addObject:soapResults];
soapResults = nil;
}
if( [elementName isEqualToString:#"TIME"])
{
xmlResults = FALSE;
[IDArray addObject:soapResults];
soapResults = nil;
}
}
This works fine , i have tested it. Check it out
-(IBAction)parseTheXml:(id)sender
{
NSString * mystr =[[NSString alloc]initWithFormat:#"<NewDataSet>"
"<Table>"
"<ID>105</ID>"
"<pk3>Apr 05, 2013</pk3>"
"<YEAR>2013</YEAR>"
"<TIME>09:10:46 PM</TIME>"
"</Table>"
"</NewDataSet>" ];
NSData * mydata =[mystr dataUsingEncoding:NSUTF8StringEncoding];
if(!parser)
parser =[[NSXMLParser alloc]initWithData:mydata];
[parser setDelegate:self];
[parser setShouldResolveExternalEntities:YES];
BOOL success= [parser parse];
if(success)
{
NSLog(#"SUCCESS");
}
}
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
{
NSLog(#"the tag is %#",elementName);
if(!([elementName isEqualToString:#"Table"] ||[elementName isEqualToString:#"NewDataSet"]))
{
if(!dataDict)
dataDict =[[NSMutableDictionary alloc]init];
datastring =[[NSMutableString alloc]init];
}
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
datastring = [NSMutableString stringWithFormat:#"%#",string];
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
if(!([elementName isEqualToString:#"Table"] ||[elementName isEqualToString:#"NewDataSet"]))
{
if([elementName isEqualToString:#"VideoThumbnail"])
NSLog(#"the string is : %#",datastring);
[dataDict setObject:datastring forKey:elementName];
}
}
it will give you dictionary like this :
2013-12-05 16:24:05.959 parsingXML[3305:c07] the string we get is {
ID = 105;
TIME = "09:10:46 PM";
YEAR = 2013;
pk3 = "Apr 05, 2013";
}
I am trying to develop an XML parser in objective-C using the method described in http://wiki.cs.unh.edu/wiki/index.php/Parsing_XML_data_with_NSXMLParser.
I have coded up the entire flow but the delegate call back methods just won't respond!
Please take a look at the following code blocks and let me know if you could figure out any mistakes/errors...
Parser is being called from:
NSString* filePath = [[NSBundle mainBundle] pathForResource:#"cache" ofType:#"xml"];
NSLog(#"Path location is : %#",filePath);
NSData* xmlData = [NSData dataWithContentsOfFile:[NSURL URLWithString:filePath]];
NSXMLParser *nsXmlParser = [[NSXMLParser alloc] initWithContentsOfURL:xmlData];
if(nsXmlParser!=NULL)
{
NSLog(#"parser is %#",nsXmlParser);
}
HDDataXML *parser = [[HDDataXML alloc] initXMLParser];
[nsXmlParser setDelegate:parser];
BOOL success = [nsXmlParser parse];
// test the result
if (success)
{
NSLog(#"No errors - effects count : i");
} else
{
NSLog(#"Error parsing document!");
}
All I see here is Error parsing document! The filePath variable is OK and the parser is not null.
Now, in the delegate's .h file:
#import <Foundation/NSObject.h>
#import "EffectsCache.h"
#class EffectsCache;
#interface HDDataXML : NSObject<NSXMLParserDelegate>
{
EffectsCache *effectsHandler;
NSMutableString *currentElementValue;
NSMutableArray *effects;
}
- (void)parser:(NSXMLParser *)parser
didStartElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI
qualifiedName:(NSString *)qualifiedName
attributes:(NSDictionary *)attributeDict;
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string ;
- (void)parser:(NSXMLParser *)parser
didEndElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI
qualifiedName:(NSString *)qName;
- (HDDataXML *) initXMLParser;
#property (nonatomic, retain) EffectsCache *effectsHandler;
#property (nonatomic, retain) NSMutableArray *effects;
#end
And in the implementation of the delegate in .m:
#import "HDDataXML.h"
#implementation HDDataXML
#synthesize effects, effectsHandler;
- (HDDataXML *) initXMLParser
{
[super init];
effects = [[NSMutableArray alloc] init];
return self;
}
- (void)parser:(NSXMLParser *)parser
didStartElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI
qualifiedName:(NSString *)qualifiedName
attributes:(NSDictionary *)attributeDict
{
NSLog(#"started parsing");
if ([elementName isEqualToString:#"effects"]) {
NSLog(#"effects element found – create a new instance of EffectsCache class...");
effectsHandler = [[EffectsCache alloc] init];
}
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
NSLog(#"mid parsing");
if (!currentElementValue)
{
currentElementValue = [[NSMutableString alloc] initWithString:string];
}
else
{
[currentElementValue appendString:string];
}
NSLog(#"Processing value for : %#", string);
}
- (void)parser:(NSXMLParser *)parser
didEndElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI
qualifiedName:(NSString *)qName
{
NSLog(#"done parsing");
if ([elementName isEqualToString:#"effects"])
{
return;
}
if ([elementName isEqualToString:#"effect"])
{
[effectsHandler addObject:effects];
[effectsHandler release];
effectsHandler = nil;
}
else
{
NSLog(#"cuurent value - %#",currentElementValue);
[effects setValue:currentElementValue forKey:elementName];
}
[currentElementValue release];
currentElementValue = nil;
}
Point is, the call back methods are not working.
Please help me find the bug.
Thanks in advance.
nsXmlParser.delegate = self;
[nsXmlParser parse];
and dont forget in the .h file to call the delegate
<NSXMLParserDelegate>
Ok... I solved it, finally:
As suggested by Martin R, I changed the code for calling the delegate:
NSString* filePath = [[NSBundle mainBundle] pathForResource:#"effects_cache" ofType:#"xml"];
NSLog(#"Path location is : %#",filePath);
NSData* xmlData = [NSData dataWithContentsOfFile:filePath];
NSXMLParser *nsXmlParser = [[NSXMLParser alloc] initWithData:xmlData];
Before doing this modification, the xmlData was null.
One other small modification was needed:
change:
[effectsHandler addObject:effects];
TO
[effects setValue:currentElementValue forKey:elementName];