Parsing xml in NSXMLParser - objective-c

I have read many examples of how to get text out of xml files, but just don't get how to. Here is a sample xml file:
<?xml version="1.0" encoding="UTF-8"?>
<questions>
<set>
<question>Question</question>
<answer>Answer</answer>
</set>
</questions>
Using -(void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI, what's the easiest way to get the values Question and Answer? I already have my parser delegate hooked up and all that blah.

For implementing NSXMLParser you need to implement delegate method of it.
First of all initiate NSXMLParser in this manner.
- (void)viewDidLoad {
[super viewDidLoad];
rssOutputData = [[NSMutableArray alloc]init];
//declare the object of allocated variable
NSData *xmlData=[[NSData alloc]initWithContentsOfURL:[NSURL URLWithString:#""]];// URL that given to parse.
//allocate memory for parser as well as
xmlParserObject =[[NSXMLParser alloc]initWithData:xmlData];
[xmlParserObject setDelegate:self];
//asking the xmlparser object to beggin with its parsing
[xmlParserObject parse];
//releasing the object of NSData as a part of memory management
[xmlData release];
}
//-------------------------------------------------------------
-(void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *) namespaceURI qualifiedName:(NSString *)qName
attributes: (NSDictionary *)attributeDict
{
if( [elementName isEqualToString:#"question"])
{
strquestion = [[NSMutableString alloc] init];
}
}
//-------------------------------------------------------------
-(void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
// init the ad hoc string with the value
currentElementValue = [[NSMutableString alloc] initWithString:string];
} else {
// append value to the ad hoc string
[currentElementValue appendString:string];
}
NSLog(#"Processing value for : %#", string);
}
//-------------------------------------------------------------
-(void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
if( [elementName isEqualToString:#"question"])
{
[strquestion setString:elementName];
}
[currentElementValue release];
currentElementValue = nil;
}
The above delegate method is sent by a parser object to its delegate when it encounters an end of specific element. In this method didEndElement you will get value of question.

// This one called out when it hit a starting tag on xml in your case <question>
BOOL got = FALSE;
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI
{
if([elementName isEqualToString:#"question"])
{
got = TRUE;
}
}
// This is third one to called out which gives the end tag of xml in your case </question>
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
// This delegate is the second one to called out which gives the value of current read tag in xml
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
if(got)
{
NSLog(#"your desired tag value %#",string);
got = FALSE;
}
}

You need to implement the method
-(void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
Once you see the elements whose (inner)text you want to grab, set a flag in your program, and keep a string with the things that foundCharacters finds between the tags. Once you hit the didEndElement method, you can do what you want with the string and reset the flag.
For example
-(void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
if (sawQuestion) {
// need to check here that self->myString has been initialized
[self->myString appendString:string];
}
}
and in didEndElement you can reset the flag sawQuestion

You have to implement the callbacks for NSXMLParserDelegate
The key ones are:
// called when it found an element - in your example, question or answer
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI
// called when it hits the closing of the element (question or answer)
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI
// called when it found the characters in the data of the element
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
So, when you hit the elements, you can set state whether the parser is currently in the question or answer element (with an iVar) and then when you get called back with foundCharacters, based on the state you set when you hit the element, you know which variable (question or answer) to assign the data to.

Related

How to parse an XML file, grabbing data from specific elements

so I have an XML file with data from a lot of instances of an object. I'm parsing this file, but only want the data with the element tag "Content"
I am using NSXMLParser, so I have the methods parserDidStartDocument, didStartElement, foundCharacters, and didEndElement
So here is my current implementation
In Header:
#property (strong) NSMutableArray* AssetJSONObjects;
In Implementation:
boo
l grabContent = NO;
- (void) parserDidStartDocument:(NSXMLParser *)parser {
NSLog(#"parserDidStartDocument");
self.AssetJSONObjects = [NSMutableArray new];
}
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict {
NSLog(#"didStartElement --> %#", elementName);
if([elementName isEqual:#"Content"])
{
grabContent = YES;
}
}
-(void) parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
NSLog(#"foundCharacters --> %#", string);
if(grabContent)
{
[self.AssetJSONObjects addObject:string];
}
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {
NSLog(#"didEndElement --> %#", elementName);
if(grabContent)
{
grabContent = NO;
}
}
- (void) parserDidEndDocument:(NSXMLParser *)parser {
NSLog(#"parserDidEndDocument");
}
So here is my question: is the way that I'm declaring/initializing my array, AssetJSONObjects legitimate? Is the way I'm initializing my bool grabContent legitimate? Is there a better way to grab data from specific tags?
Went the cheap route, just kept track of a global boolean and set it if the tag was found
relevant code:
BOOL grabContent = NO;
- (void) parserDidStartDocument:(NSXMLParser *)parser {
self.AssetJSONObjects = [NSMutableArray new];
}
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict {
if([elementName isEqual:#"Content"])
{
grabContent = YES;
}
}
-(void) parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
if(grabContent)
{
NSDictionary *JSONObject =
[NSJSONSerialization JSONObjectWithData: [string dataUsingEncoding:NSUTF8StringEncoding]
options: NSJSONReadingMutableContainers
error: nil];
if (JSONObject)
{
[self.AssetJSONObjects addObject:JSONObject];
}
}
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {
if(grabContent)
{
grabContent = NO;
}
}
- (void) parserDidEndDocument:(NSXMLParser *)parser {
self.notifications = [self convertRawJSONToNotifications:self.AssetJSONObjects];
if(self.notifications != nil)
{
self.notificationCompletionHandler(self.notifications, self.numNewNotifications);
}
}

NSXMLParser can not parse special characters (german & french)

I am working on an App, which makes a search on a private server and shows the results to the user. The problem is NSXLParser can not parse the special german and french characters. For example: it should be:(Geschäftsführer) -> what i get is: (äftsführer)
How can i fix this ?
here is my code:
- (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:#"results"])
{
currentJob = [SearchResult alloc];
}
}
- (void) parser:(NSXMLParser *)parser didEndElement:(NSString *)elementname namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
if ([elementname isEqualToString:#"jobTitle"])
{
currentJob.jobTitle = currentNodeContent;
}
if ([elementname isEqualToString:#"location"])
{
currentJob.shortAddress = currentNodeContent;
}
if ([elementname isEqualToString:#"companyName"])
{
currentJob.employer = currentNodeContent;
}
if ([elementname isEqualToString:#"results"])
{
[self.jobs addObject:currentJob];
currentJob = nil;
currentNodeContent = nil;
}
}
Any help would be much appreciated...
Thanks in advance
Your foundCharacters method should append the string to a NSMutableString object, because it can be called multiple times for a single value. In didStartElement, initialize a NSMutableString object (let's call it elementContentString), then do this:
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)chars
{
[self.elementContentString appendString:chars];
}
And in your didEndElement you can get the content as a string. Note that you should make a non-mutable copy of it (so you don't overwrite it with the next element), using [NSString stringWithString:self.elementContentString].

NSXMLParser can not get the content of elements correctly

i have the following XMLParser but when i try to run it, it doesn't work properly.
- (void) parser:(NSXMLParser *)parser didStartElement:(NSString *)elementname namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
{
if ([elementname isEqualToString:#"results"])
{
currentJob = [SearchResult alloc];
}
}
- (void) parser:(NSXMLParser *)parser didEndElement:(NSString *)elementname namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
if ([elementname isEqualToString:#"jobTitle"])
{
currentJob.jobTitle = currentNodeContent;
}
if ([elementname isEqualToString:#"location"])
{
currentJob.shortAddress = currentNodeContent;
}
if ([elementname isEqualToString:#"companyName"])
{
currentJob.employer = currentNodeContent;
}
if ([elementname isEqualToString:#"results"])
{
[self.jobs addObject:currentJob];
currentJob = nil;
currentNodeContent = nil;
}
}
AND here is my foundCharakter Method:
- (void) parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
currentNodeContent = (NSMutableString *) [string stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
}
The output doesn't start from the beginning, it starts from the middle of the String...
I just can not understand, why some results look nice where some others don't.
What am i doing wrong ? How can i parse an xml properly ?
Any help will be appreciated.
Thx in advance
I used the following code and works now:
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string{
if(!elementContentString)
elementContentString = [[NSMutableString alloc] initWithString:string];
else
[elementContentString appendString:string];
}
I don't think there any problem in your code, it is working fine at my end. I am using the twitter api for getting xml and it is giving me proper output.

How to get tags parameters with NSXMLParser in Objective-C?

In XML struct i have:
<font fontsize="10" fontcolor="#000000" fontface="file.ttf"/>
How do i get fontsize, color and face using NSXMLParser?
Of course i have the standard implementation
-(id)init
{
self = [super init];
parser = [[NSXMLParser alloc] initWithContentsOfURL:[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:#"myxmlfile" ofType:#"xml"]]];
[parser setDelegate:self];
[parser parse];
return self;
}
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
{
NSLog(#"Started Element %#", elementName);
element = [NSMutableString string];
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
NSLog(#"Found an element named: %# with a value of: %#", elementName, element);
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
if (element == nil)
element = [[NSMutableString alloc] init];
[element appendString:string];
}
And it works beautifly for a <mytag>something</mytag>. How to get tag attributes?
Your attributeDictionary from
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
contains them. Just call [atrributeDict objectForKey:#"fontColor"] for example
The NSXMLParserDelegate protocol has a – parser:foundAttributeDeclarationWithName:forElement:type:defaultValue: method that the parser uses to tell the delegate about each attribute. Implement that method in your delegate and you'll get the attributes.
Use xpathQuery.. Its the most simple, quickest solution for XML parsing.. This will solve your problem..
here is the link..
http://cocoawithlove.com/2008/10/using-libxml2-for-parsing-and-xpath.html
BTW: for 'query' part, you need to put '//' for root element, '//root//item' for inner hierarchy for example.

How to parse this XML file using Objective C?

I have an XML file of the following structure:
<xmlDocument version="1">
<subject id="1">
<maths marks="65"/>
<science marks="80"/>
<tamil marks="90"/>
<social marks="79"/>
<English marks="70"/>
</subject>
</xmlDocument>
How to parse and get this data using Objective C?
Create an instance of NSXMLParser and assign a delegate to the parser.
In your delegate class, implement the relevant methods of the NSXMLParserDelegate protocol.
Call the parser's parse method.
Ask more specific questions if you encounter problems.
Since you don't have any text inside your tags you can use the parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName attributes:(NSDictionary *)attributeDict method on your delegate. Than you can store the values inside a dictionary or object. If you have multiple subject tags you can use the parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName to change the context of your parser. The official documentation should give you more details on which methods are available.
You could do something like that (incomplete implementation):
/*
* Incomplete implementation just to give some pointers
*/
#implementation MyDelegate
-(void) init {
if((self = [super init])) {
_subjects = [NSMutableArray new];
}
}
-(void) parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName attributes:(NSDictionary *)attributeDict {
if([elementName equalsIgnoreCase:#"subject"]) {
_context = [NSMutableDictionary new];
} else {
[_context setObject:[attributeDict valueForKey:#"mark"] forKey:elementName];
}
}
- (void) parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName {
[_subjects addObject:_context]
[_context release]; _context = nil;
}
#end