NSXMLParser not finding closing tag - ios

Im trying to fetch list of content from xml web source . Im using NSXMLParser atm.
here is the code :
- (void)main
{
self.workingArray = [NSMutableArray array];
self.workingPropertyString = [NSMutableString string];
NSURL *url = [[NSURL alloc]initWithString:#"http://myxmlwebsite.xml"];
NSXMLParser *parser = [[NSXMLParser alloc]initWithContentsOfURL:url];
[parser setDelegate:self];
bool result = [parser parse];
NSLog(#"result is ok for xml parse : %#", result ? #"Yes" : #"No");
if (![self isCancelled])
{
self.appRecordList = [NSArray arrayWithArray:self.workingArray];
SubCategoryViewController *subCategoryViewController;
subCategoryViewController.entries = self.appRecordList;
[subCategoryViewController.tableView reloadData];
}
self.workingArray = nil;
self.workingPropertyString = nil;
self.dataToParse = nil;
}
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI
qualifiedName:(NSString *)qName
attributes:(NSDictionary *)attributeDict
{
if ([elementName isEqualToString:kUser])
{
self.workingEntry = [[UserFetchAppRecord alloc] init];
}
_elementsToParse = [[NSArray alloc] initWithObjects:
kid,ktitle, nil];
self.storingCharacterData = [_elementsToParse containsObject:elementName];
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI
qualifiedName:(NSString *)qName
{
if (self.workingEntry)
{
if (self.storingCharacterData)
{
NSString *trimmedString = [self.workingPropertyString stringByTrimmingCharactersInSet:
[NSCharacterSet whitespaceAndNewlineCharacterSet]];
[self.workingPropertyString setString:#""];
if ([elementName isEqualToString:kid])
{
self.workingEntry.ids = trimmedString;
NSLog(#"id : %#" , trimmedString);
}
else if ([elementName isEqualToString:ktitle])
{
self.workingEntry.title = trimmedString;
NSLog(#"ktitle : %#" , trimmedString);
}
}
else if ([elementName isEqualToString:kUser])
{
NSLog(#"inside elementName isEqualToString:kUser");
[self.workingArray addObject:self.workingEntry];
NSUInteger self_workingArrayCount = [self.workingArray count];
self.workingEntry = nil;
}
}
}
Now at console if i run program i get these results :
"result is ok for xml parse = true"
"id : 1"
"ktitle : usertitle"
.
.
.
but the result of closing tab no showing in console, this one "inside elementName isEqualToString:kUser".
hows that possible ?
the tag of my xml are like this :
<Main>
<user>
<id></id>
<title></title>
</user>
<user>
<id></id>
<title></title>
</user>
.....
</Main>

Change else if ([elementName isEqualToString:kUser]) in
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI
qualifiedName:(NSString *)qName
to if ([elementName isEqualToString:kUser]).
self.storingCharacterData become YES when element id or title starts. So when element user ends self.storingCharacterData will be YES, and else if ([elementName isEqualToString:kUser]) wont work.

Related

How can I parse this xml in iOS 7?

I want to parse this XML:
<?xml version="1.0" encoding="UTF-8"?>
<eventdata>
<rev></rev>
<event>
<id> </id>
<name></name>
<thumb> </thumb>
<eimage></eimage>
<artists></artists>
<date></date>
<time> </time>
<cost> </cost>
<discount> </discount>
<gmap> </gmap>
<web> </web>
<desc> </desc>
<file>
<src> </src>
<size> </size>
</file>
<vtype></vtype>
<address></address>
<area></area>
<city></city>
<pcode></pcode>
<lmark></lmark>
<likes></likes>
<hl></hl>
<pref></pref>
<img> <src> </src>
<size> </size></img>
<vid> <src> </src>
<size> </size></vid>
</event>
<event>
<id> </id>
<name></name>
<thumb> </thumb>
<eimage></eimage>
<artists></artists>
<date></date>
<time> </time>
<cost> </cost>
<discount> </discount>
<gmap> </gmap>
<web> </web>
<desc> </desc>
<file>
<src> </src>
<size> </size>
</file>
<vtype></vtype>
<address></address>
<area></area>
<city></city>
<pcode></pcode>
<lmark></lmark>
<likes></likes>
<hl></hl>
<pref></pref>
<img> <src> </src>
<size> </size></img>
<vid> <src> </src>
<size> </size></vid>
</event>
</eventdata>
I tried this code:
- (void)viewDidLoad
{
[super viewDidLoad];
_currentParsedCharacterData = [[NSMutableString alloc] init];
NSString *path = [[NSBundle mainBundle] pathForResource:#"NewYearPartyData" ofType:#"xml"];
NSData *data = [[NSData alloc] initWithContentsOfFile:path];
NSXMLParser *parser = [[NSXMLParser alloc] initWithData:data];
[parser setDelegate:self];
// parsing...
BOOL success = [parser parse];
// test the result
if (success) {
//NSLog(#"No errors - user count : %i", [parser [users count]]);
NSLog(#"Success");
// get array of users here
// NSMutableArray *users = [parser users];
} else {
NSLog(#"Error parsing document!");
}
}
#pragma mark - NSXMLParser delegate methods
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict {
if ([elementName isEqualToString:#"event"]) {
NSLog(#"user element found – create a new instance of User class...");
//user = [[User alloc] init];
//We do not have any attributes in the user elements, but if
// you do, you can extract them here:
// user.att = [[attributeDict objectForKey:#"<att name>"] ...];
NSLog(#"Event Name = %#", [attributeDict objectForKey:#"name"]);
NSLog(#"attributeDict = %#", attributeDict);
}
if ([elementName isEqualToString:#"name"]) {
NSLog(#"attributeDict = %#", attributeDict);
NSLog(#"Event Name = %#", [attributeDict objectForKey:#"name"]);
NSLog(#"elementName = %#", elementName);
}
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {
NSLog(#"didEndElement");
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
NSLog(#"value of element %#", string);
}
- (void)parser:(NSXMLParser *)parser parseErrorOccurred:(NSError *)parseError {
}
Someone who is good in NSXMLParser - I request them to explain to me the flow.
My basic question is "How to access data of event i.e., id, name, thumb etc?"
NSXMLParsing is the easiest way to parse data. You can easily access data of event i.e., id, name, thumb etc using the delegate method
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {
}
You can create a NSOBject class named Event.
Here is my code
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {
if ([elementname isEqualToString:#"id"])
{
event.id = currentNodeContentChapters;
}
if ([elementname isEqualToString:#"name"])
{
event.name = currentNodeContentChapters;
}
if ([elementname isEqualToString:#"thumb"])
{
event.thumb = currentNodeContentChapters;
}
if ([elementname isEqualToString:#"eiimage"])
{
event.eiimageUrl = currentNodeContentChapters;
}
-------------------
---------------
}
Hopefully it will work for you .

How to parse SOAP xml response in iPhone programming

I am unable to parse soap response,I have tried many ways but not solved my problem,I need the value of USERNAME and PASSWORD.
I am getting following response after soap request :
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Body>
<AuthenticateResponse xmlns="http://tempuri.org/">
<AuthenticateResult>
<DocumentElement>
<Status>
<USERNAME>True</USERNAME>
<PASSWORD>true</PASSWORD>
</Status>
</DocumentElement>
</AuthenticateResult>
</AuthenticateResponse>
</soap:Body>
</soap:Envelope>
Here is my code :
-(void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *) namespaceURI qualifiedName:(NSString *)qName attributes: (NSDictionary *)attributeDict
{
if ( [elementName isEqualToString:#"AuthenticateResponse"]||[elementName
isEqualToString:#"AuthenticateResult"] || [elementName isEqualToString:#"DocumentElement"])
{
statusArray = [[NSMutableArray alloc] init];
}
else if ([elementName isEqualToString:#"Status"])
{
authenticate = [[Authenticate alloc] init];
}
else if ([elementName isEqualToString:#"USERNAME"])
{
currentElementValue = [[NSMutableString alloc] init];
}
else if ([elementName isEqualToString:#"PASSWORD"])
{
currentElementValue = [[NSMutableString alloc] init];
}
}
-(void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
if (currentElementValue)
{
[currentElementValue appendString:string];
}
}
-(void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI: (NSString *)namespaceURI qualifiedName:(NSString *)qName
{
if( [elementName isEqualToString:#"USERNAME"])
{
authenticate.userName = currentElementValue;
}
else if ([elementName isEqualToString:#"PASSWORD"])
{
authenticate.strAuthenticate = currentElementValue;
}
else if ([elementName isEqualToString:#"Status"]) {
[statusArray addObject:authenticate];
}
}
How can i get the values of username and password,can someone help me to parse this.
Thanks in advance.
Try this:
Add 2 properties to your class.
#property (nonatomic, strong) NSString *elementValue;
#property (nonatomic, strong) NSMutableArray *authenticationValues;
Replace your current implementation by:
- (void)parseXML:(NSData *)xmlData {
self.authenticationValues = [NSMutableArray array];
NSXMLParser *parser = [[NSXMLParser alloc] initWithData:xmlData];
parser.delegate = self;
[parser parse];
NSLog(#"Authentication values: %#", self.authenticationValues);
}
-(void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
// Keep track of the current element value
self.elementValue = string;
}
-(void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
// If the element was 'username' or 'password', add the value to the authenticationValues array
if ([elementName isEqualToString:#"USERNAME"] ||
[elementName isEqualToString:#"PASSWORD"]) {
[self.authenticationValues addObject:self.elementValue];
}
}
To parse the file perform the method parseXML:
When running this you should see the following output on the console:
Authentication values: (
True,
true
)
which are the values for USERNAME and PASSWORD.
Please see the demo prepared for iOS/OSX using sample web service.
It uses swift - SOAP request creator & response parser.
[DEMO][1]
Done using Alamofire & SWXMLHash library
Thanks

How to grab an XML element and store it? Objective C

I am trying to grab a token from a website. Upon successful authentication, an XML document would be displayed.
I created a connection as shown below:
NSString *strURLQueryString = [NSString stringWithFormat:#"%#?username=%#&password=%#", kURL_LOGIN, nameString, passwordString];
NSURLRequest *theRequest = [NSURLRequest requestWithURL:[NSURL URLWithString:strURLQueryString]
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:60.0];
In order to display the output, I used this:
unsigned char byteBuffer[[receivedData length]];
[receivedData getBytes:byteBuffer];
NSLog(#"Output: %s", (char *)byteBuffer);
So some of the output of the returned document is as shown below:
<status>0</status><reason>User fetched.</reason><token>9cb7396dccabe68c067521db219afb83</token>
I have read many XML parsing implementation but I just could not implement it as it does not fulfil my need, and I just could not understand the complexity of its explanation.
Would appreciate if anyone could give me a good advice on how to go about.
- (XMLParserViewController *) initXMLParser {
appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
return self;
}
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qualifiedName
attributes:(NSDictionary *)attributeDict
{
if([elementName isEqualToString:#"Books"]) {
appDelegate.books = [[NSMutableArray alloc] init];
}
else if([elementName isEqualToString:#"Book"])
{
aBook = [[Books 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:#"Books"])
return;
if([elementName isEqualToString:#"Book"])
{
[appDelegate.books addObject:aBook];
aBook = nil;
}
else if([elementName isEqualToString:#"name"])
{
aBook.name=currentElementValue;
}
else if([elementName isEqualToString:#"address"])
{
aBook.address=currentElementValue;
}
else if([elementName isEqualToString:#"country"])
{
aBook.country=currentElementValue;
}
currentElementValue = nil;
NSLog(#"%#",aBook.name);
NSLog(#"%#",aBook.address);
NSLog(#"%#",aBook.country);
}
Try this ,, I hope this works....
The relevant NSXMLParserDelegate methods:
-(void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName //etc
{ _inToken = [elementName isEqualToString:#"token"]; }
-(void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName //etc
{ _inToken = NO; }
-(void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
if (_inToken) {
_token = string;
[parser abortParsing];
}
}
You should use XML parser.
It is easy to use, go all below steps to get best result:
Create XMLParser class subclasses from NSXMLParser, so you have a NSXMLParser.h and NSXMLParser.m class
your .h class must be like this:
#import <Foundation/Foundation.h>
#interface XMLParser : NSXMLParser <NSXMLParserDelegate>{
NSUInteger parsedCounter;
BOOL accumulatingParsedCharacterData;
BOOL didAbortParsing;
}
#property (nonatomic, strong) NSMutableString *currentParsedCharacterData;
#property (nonatomic, strong) NSMutableArray *currentParsedCharacterArray;
#end
And .m class :
#import "XMLParser.h"
#implementation XMLParser
#pragma mark Parser constants
// Limit the number of parsed data to 100.
static const NSUInteger kMaximumNumberOfFilesToParse = 100;
static NSUInteger const kSizeOfFileBatch = 10;
// Reduce potential parsing errors by using string constants declared in a single place.
static NSString * const kEntryElementName = #"dlResult";
static NSString * const kStringElementName = #"string";
#pragma mark NSXMLParser delegate methods
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict {
// NSLog(#"didStart");
// If the number of parsed earthquakes is greater than kMaximumNumberOfEarthquakesToParse, abort the parse.
if (parsedCounter >= kMaximumNumberOfFilesToParse) {
// Use the flag didAbortParsing to distinguish between this deliberate stop and other parser errors.
didAbortParsing = YES;
[self abortParsing];
}
if ([elementName isEqualToString:kEntryElementName]) {
_currentParsedCharacterArray = [[NSMutableArray alloc]init];
} else if ([elementName isEqualToString:kStringElementName]) {
accumulatingParsedCharacterData = YES;
_currentParsedCharacterData = [[NSMutableString alloc]init];
}
}
// return string between tags
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
// NSLog(#"foundCh");
if (accumulatingParsedCharacterData) {
// If the current element is one whose content we care about, append 'string'
// to the property that holds the content of the current element.
[_currentParsedCharacterData appendString:string];
NSLog(#"currentParsedCharacterData:%#",_currentParsedCharacterData);
}
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {
// NSLog(#"didEnd");
if ([elementName isEqualToString:kStringElementName]) {
[_currentParsedCharacterArray addObject:_currentParsedCharacterData];
}
accumulatingParsedCharacterData = NO;
}
- (void)parser:(NSXMLParser *)parser parseErrorOccurred:(NSError *)parseError {
if (didAbortParsing == NO) {
// Pass the error to the main thread for handling.
[self performSelectorOnMainThread:#selector(handleError:) withObject:parseError waitUntilDone:NO];
}
}
#end
In .m class there are two const string:
static NSString * const kEntryElementName = #"dlResult";
static NSString * const kStringElementName = #"string";
those are string tags,the tags that you should implement are "status", "reason" "token"
from connection class, send data connection to XMLParser class like below:
#autoreleasepool {
// It's also possible to have NSXMLParser download the data, by passing it a URL, but this is not desirable
// because it gives less control over the network, particularly in responding to connection errors.
//
XMLParser *parser = [[XMLParser alloc] initWithData:data];
parser.currentParsedCharacterArray = [NSMutableArray array];
parser.currentParsedCharacterData = [NSMutableString string];
[parser setDelegate:parser];
[parser parse];
// depending on the total number of earthquakes parsed, the last batch might not have been a "full" batch, and thus
// not been part of the regular batch transfer. So, we check the count of the array and, if necessary, send it to the main thread.
if ([parser.currentParsedCharacterArray count] > 0) {
// send parsed data to another class or ...
// parser.currentParsedCharacterArray is parsed data
}
parser.currentParsedCharacterArray = nil;
parser.currentParsedCharacterData = nil;
}
if you have any question, ask me!

IOS: NSMXLParser with multiple node

I have a file xml as this:
<data>
<first>
<city>
city
</city>
<people>
400
</people>
</first>
<size>
<width>
340
</width>
<height>
120
</height>
</size>
<description>
<temp>
sunny
</temp>
<people>
45
</people>
</description>
<description>
<temp>
cloudy
</temp>
<people>
90
</people>
</description>
I use for parsing this code:
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict{
currentElement = [elementName copy];
if ([elementName isEqualToString:#"first"]) {
firstType = [[NSMutableDictionary alloc] init];
currentCity = [[NSMutableString alloc] init];
currentPeople = [[NSMutableString alloc] init];
}
if ([elementName isEqualToString:#"size"]){
currentSize = [[NSMutableDictionary alloc] init];
width = [[NSMutableString alloc]init];
height = [[NSMutableString alloc]init];
}
if ([elementName isEqualToString:#"description"]){
desc1 = [[NSMutableDictionary alloc] init];
temp1 = [[NSMutableString alloc]init];
people1 = [[NSMutableString alloc]init];
}
if ([elementName isEqualToString:#"description"]){
desc2 = [[NSMutableDictionary alloc] init];
temp2 = [[NSMutableString alloc]init];
people2 = [[NSMutableString alloc]init];
}
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName{
if ([elementName isEqualToString:#"first"]) {
[firstType setObject:currentType forKey:#"city"];
[firstType setObject:currentQuery forKey:#"people"];
[feed addObject:[firstType copy]];
}
if ([elementName isEqualToString:#"size"]){
[currentSize setObject:tempC forKey:#"width"];
[currentSize setObject:tempF forKey:#"height"];
[feed addObject:[currentSize copy]];
}
if ([elementName isEqualToString:#"description"]){
[desc1 setObject:temp1 forKey:#"temp1"];
[desc1 setObject:people1 forKey:#"people1"];
[feed addObject:[desc1 copy]];
}
if ([elementName isEqualToString:#"description"]){
[desc2 setObject:temp1 forKey:#"temp2"];
[desc2 setObject:people1 forKey:#"people2"];
[feed addObject:[desc2 copy]];
}
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string{
NSLog(#"found");
if ([currentElement isEqualToString:#"city"]){
[currentCity appendString:string];
}
else if ([currentElement isEqualToString:#"people"]) {
[currentPeople appendString:string];
}
else if ([currentElement isEqualToString:#"width"]){
[width appendString:string];
}
else if ([currentElement isEqualToString:#"height"]){
[height appendString:string];
}
else if ([currentElement isEqualToString:#"temp"]){
[temp1 appendString:string];
}
else if ([currentElement isEqualToString:#"temp"]){
[temp2 appendString:string];
}
else if ([currentElement isEqualToString:#"people"]){
[people1 appendString:string];
}
else if ([currentElement isEqualToString:#"people"]){
[people2 appendString:string];
}
}
- (void) parserDidEndDocument:(NSXMLParser *)parser {
NSLog(#"feed:%#",feed);
}
the result of nslog is:
feed:(
{
city = city;
people = 4004590;
},
{
width = 340;
height = 120;
},
{
temp = sunny;
people = "";
},
{ ///???? here there is an empty space
},
{
temp = cloudy;
people = "";
},
{
}
)
Now I don't understand why there is a space between first dictionary of desc 1 and desc2, and I don't know how "people" take the result of people1 and people2 in a single string
Can you help me?
I guess your problem is in duplicated chunks of code such as:
else if ([currentElement isEqualToString:#"temp"]){
[temp1 appendString:string];
}
else if ([currentElement isEqualToString:#"temp"]){
[temp2 appendString:string];
}
In this case your first part of code will executed twice and second never.
Check also another parts of your code, yo have several blocks with this issue.
You need to keep track of whether you are parsing the first occurrence of description within the data tag, or the second. This can easily be done with a boolean (if there are only two), or an integer (for multiple) that indicates which of the tags you are currently processing. Then, in the parser:didEndElement: method, you can assign the accumulated data to the correct dictionary based on the flag/counter.
The other possibility, which I use in my XML parsing, is to accumulate characters for one tag at a time, then when I encounter the closing element for that tag, store the characters into the containing element's Dictionary right then. In other words, when I encounter the endTag for temp, I will immediately assign it to the current description tag's dictionary. Then, when I encounter the ending tag for the description tag itself, I can close out that dictionary, set the flag/increment the counter, and continue on with the next tag that is to be parsed.
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
{
// ... SNIP ...
if ( [ elementName isEqualToString:#"description" ] )
{
curDescription = [ [ NSMutableDictionary alloc ] init ] ;
}
// ... SNIP ...
accumulatedCharacters = [ [ NSMutableString alloc ] init ]
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
// ... SNIP ...
if ( [ elementName isEqualToString:#"temp" ] )
{
[ curDescription setValue:accumulatedCharacters forKey:#"temp" ] ;
}
if ( [ elementName isEqualToString:#"description" ] )
{
// Save the curDescription object, then clear it for reuse on the next
// occurrence of the tag
[ curDescription release ] ;
curDescription = nil ;
}
// ... SNIP ...
[ accumulatedCharacters release ] ;
accumulatedCharacters = nil ;
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string{
{
[ accumulatedCharacters appendString:string ] ;
}

NSXMLParser strange behavior with \n

I'm developing an iOS 4 application that parses a XML file. A piece of XML is:
<?xml version="1.0" encoding="utf-8" ?>
<cards>
<card id ="0">
<name lang="es">The Mad</name>
<description lang="es">...</description>
</card>
...
</cards>
I use the following method to parse <name lang="es">The Mad</name>.
#pragma mark -
#pragma mark NSXMLParserDelegate methods
- (void)parser:(NSXMLParser *)parser
didStartElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI
qualifiedName:(NSString *)qName
attributes:(NSDictionary *)attributeDict
{
NSLog(#"DidStartElement: %#", elementName);
if ([elementName isEqualToString:#"card"])
{
currentCard = [[Card alloc] init];
NSString* arcaneNumber = [attributeDict objectForKey:#"id"];
currentCard.Number = arcaneNumber;
return;
}
if ([elementName isEqualToString:#"name"])
{
if ([[attributeDict objectForKey:#"lang"] isEqualToString:userLanguage])
{
currentProperty = kNameProperty;
return;
}
}
if ([elementName isEqualToString:#"description"])
{
if ([[attributeDict objectForKey:#"lang"] isEqualToString:userLanguage])
{
currentProperty = kDescriptionProperty;
return;
}
}
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
if (!currentStringValue)
{
// currentStringValue is an NSMutableString instance variable
currentStringValue = [[NSMutableString alloc] initWithCapacity:50];
}
[currentStringValue appendString:string];
}
- (void) parser:(NSXMLParser *)parser
didEndElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI
qualifiedName:(NSString *)qName
{
NSLog(#"DidEndElement: %#", elementName);
if ([elementName isEqualToString:#"card"])
{
[cards setObject:currentCard forKey:currentCard.Number];
[currentCard release];
currentCard = nil;
return;
}
if (currentProperty == kNameProperty)
{
currentProperty = kNoneProperty;
currentCard.Name = [currentStringValue stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
[currentStringValue release];
currentStringValue = nil;
return;
}
if (currentProperty == kDescriptionProperty)
{
currentProperty = kNoneProperty;
currentCard.Description = currentStringValue;
[currentStringValue release];
currentStringValue = nil;
return;
}
}
After, parsing , I get on currentStringValue the following:
\n\nThe Mad
How can avoid these two '\n'? Why am I getting these two '\n'?
This xml file came from a Windows system, and I've used TextWrangler to covert it to Classic Mac format.
The foundCharacters delegate method also gets called for whitespace in between elements. It will get called if there is say a newline between <cards> and <card id=....
I suggest clearing currentStringValue at the top of didStartElement to discard any characters found before the start of the current element and to make sure only the characters inside the current element (not between) are captured by foundCharacters.
At the top of didStartElement, add:
[currentStringValue release];
currentStringValue = nil;
It is possible for an element's value to contain whitespace (so removing them in didEndElement could result in saving values that don't match the xml content).
On your end element method you can try stripping these out yourself from the current text string. Simply try searching for them on the string and replace them with #"". I like replacing these and unwanted blank entries.
Try this it work for me ,
NSString *data= [str stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
Use above line of code in foundCharacters method .
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string;
{
NSString *data= [string stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
if(dString == nil){
dString = [[NSMutableString alloc] initWithString:data];
}else
{
[dString appendString:data];
}
}
Hope this will help for some one .

Resources