Parsing simple XML in Objective-C - objective-c

I have the following very simple XML returned from a webserver which I use ASIHttpRequest to connect to:
<element1>something</element1>
<element2>somethingelse</element2>
<element3>anotherthing</element3>
ASIHttpRequest can return it as NSData or NSString. I need to parse the information, what is the easiest way to do so?
Thanks

There are some XML parsers available for iOS NSXMLParser, libxml2 (DOM and SAX),TBXML,KissXML. You can refer http://www.raywenderlich.com/553/how-to-chose-the-best-xml-parser-for-your-iphone-project to choose best XML Parser (Speed and memory footprint). Easiest would be TBXML. NSXMLParser is easy as well.
NSXMLParser* xmlParser = [[NSXMLParser alloc] initWithData:receivedXMLData];//init NSXMLParser with receivedXMLData
[xmlParser setDelegate:self]; // Set delegate for NSXMLParser
[xmlParser parse]; //Start parsing
[xmlParser release];
//Delegate Methods
//Have a instance variable NSMutableString* currentString; to hold data between elements and NSMutableArray* elementsArray; to hold parsed data
- (void)parserDidStartDocument:(NSXMLParser *)parser
{
elementsArray = [[NSMutableArray alloc] init];
}
//store all found characters between elements in currentString mutable string
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
if(!currentString)
{
currentString = [[NSMutableString alloc] init];
}
[currentString appendString:string];
}
//When end of XML tag is found this method gets notified
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
if([elementName isEqualToString:#"element1"])
{
[elementsArray addObject:currentString];
[currentString release],currentString=nil;
return;
}
if([elementName isEqualToString:#"element2"])
{
[elementsArray addObject:currentString];
[currentString release],currentString=nil;
return;
}
if([elementName isEqualToString:#"element3"])
{
[elementsArray addObject:currentString];
[currentString release],currentString=nil;
return;
}
[currentString release],currentString =nil;
}
//Parsing has ended
- (void)parserDidEndDocument:(NSXMLParser *)parser
{
NSLog(#"Content of Elements Array: %#",elementsArray);
[elementsArray release],elementsArray=nil;
}
- (void)parser:(NSXMLParser *)parser parseErrorOccurred:(NSError *)parseError
{
UIAlertView* parseErrorAlert = [[UIAlertView alloc] initWithTitle:#"Parse Error" message:[NString stringWithFormat:"%#",[parseError localizedDescription]] delegate:nil cancelButtonTitle:#"Ok" otherButtonTitles:nil];
[parseErrorAlert show];
[parseErrorAlert release];
}
You have other delegate methods too like parseErrorOccured. Refer http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/NSXMLParser_Class/Reference/Reference.html
For TBXML : http://tbxml.co.uk/TBXML/API.html
Updated: Implemented parseError delegate method and valid xml example
XML You posted in code is not a valid XML (You can check XML validation online: http://validator.w3.org/#validate_by_input) so it will throw an parseError. Here is valid XML for XML you posted in question:
<?xml version="1.0"?>
<root>
<element1>something</element1>
<element2>somethingelse</element2>
<element3>anotherthing</element3>
</root>

Try also XMLObject. This may helps if you want to keep your cocoa style in your project.

Related

I Got the XML data ,Now how I can save the XML Data in Objective C?

As an New to the iOS Development in Xcode 7.
Below I have some questions please clarify my doubt.
I need to Store the XML Data from an URL
And Split the XML data each line and store it in the Objective C.
<?xml version="1.0" encoding="UTF-8"?>
<NewDataSet>
<tbl>
<Es_Id>8e268283-e87e-4abc-aab9-07cb611a8e60</Es_Id>
<EstablishmentType>40640054-2221-4086-92e4-4440497ccea2</EstablishmentType>
<EstablishmentName>La Parrilla Colombian Steakhouse & Bar</EstablishmentName>
<BusinessName>La Parrilla Colombian Steakhouse & Bar</BusinessName>
<OpenTime>PT8H31M</OpenTime>
<ClosingTime>PT18H50M</ClosingTime>
<Floor>12 th floor</Floor>
</tbl>
</NewDataSet>
When I start learning XML parsing it has basic steps.I implement all for you.
In ViewController.h
Step 1 : Add the Delegate classes
First you have to add <NSXMLParserDelegate>
Step 2 : Create necessary objects
NSXMLParser *parser;
NSMutableData *ReceviedData;
NSMutableString *currentStringValue;
NSMutableArray *arrayID;
Now it looks like
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController<NSXMLParserDelegate>
{
NSXMLParser *parser;
NSMutableData *ReceviedData;
NSMutableString *currentStringValue;
NSMutableArray *arrayID;
}
#end
Then in ViewController.m
Step 3 - Allocate your Array 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.
Now the viewDidLoad method is
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
arrayID = [[NSMutableArray alloc]init];
[self createConnection:#"http://www.google.com"]; //give your valid url.
}
createConnection method is
-(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);
}
}
STEP 6 - NSXMLParserDlegate Methods are below
-(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"]) //according to your xml response your id is Es_Id.So you need to compare #"Es_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"]) //according to your xml response your id is Es_Id.So you need to compare #"Es_Id"
{
[arrayResult addObject:currentStringValue];
}
currentStringValue = nil;
}
From above code I check ID only.According to your response you need to compare other keys like EstablishmentType,EstablishmentName,BusinessName,OpenTime.......

XML Parsing issue in Xcode?

I am making a mac application, and I need it to parse a local xml file and display it into a tableView. For some reason, I get a blank row in my tableView, which makes no sense, as it has found characters that are in my xml. Here is my code:
- (void)parserDidStartDocument:(NSXMLParser *)parser{
NSLog(#"found file and started parsing");
}
- (void)parseXMLFileAtURL:(NSString *)URL
{
//you must then convert the path to a proper NSURL or it won't work
NSURL *xmlURL = [NSURL URLWithString:URL];
// here, for some reason you have to use NSClassFromString when trying to alloc NSXMLParser, otherwise you will get an object not found error
// this may be necessary only for the toolchain
rssParser = [[NSXMLParser alloc] initWithContentsOfURL:xmlURL];
// Set self as the delegate of the parser so that it will receive the parser delegate methods callbacks.
[rssParser setDelegate: self];
// Depending on the XML document you're parsing, you may want to enable these features of NSXMLParser.
[rssParser setShouldProcessNamespaces:NO];
[rssParser setShouldReportNamespacePrefixes:NO];
[rssParser setShouldResolveExternalEntities:NO];
[rssParser parse];
}
- (void)parser:(NSXMLParser *)parser parseErrorOccurred:(NSError *)parseError {
NSString * errorString = [NSString stringWithFormat:#"Unable to download XML feed (Error code %i )", [parseError code]];
NSLog(#"Error parsing XML: %#", errorString);
}
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict{
//NSLog(#"found this element: %#", elementName);
currentElement = [elementName copy];
if ([elementName isEqualToString:#"event"]) {
// clear out our story item caches...
item = [[NSMutableDictionary alloc] init];
date = [[NSMutableString alloc] init];
opponent = [[NSMutableString alloc] init];
location = [[NSMutableString alloc] init];
time = [[NSMutableString alloc] init];
games = [[NSMutableString alloc] init];
}
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName{
NSLog(#"ended element: %#", elementName);
if ([elementName isEqualToString:#"event"]) {
// save values to an item, then store that item into the array...
[item setObject:date forKey:#"date"];
[item setObject:opponent forKey:#"opponent"];
[item setObject:location forKey:#"location"];
[item setObject:time forKey:#"time"];
[item setObject:games forKey:#"games"];
NSMutableArray *stories = [[NSMutableArray alloc] init];
[stories addObject:[item copy]];
[arrayController addObject:[NSDictionary dictionaryWithObjectsAndKeys:
date, #"date",
opponent, #"opponent",
location, #"location",
time, #"time",
games, #"games"
, nil]];
}
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string{
//NSLog(#"found characters: %#", string);
// save the characters for the current item...
if ([date isEqualToString:#"date"]) {
[date appendString:string];
} else if ([opponent isEqualToString:#"opponent"]) {
[opponent appendString:string];
} else if ([location isEqualToString:#"location"]) {
[location appendString:string];
} else if ([time isEqualToString:#"time"]) {
[time appendString:string];
} else if ([games isEqualToString:#"games"]) {
[games appendString:string];
}
}
- (void)parserDidEndDocument:(NSXMLParser *)parser {
NSLog(#"all done!");
[tabelview reloadData];
}
When i remove my adding part, where it adds item to the arraycontroller, and add
[arrayController addObject:stories]; I get a buch of ('s
If there is anything else you need, do not just down-vote, and instead tell me. Thanks!
Here is my xml:
<?xml version="1.0" encoding="ISO-8859-1"?>
<xmlData>
<event>
<date>date here</date>
<opponent>opponent here</opponent>
<location>location here</location>
<time>time here</time>
<games>games here</games>
</event>
<event>
<date>date here</date>
<opponent>opponent here</opponent>
<location>location here</location>
<time>time here</time>
<games>games here</games>
</event>
<event>
<date>date here</date>
<opponent>opponent here</opponent>
<location>location here</location>
<time>time here</time>
<games>games here</games>
</event>
<event>
<date>date here</date>
<opponent>opponent here</opponent>
<location>location here</location>
<time>time here</time>
<games>games here</games>
</event>
</xmlData>
The error is in your parser. Please revise the logic. You are not using your object item when filling your table view array. Also, you are not catching the text in between the XML elements and are not assigning them to the appropriate variables.
Note the following:
When you enter an element, keep track of which element you are in currently
When you find characters you have to fill the appropriate attribute variable according to which element you are in
When you finish the event element, you should add your item with all its filled in keys into your data array.
You need to know how to use array. You are allocating one array stories. But then not using. Please Check your didEndElement method.
Make one class of Event, create .h and .m file and then create properties of your all element and then add whole object of Event class into an array. That array you can in appHandler or Single ton class.
Check this thing. May it help you.

Parsing XML into NSManagedObjects using categories and what to do with properties in categories?

Based on the excellent example "Parsing XML with NSXMLParser" in the book "The Big Nerd Ranch Guide" (3rd ed.), I haved added categories to my NSManagedObjects for which I want to add XML parsing. These categories provide only parsing functionality.
This is how I have implemented these categories:
.h:
#import "IBCompany.h"
#interface IBCompany (Xml) <NSXMLParserDelegate>
- (void)parseXmlString:(NSString*)xmlStr withCompletion:(void(^)(NSError *error))completionBlock;
#end
.m:
#implementation IBCompany (Xml)
- (void)parseXmlString:(NSString*)xmlStr withCompletion:(void(^)(NSError *error))completionBlock;
{
NSData *xmlData = [xmlStr dataUsingEncoding:NSUTF8StringEncoding];
NSXMLParser *parser = [[NSXMLParser alloc]initWithData:xmlData];
parser.delegate = self;
[parser parse];
xmlData = nil;
NSError *error;
completionBlock(error);
}
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
{
if ([elementName isEqualToString:#"Issue"]) {
IBIssue *issue = [NSEntityDescription insertNewObjectForEntityForName:#"IBIssue" inManagedObjectContext:self.managedObjectContext];
issue.company = self;
issue.parentParserDelegate = self;
parser.delegate = issue;
}
As you can see in this code snippet, I switch the parser delegate to other subclasses / XML child elements to have them further process the next XML elements, which belong to them until the end of the XML element is reached and the delegate is set back to the parent.
This is why I need to store the parent delegate in the child. However, ivars and properties are not allowed in categories.
I came up with this solution which seems to circumvent this problem:
Child element, h:
#import "IBIssue.h"
#interface IBIssue (Xml) <NSXMLParserDelegate>
#property id parentParserDelegate;
#end
#import "IBIssue+Xml.h"
#implementation IBIssue (Xml)
NSMutableString *currentString;
NSString *currentXmlDocument;
id _parentParserDelegate;
- (id)parentParserDelegate
{
return _parentParserDelegate;
}
- (void)setParentParserDelegate:(id)parentParserDelegate;
{
_parentParserDelegate = parentParserDelegate;
}
- (NSDateFormatter*)dateFormatter
{
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setLocale:[[NSLocale alloc] initWithLocaleIdentifier:#"en_US_POSIX"]];
[dateFormatter setDateFormat:#"yyy-MM-dd"];
[dateFormatter setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT: 0]];
return dateFormatter;
}
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
{
if ([elementName isEqualToString:#"IssueID"]) {
currentString = [[NSMutableString alloc]init];
if ([attributeDict[#"Type"] isEqualToString:#"Ticker"]) self.ticker = currentString;
else if ([attributeDict[#"Type"] isEqualToString:#"Name"]) self.issueName = currentString;
else if ([attributeDict[#"Type"] isEqualToString:#"CUSIP"]) self.cusip = currentString;
else if ([attributeDict[#"Type"] isEqualToString:#"ISIN"]) self.isin = currentString;
else if ([attributeDict[#"Type"] isEqualToString:#"RIC"]) self.ric = currentString;
else if ([attributeDict[#"Type"] isEqualToString:#"SEDOL"]) self.sedol = currentString;
else if ([attributeDict[#"Type"] isEqualToString:#"DisplayRIC"]) self.displayRic = currentString;
else if ([attributeDict[#"Type"] isEqualToString:#"InstrumentPI"]) ; //
else if ([attributeDict[#"Type"] isEqualToString:#"QuotePI"]) ; //
} else if ([elementName isEqualToString:#"Exchange"]) {
currentString = [[NSMutableString alloc]init];
self.exchangeCode = attributeDict[#"Code"];
self.exchangeCountry = attributeDict[#"Country"];
self.exchange = currentString;
} else if ([elementName isEqualToString:#"MostRecentSplit"]) {
currentString = [[NSMutableString alloc]init];
self.mostRecentSplitDate = [self.dateFormatter dateFromString:attributeDict[#"Date"]];
// self.mostRecentSplit = [NSNumber numberWithFloat: currentString.floatValue];
}
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
// NSLog(#"appendString: %#", string);
[currentString appendString:string];
}
-(void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
if ([elementName isEqualToString:#"Issue"]) {
parser.delegate = self.parentParserDelegate;
} else if ([elementName isEqualToString:#"MostRecentSplit"]) {
self.mostRecentSplit = [NSNumber numberWithFloat: currentString.floatValue];
}
currentString = nil;
}
#end
I save the delegate to the parent in a variable _parentDelegate which is declared outside the ivar declaration block and does not seem to be a real ivar.
This code works well in my tests and I wonder if I missed something which will turn out to become a problem later in the development process or if this design is ok.
What are your thoughts on that?
Thank you!
I'm not sure how the compiler will treat that variable. Could it be allocated so that only one variable is shared by all objects of this type? If your XML is parsed such that more than one IBCompany exists at a point in time it could cause a problem. I'd write a test that allocated two IBCompany objects, cause them both to write different values to _parentDelegate, then assert the values are different.
Or ignore the issue if there is no possibility that two IBCompany objects are parsed in parallel. You'd have to ensure that the XML can't have an IBCompany inside another IBCompany, multiple parts of the XML will not be processed in parallel, and that multiple XML documents will not be processed in parallel.
I don't see the need for a category. Categories are useful when you shouldn't write a subclass to an existing class, such as adding functionality to classes in the Cocoa framework. You are writing a custom subclass, so why not add the ivar to your subclass? You can have additional ivars in managed objects that are not saved in the Core Data backing stores. At most I'd just use an extension to segregate XML parsing code from the rest of the managed object.

Parsing XML files with special characters

I try to parse a list of persons and pollute a UITableView with the names. But the persons I want to parse have special character (ä, ö, ü). Now if I start parsing the name "Gött" it is "ött" afterwards. Really strange, any ideas? Thanks a lot!
-(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 didStartElement:(NSString *)elementname namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
{
if ([elementname isEqualToString:#"lehrer"])
{
currentTweet = [Tweet alloc];
}
}
- (void) parser:(NSXMLParser *)parser didEndElement:(NSString *)elementname namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
if ([elementname isEqualToString:#"name"])
{
currentTweet.content = currentNodeContent;
}
if ([elementname isEqualToString:#"vorname"])
{
currentTweet.vorname = currentNodeContent;
}
if ([elementname isEqualToString:#"created_at"])
{
currentTweet.dateCreated = currentNodeContent;
}
if ([elementname isEqualToString:#"lehrer"])
{
[tweets addObject:currentTweet];
[currentTweet release];
currentTweet = nil;
[currentNodeContent release];
currentNodeContent = nil;
}
}
- (void) parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
currentNodeContent = (NSMutableString *) [string stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
}
- (void) dealloc
{
[parser release];
[super dealloc];
}
#end
This is normal behaviour - parser:foundCharacters can be called multiple times for one string (and tends to be for accented characters). Your string isn't complete until the end of the element, so store them and use the full string when you get to the end of the block.
It is in the documentation for foundCharacters
Apple developer docs on NSXMLParser
The parser object may send the delegate several parser:foundCharacters: messages to report the characters of an element. Because string may be only part of the total character content for the current element, you should append it to the current accumulation of characters until the element changes.
Edit as per question:
the code in general is fine but in the characters function, do
- (void) parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
if(nil == currentNodeContent)
currentNodeContent = [[NSMutableString alloc] initWithString:string];
else
[currentNodeContent appendString:string];
}
then in both didStart and didEnd call a method that checks to see if the string is nil, do whatever it was you were going to do with it in the first place, and then release the string (and null it).
The string is ended at both the start of a new element (ie, the text before an opening <), and at the end (the bit of text before the
As per Woody's answer, this is completely expected. You will need to concatenate the strings from the multiple - (void) parser:(NSXMLParser *)parser foundCharacters:(NSString *)string calls.
The correct way to do this is as follows:
- (void) parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
if (currentElementContent== nil)
currentElementContent = [[NSMutableString alloc] initWithString:string];
else
currentElementContent = [currentElementContent stringByAppendingString:string];
}
You should always be setting the currentElementContent to nil at the very end of the didEndElement method anyway. An example for this is below:
- (void) parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
// Do what you want with the parser here
// Set element content variable to nil
currentElementContent = nil;
}
You may need to replace the variable: currentElementContent with whatever variable you have used in your parser to house the content found between the start and end tags.

iOS: Parsing a xml from HTTP using NSXMLParser for

It's first time using NSXMLParser and wondering if you give me some direction of parsing the returned xml from an http request that looks like:
<?xml version="1.0" ?>
<theresponse>
<status>OK</status>
<pricing currency="USD" symbol="$">
<price class="items">24.00</price>
<price class="shipping">6.00</price>
<price class="tax">1.57</price>
</pricing>
</theresponse>
I know the basic of parsing delegate methods, I just want to know what the code would look like in didEndElement/foundCharacters/didStartElement for retreiving above items(currency/items/shipping/tax)? any help greatly appreciated.
This is a little more tricky than some standard NSXMLParser code; Because essentially when you are looking for the "shipping" you want "6.00" but those two pieces of data are returned to you in different delegate methods, which is normal. But usually the element would be named "shipping" so in parser:didEndElement:namespaceURI:qualifiedName: you would automatically have the element name as it was passed into the method.
The solution would seem simple, have a _currentAttributes ivar and in parser:didStartElement:namespaceURI:qualifiedName:attributes: do something like _currentAttributes = attributeDict; and then handle this in the didEndElement: method. However this style would easily break, even on this moderately simple XML.
My way of handling this would be to store the attributes dictionary passed into the didStartElement: and set it in a dictionary as the object for the key of the element name. Combining this style with the standard use of an NSMutableString as a characterBuffer of sorts allows you to put all of your logic into the didEndElement: method.
Side note: I am also quite fond of having my NSXMLParserDelegate classes be NSXMLParser subclasses, as this one is. However the delegate methods would be identical if it were not.
ItemParser.h
#import <Foundation/Foundation.h>
#interface ItemParser : NSXMLParser <NSXMLParserDelegate>
#property (readonly) NSDictionary *itemData;
#end
ItemParser.m
#import "ItemParser.h"
#implementation ItemParser {
NSMutableDictionary *_itemData;
NSMutableDictionary *_attributesByElement;
NSMutableString *_elementString;
}
-(NSDictionary *)itemData{
return [_itemData copy];
}
-(void)parserDidStartDocument:(NSXMLParser *)parser{
_itemData = [[NSMutableDictionary alloc] init];
_attributesByElement = [[NSMutableDictionary alloc] init];
_elementString = [[NSMutableString alloc] init];
}
-(void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict{
// Save the attributes for later.
if (attributeDict) [_attributesByElement setObject:attributeDict forKey:elementName];
// Make sure the elementString is blank and ready to find characters
[_elementString setString:#""];
}
-(void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string{
// Save foundCharacters for later
[_elementString appendString:string];
}
-(void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName{
if ([elementName isEqualToString:#"status"]){
// Element status only contains a string i.e. "OK"
// Simply set a copy of the element value string in the itemData dictionary
[_itemData setObject:[_elementString copy] forKey:elementName];
} else if ([elementName isEqualToString:#"pricing"]) {
// Pricing has an interesting attributes dictionary
// So copy the entries to the item data
NSDictionary *attributes = [_attributesByElement objectForKey:#"pricing"];
[_itemData addEntriesFromDictionary:attributes];
} else if ([elementName isEqualToString:#"price"]) {
// The element price occurs multiple times.
// The meaningful designation occurs in the "class" attribute.
NSString *class = [[_attributesByElement objectForKey:elementName] objectForKey:#"class"];
if (class) [_itemData setObject:[_elementString copy] forKey:class];
}
[_attributesByElement removeObjectForKey:elementName];
[_elementString setString:#""];
}
-(void)parserDidEndDocument:(NSXMLParser *)parser{
_attributesByElement = nil;
_elementString = nil;
}
-(void)parser:(NSXMLParser *)parser parseErrorOccurred:(NSError *)parseError{
NSLog(#"%# with error %#",NSStringFromSelector(_cmd),parseError.localizedDescription);
}
-(BOOL)parse{
self.delegate = self;
return [super parse];
}
#end
And so to test I stored the XML you posted above into a file named "ItemXML.xml". And tested it using this code:
NSURL *url = [[NSBundle mainBundle] URLForResource:#"ItemXML" withExtension:#"xml"];
ItemParser *parser = [[ItemParser alloc] initWithContentsOfURL:url];
[parser parse];
NSLog(#"%#",parser.itemData);
The result I got was:
{
currency = USD;
items = "24.00";
shipping = "6.00";
status = OK;
symbol = "$";
tax = "1.57";
}