We will first discuss how to simply load an XML file. We will later consider how to add data back into an XML file.
For this chapter, I created a new project called Data
, and all the necessary files can be found in the Resources
folder of this chapter. The project file is also included in the code resource for the chapter, so if you get stuck anywhere, you can refer to it for clarification.
To load an XML file, we first need to have an XML file to work with. For this, I included the GroupList.xml
file. Import this file into the project.
The file can be viewed in Xcode. Click on the file to see it in the navigator, as follows:
<Group> <Player> <Name>Siddharth</Name> <Level>1</Level> </Player> <Player> <Name>Alice</Name> <Level>2</Level> </Player> <Player> <Name>Steve</Name> <Level>3</Level> </Player> </Group>
In the file, we have our group of players that we want to load. There are three players, and for each of the players, we will also include properties such as their name and level. Player Siddharth is level 1, Alice is level 2, and Steve is level 3.
Once you import the XML file, you will next make some changes to the project so that it can be read in the XML file.
For this, we will use GDataXML created by Google to process XML data. You can download it from https://github.com/google/gdata-objectivec-client.
Once it is downloaded, go to the Source
/ XMLSupport
folder and copy the GDataXMLNode.h
and GDataXMLNode.m
files to your project. It is better if you create a new group before importing so that the project file is neatly organized.
Next, click on your project in Xcode in Build Settings, select all the items in Header Search Paths under Search Paths, and then add /usr/include/libxml2
.
Then, in Other Linker Flags, add –lxml2
.
Also, select the GDataXMLNode.m
file and add the –fno-objc-arc
compiler flag to it.
In the MainScene.m
file, let's create a user struct so that we can create a mutable array to store data in. So, at the top of the class, we will create a struct called Player
, as follows:
typedefstruct{ __unsafe_unretainedNSString* name; int level; }Player;
In the MainScene.h
file, we will create a variable called players
of the mutable array type via the following code:
@interface MainScene :CCNode{ NSMutableArray *players; } +(CCScene*) scene; @end
Next, in the init
function, we will initialize the mutable array, as follows:
+(CCScene*) scene{ return [[self alloc]init]; } -(id)init{ if(self = [super init]){ //** XML players = [[NSMutableArrayalloc]init]; } return self; }
Next, we will create a function that will load the XML file, get data from it, and save it in the mutable array. We will call this function loadXMLGroup
and add it as follows:
- (void)loadXMLGroup { NSString *filePath = [self XMLdataFilePath:FALSE]; NSData *xmlData = [[NSMutableDataalloc] initWithContentsOfFile:filePath]; NSError *error; GDataXMLDocument *doc = [[GDataXMLDocumentalloc] initWithData:xmlData options:0 error:&error]; if (doc == nil){ NSLog(@" **** unable to load xml ****"); } NSLog(@"%@", doc.rootElement); NSArray *groupMembers = [doc.rootElementelementsForName:@"Player"]; for (GDataXMLElement *groupMember in groupMembers) { NSString *name; int level; Player player; //** Name NSArray *names = [groupMemberelementsForName:@"Name"]; if (names.count> 0) { GDataXMLElement *firstName = (GDataXMLElement *) [names objectAtIndex:0]; name = firstName.stringValue; NSLog(@"Name: %@", name); player.name = name; } else continue; //** Level NSArray *levels = [groupMemberelementsForName:@"Level"]; if (levels.count> 0) { GDataXMLElement *firstLevel = (GDataXMLElement *) [levels objectAtIndex:0]; level = firstLevel.stringValue.intValue; NSLog(@"Level: %d", level); player.level = level; } else continue; NSValue *value = [NSValuevalueWithBytes:&player objCType:@encode(Player)]; [playersaddObject:value]; } }
First we will pass in the filename of the XML file that we would like to load, which is a string. Next, we will get the actual data from the file using the NSData
property class. This will then be transferred to a variable called doc
of the GDataXMLDocument
type.
If doc
is empty, we will log an error saying that no data was found.
Otherwise, we will store all the values in an NSArray
variable called groupMembers
.
To cycle through each of the elements of the array, we will use the GDataXMLElement
property, and we will use the for loop to go through each of the elements.
Two temporary variables are created to store the name and level. Also, a variable called player
is created of the Player
type to store in the players' Mutable
array.
The name and level member elements are taken and stored in separate NSArrays
, respectively.
All the player elements are stored in a separate array called players
.
We will also log the names and levels if found in GDataXMLElement
.
To actually retrieve the file path for the XML file, we have to create a function as follows. This same function will be used to get a filename to save:
- (NSString *)XMLdataFilePath:(BOOL)forSave { NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); NSString *documentsDirectory = [paths objectAtIndex:0]; NSString *documentsPath = [documentsDirectorystringByAppendingPathComponent:@"GroupList.xml"]; if (forSave || [[NSFileManagerdefaultManager] fileExistsAtPath:documentsPath]) { returndocumentsPath; } else { return [[NSBundlemainBundle] pathForResource:@"GroupList" ofType:@"xml"]; } }
This file
function will check whether a file with the same name already exists. If it exists, then the file path is returned. If not, then a new XML file is created and the path is returned as a string.
Now, in the init
function, after where we initialized the players, the Mutable
array calls the loadXMLGroup
function, as follows:
-(id)init{ if(self = [super init]){ //** XML players = [[NSMutableArrayalloc]init]; [selfloadXMLGroup]; } return self; }
18.191.186.219