NSXML Parser and loading a level cocos2D - objective-c

I am trying to load my levels in objective-c through xml.
Here is the style of my xml that is output from my level editor.
<level>
<entity>
<name>grey</name>
<id>5</id>
<body>false</body>
<x>0.0</x>
<y>0.0</y>
<rotation>0.0</rotation>
</entity>
<entity>
<name>grey</name>
<id>5</id>
<body>false</body>
<x>0.0</x>
<y>0.0</y>
<rotation>0.0</rotation>
</entity>
</level>
Each game object is recognized in XML as its own entity(Sprite when it is loaded int the game). So when the parsing takes place each entity or CCSprite should have its own x and y.
I would like the parser to traverse the xml document so each entity has a name, x, and y, and rotation. The other elements im not concerned with yet.
I have been trying for hours now to get things up and running with NSXML parser but no luck thus far..Here is what i have tried so far.
NSString* currentElement;
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName{
currentElement = elementName;
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string{
if([currentElement isEqualToString:#"name"]){
NSLog(#"Name found: %#", string);
}
}
This works for some of the elements but the problem is foundCharacters is called multiple times and sometimes the name string returns blank.
What i am trying to do is when a element "name is found, i want to call a method that adds the current entity to the scene taking the "Name", "X, and "Y" elements as paramters.

Related

Parsing With NSXML Parser Cocoa

I am trying to parse the following information from xml in Cocoa.
<level>
<entity>
<name>red</name>
<id>0</id>
<body>false</body>
<x>0.0</x>
<y>0.0</y>
<rotation>0.0</rotation>
</entity>
Here is what i have so far from following the nsxml parser guide by apple.
NSString* currentElement;
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName{
currentElement = elementName;
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string{
if([currentElement isEqualToString:#"name"]){
NSLog(#"Name found: %#", string);
}
}
In my found character method it logs the statement but the only thing returning is "Name found: " and the rest is blank.
Am i doing this correctly to get the following tags in my xml? I would like to extract each tag.
for example:
NSString* name = THE_NAME;
int x = [THE_X_VALUE, intValue];
etc.
Could anyone help me out?
NSXMLParser is one of those classes that sounds good on paper, but drives you insane when you actually start to use it. If you really want to continue on this joyless path, implement parser:didStartElement: and then pray that parser:foundCharacters: delivers the goods.
In my experience, NSXMLParser is like a big toddler who smashes the puzzle and then hands you the pieces one by one. That seems like a great at first: "Oh look, I've got a piece! And another one! And one more!" but soon you find yourself bewildered: "Oh look, I've got 5.0! Now, was that the rotation or the y coordinates?" Who knows? Not NSXMLParser, that's for sure.
As for the last line of code: to extract the numeric value of a string, NSDecimalNumber is very handy.
if([currentElement isEqualToString:#"x"]){
NSDecimalNumber *dec = [NSDecimalNumber numberWithString:string];
CGFloat x = dec.floatValue;
}

feed reader using nsxmlparserdelegate

i am creating an app that shows the latest feeds from a particular webservice,i am using NSXMLParserDelegate protocol for this purpose,well i read the apple documentation and i tried some tutorials too,but something seems to be going wrong somewhere,i dont understand how does the didEndElement,foundCharacters work,anyways i want to display the image,title and content,pub-date of the post,i am newbie to xmlparsing here's my viewcontroller.h(i have just parsed only the title element in the following code)
#property(nonatomic,strong)NSString *currentElement;
#property(nonatomic,strong)NSString *currentTitle;
#property(nonatomic,strong)NSMutableArray *titles;
viewdidload
NSURL *url=[NSURL URLWithString:#"http://www.forbes.com/fast/feed"];
NSXMLParser *parser=[[NSXMLParser alloc]initWithContentsOfURL:url];
[parser setDelegate:self];
[parser parse];
NSLog(#"%d",titles.count);
didStartElement
-(void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
{
self.currentElement=elementName;
if ([self.currentElement isEqualToString:#"title"])
{
self.currentTitle=[NSMutableString alloc];
titles=[[NSMutableArray alloc]init];
titles=[attributeDict objectForKey:#"title"];
}
}
foundCharacters
-(void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
{
self.currentElement=elementName;
if ([self.currentElement isEqualToString:#"title"])
{
self.currentTitle=[NSMutableString alloc];
titles=[[NSMutableArray alloc]init];
titles=[attributeDict objectForKey:#"title"];
}
}
didEndElement
-(void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
if([self.currentElement isEqualToString:#"title"])
{
NSLog(#"%#",self.currentTitle);
}
}
doubts
1)where am i supposed to declare my titles array so that i can add individual title object to it.
what is the use of [attributeDict objectForKey] in didStartElement? it returned null for my program
2)what does foundCharacters delegate actually do? what does it append?
3)After didEndElement why doesnt the compiler reach for didStartElement and not the foundCharacters ?
4)finally should i actually use NSXMLParserDelegate protocol for the xml parsing,do others like touchXML,TBXML and others provided in the raywenderlich make a difference?
i am sorry for the long post,but i havent got any satisfying answers online regarding my queries,i used all the breakpoints and figured out how the delegates are called back and forth,i need some enlightening answers to my queries,thanks and sorry
1. Declare your array before starting to parse.Whenever you meet an elements (an xml tag), initialize the elements (set some BOOL in the class in a way that you can recognize what element you are reading);
2. Found characters are the characters found as value of a tag.If you know what element you are reading (reading your instance variables), you should append this string to your temporary NSMutableString and add it to the array only when the element is ended.
3. Because it doesn't start finding other characters until a new tag is reached.
Example
I see that you are confused, let's say that you have this XML code:
<person> mickey mouse </person>
When you meet the tag the element starts, then you find other characters (not the entire string, just a part of the string) until the string ends, then when you meet the tag the element is ended.
in didFindCharacters just add the found characters to a NSMutableString and in didEndElement you know what you ended and set a variable to the strings you found
image:
image => the character at didEnd are the name of the link, the url is in the attributes past in didStart
title-tag
didStart => didStart : html started, every tag is html until the didEnd of title-tag
content:
didStart => didStart : html started, every tag is html until the didEnd of content

Parsing XML CDATA Blocks

I'm attempting to parse an XML file (using NSXMLParser) from the website librarything.com. This is the first file I have ever parsed, but for the most part it seems fairly straight forward. My problem occurs when trying to parse a CDATA block; the method parser:foundCDATA: isn't called, and I can't understand why. I know my parser is set up properly because the parser:foundCharacters: method works fine. The XML data I am trying to parse looks like this http://www.librarything.com/services/rest/1.1/?method=librarything.ck.getwork&isbn=030788743X&apikey=d231aa37c9b4f5d304a60a3d0ad1dad4 and the CDATA block occurs inside the element with the attribute name "description".
Any help as to why the method is not being called would be greatly appreciated!
EDIT: I ran the parser:foundCharacters: method on the description CDATA block and it returned "<". I'm assuming this means that the parser is not seeing the CDATA tag correctly. Is there anything that can be done on my end to fix this?
It appears the CDATA contents in the <fact> tags is being returned incrementally over multiple call backs in parser:foundCharacters. In you class where you are conforming to NSXMLParserDelegate try building up the CDATA by appending it to an NSMutableString instance, like so:
(Note: here _currentElement is an NSString property and _factString is an NSMutableString property)
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qualifiedName attributes:(NSDictionary *)attributeDict {
self.currentElement = elementName;
if ([_currentElement isEqualToString:#"fact"]) {
// Make a new mutable string to store the fact string
self.factString = [NSMutableString string];
}
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {
if ([elementName isEqualToString:#"fact"]) {
// If fact string starts with CDATA tags then just get the CDATA without the tags
NSString *prefix = #"<![CDATA[";
if ([_factString hasPrefix:prefix]) {
NSString *cdataString = [_factString substringWithRange:NSMakeRange((prefix.length+1), _factString.length - 3 -(prefix.length+1))];
// Do stuff with CDATA here...
NSLog(#"%#", cdataString);
// No longer need the fact string so make a new one ready for next XML CDATA
self.factString = [NSMutableString string];
}
}
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
if ([_currentElement isEqualToString:#"fact"]) {
// If we are at a fact element, append the string
// CDATA is returned to this method in more than one go, so build the string up over time
[_factString appendString:string];
}
}

How to handle a tags inside another tags in NSXMLParser

I have a file:
<xml>
<component>something
<system>somethingDeeper
<value>somethingDeepest</value>
</system>
</component>
<component>somethinfDifferent
<value>somethingDifferentDeeper</value>
</component>
<value>somethingNew</value>
</xml>
So I want to distinguish what is inside another tag (ex. <system>) what is not. How to do this with NSXMLParser? I currently use BOOL ivar's but this is a lot of tags and this is not as elegant as I want it to be. I know that NSXMLParser is a SAX parser and I understand that.
In above example I will be enter to didEndElement method three times with:
elementName equal value Is there a more elegant way to distinguish what entry was from <component> tag above what not?
You could keep an array of tag names you are currently within
NSMutableArray *tagNameStack;
Each time you enter a new element you add it to this array. Each time you leave you remove it again. i.e.
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qualifiedName attributes:(NSDictionary *)attributeDict {
[tagNameStack addObject:elementName];
// Your code here
}
and
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {
// Your code here
[tagNameStack removeLastObject];
}
So, when you are parsing somethingDeepest your tagNameStack array would be
#"xml", #"component", #"system", #"value"
You can use this stack to decide where you are in the xml i.e.
- (void) parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
if ([tagNameStack containsObject:#"system"]) {
// Deal with the value inside the system tag
} else if ([tagNameStack containsObject:#"component"]) {
// Deal with the value inside the component tag
} else {
// This must be the value inside the XML tag
}
}

get XML content at node in Objective C

Using Objective C - I want to loop through an XML tree and display the full XML content at each instance of a specific node matching with a particular element name.
As an example - I am looking to get the XML (represented as an NSString) within each instance of element b. I can get the value if there is only a string in element b, but how do I get an NSString representation formatted as XML including all the element names?
<element a>
<element b>
<element c>
some text 1
</element c>
</element b>
<element b>
<element c>
some text 2
</element c>
</element b>
<element b>
<element c>
some text 3
</element c>
</element b>
</element a>
You can use NSXMLParser to do this. The three main sections of the class (1) check for opening tags:
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qualifiedName
attributes:(NSDictionary *)attributeDict;
(2) grab the content within the node encountered:
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string;
and (3) store the data to an appropriate place of your choice on node completion:
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName;
Apple has an excellent guide covering NSXMLParser here
There are possibly three approaches I can think of, all of which have the pros and cons.
Parse as a string. Depending on what exactly you want to extract, you could just use string manipulation code to search and extract the bits you want. This ignores the xml structure and reduces the problem to a simple string processing one. But may not be clever enough depending on the xml and the nodes you want.
Code up a NSXMLParser to parse the xml string into some sort of datastructure (i.e. DOM), locate the nodes you want in it and then get them to generate out the xml. Again depending on what you want, this could be too heavy. COuld also mean a lot more coding.
Download a library to do the dirty work for you. There are a variety around and I have one at (Shameless self promotion here) http://github.com/drekka/dXml which may help. It can certainly parse the xml into a DOM like data structure from which you can use XPath like queries to find the nodes and convert back to strings. The cons of this is that you are now using a third party library.
I had a brainwave last night and here is the solution I came up with... seems a little inelegant, but it works.
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict{
if ([elementName isEqualToString:#"element b"])
{
area = [[NSMutableString alloc] init];
current_element = [elementName copy];
}
else if ([current_element isEqualToString:#"element b"])
{
NSString *tag = [NSString stringWithFormat:#"<%#>", elementName];
[area appendString:tag];
}
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName{
if ([elementName isEqualToString:#"element b"])
{
NSLog(#"tag info: %#", area);
}
else if ([current_element isEqualToString:#"element b"])
{
NSString *tag = [NSString stringWithFormat:#"</%#>", elementName];
[area appendString:tag];
}
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string{
if ([current_element isEqualToString:#"element b"]) {
[area appendString:string];
}
}