XML files are used as an easy way to read and store data which is useful for storing configuration settings from applications. It’s always good practice to allow your application to be customised by the user, be it by turning off the Wiimote rumble, enabling background music, disabling prompts, etc. In this tutorial we’ll learn how to load and save simple settings by using XML files. You can grab the PDF of this tutorial here: codemii-tutorial-13
Understanding XML files
If you don’t know what an XML file looks like here is an example:
[sourcecode language=’c’]
As you can tell, it’s well structured and easily readable. You firstly have the root element which tells the XML parser that this is an XML document. This isn’t much importance to us but note that all valid XML files must have this root element.
[sourcecode language=’c’] [/sourcecode]
Next we have “app” as an element with an attribute of “version” and the attribute value of “1”. Elements are defined as being the text after the <. The attribute is the text that is inside the element and is equal to something, in this case it’s version = 1.
[sourcecode language=’c’]
Moving on, we have an element beneath the “app” element.
[sourcecode language=’c’]
This means that this element belongs to the “app” element. In this case the element is “name” and this time the element has a content of “Homebrew Browser”. We need to close off this element by using the / and the elements name.
The next few elements we can skip as they require the exact same processing as above. We then reach the end of our app element.
[sourcecode language=’c’][/sourcecode]
You can either end the file or keep adding more elements at the end such as:
[sourcecode language=’c’]
Homebrew Browser 2
teknecal2
…
[/sourcecode]
You will firstly need to download libxml which can be found here: http://wiichat.googlecode.com/files/mxml-wii.tgz
Extract and then copy mxml-wii\mxml\lib\libmxml.a to C:\devkitPro\libogc\lib\wii and mxml-wii\mxml\lib\include\mxml.h to C:\devkitPro\libogc\include. Thanks to Beardface for porting this XML library.
You’ll need to add –lxmxl to LIBS: in your makefile and also add #include in your main.c file. Also make sure you have #include and the other necessary fat initialisation functions.
Here is our source code for both saving and loading XML files: tutorial13.zip
Saving XML files
So now we have a very basic understanding of how XML files are structured and can now proceed to save our own XML files. We’ll be saving our data as attributes.
Going on the simple settings theme, let’s assume we only have either a 0 or a 1 to store in our XML file and that we have 3 variables which are setting_background_music, setting_rumble and setting_tips. We have our function below which saves our settings which I’ll explain below.
[sourcecode language=’c’]void update_settings() {
mxml_node_t *xml;
mxml_node_t *data;
xml = mxmlNewXML(“1.0”);
data = mxmlNewElement(xml, “settings”);
char set1[1];
sprintf(set1, “%i”, setting_background_music);
mxmlElementSetAttr(data, “setting_background_music”, set1);
char set2[1];
sprintf(set2, “%i”, setting_rumble);
mxmlElementSetAttr(data, “setting_rumble”, set2);
char set3[1];
sprintf(set3, “%i”, setting_tips);
mxmlElementSetAttr(data, “setting_tips”, set3);
FILE *f;
f = fopen(“sd:/settings.xml”, “wb”);
if (f == NULL) {
fclose(f);
printf(“Settings could not be written.\n”);
}
else {
mxmlSaveFile(xml, f, MXML_NO_CALLBACK);
fclose(f);
mxmlDelete(data);
mxmlDelete(xml);
printf(“Settings Saved\n”);
}
}[/sourcecode]
The first three items are just standard XML things which we do. We will be creating a XML file in memory at this point in time.
[sourcecode language=’c’]mxml_node_t *xml;
mxml_node_t *data;
xml = mxmlNewXML(“1.0”);[/sourcecode]
We now create a new element with the name settings which would look like in the file.
[sourcecode language=’c’]data = mxmlNewElement(xml, “settings”);[/sourcecode]
Then we start adding our attributes, but before we do so, these attributes are of type strings and our 0 or 1 (integer) needs to be changed into a string, so we use sprintf. We create an empty char array with a length of 1. We then sprintf to set1 the value of setting_background_music.
[sourcecode language=’c’]char set1[1];
sprintf(set1, “%i”, setting_background_music); [/sourcecode]
Now our char array has the value of either “0” or “1”. We can then set an attribute in our element settings to show this. We’ll call our attribute the same name as our variable which is setting_background_music for simplicity. Our setting element would like: (assuming we had the variable set to 1).
[sourcecode language=’c’]mxmlElementSetAttr(data, “setting_background_music”, set1); [/sourcecode]
Now we just repeat this to the rest of our variables.
[sourcecode language=’c’]char set2[1];
sprintf(set2, “%i”, setting_rumble);
mxmlElementSetAttr(data, “setting_rumble”, set2);
char set3[1];
sprintf(set3, “%i”, setting_tips);
mxmlElementSetAttr(data, “setting_tips”, set3); [/sourcecode]
Ok, so now we are done we can begin writing the file. As normal we open the file for writing, check if we can write to the file, etc.
[sourcecode language=’c’]FILE *f;
f = fopen(“sd:/settings.xml”, “wb”);
if (f == NULL) {
fclose(f);
printf(“File could not be written to\n”);
}[/sourcecode]
Now we can save our XML to file with just one line. After we have saved the file we close our file and then delete the XML in memory.
[sourcecode language=’c’]else {
mxmlSaveFile(xml, f, MXML_NO_CALLBACK);
fclose(f);
mxmlDelete(data);
mxmlDelete(xml);
printf(“XML Saved\n”);
}[/sourcecode]
Loading XML files
So now we know what we’ve saved in the XML file and what it will look like this:
We can parse our XML file and find out what our settings for each variable are; we can use the below code to do this.
[sourcecode language=’c’]void load_settings() {
mxml_node_t *tree;
mxml_node_t *data;
FILE *fp = fopen(“sd:/settings.xml”, “rb”);
if (fp == NULL) {
fclose(fp);
}
else {
fseek (fp , 0, SEEK_END);
long settings_size = ftell (fp);
rewind (fp);
if (settings_size > 0) {
tree = mxmlLoadFile(NULL, fp, MXML_NO_CALLBACK);
fclose(fp);
data = mxmlFindElement(tree, tree, “settings”, NULL, NULL, MXML_DESCEND);
if (mxmlElementGetAttr(data,”setting_background_music”)) {
setting_background_music = atoi(mxmlElementGetAttr(data,”setting_background_music”));
printf(“Setting for background music loaded\n”);
}
if (mxmlElementGetAttr(data,”setting_rumble”)) {
setting_rumble = atoi(mxmlElementGetAttr(data,”setting_rumble”));
printf(“Setting for rumble loaded\n”);
}
if (mxmlElementGetAttr(data,”setting_tips”)) {
setting_tips = atoi(mxmlElementGetAttr(data,”setting_tips”));
printf(“Setting for tips loaded\n”);
}
mxmlDelete(data);
mxmlDelete(tree);
printf(“Settings loaded.\n”);
}
else {
fclose(fp);
unlink(“sd:/settings.xml”);
}
}
}[/sourcecode]
We start almost the same as before when saving our XML file, we initialise variables to store the XML and then we just use our standard fopen to read our XML file.
[sourcecode language=’c’]void load_settings() {
mxml_node_t *tree;
mxml_node_t *data;
FILE *fp = fopen(“sd:/settings.xml”, “rb”);
if (fp == NULL) {
fclose(fp);
}[/sourcecode]
It’s a good idea to check that this file has content otherwise we’ll have some errors, so we can do so using ftell to tell us the file size, if it’s over 0 bytes, the file has some content.
[sourcecode language=’c’] else {
fseek (fp , 0, SEEK_END);
long settings_size = ftell (fp);
rewind (fp);
if (settings_size > 0) {[/sourcecode]
Next we’ll load our file to our XML variable which we created at the start and then close the file, read all our “settings” elements and store them in the variable data.
[sourcecode language=’c’] tree = mxmlLoadFile(NULL, fp, MXML_NO_CALLBACK);
fclose(fp);
data = mxmlFindElement(tree, tree, “settings”, NULL, NULL, MXML_DESCEND); [/sourcecode]
Now we start reading our settings one by one. We make reference to our data variable which contains all the settings and say that we only want to read the element value for the element called “setting_check_size”.
It’s important to have this check, otherwise if our settings XML file didn’t contain the element we were trying to read, it would cause some issues. If this element is present, it’s stored as a string so we use atoi to convert it to an int and store it in our variable “setting_check_size”.
[sourcecode language=’c’] if (mxmlElementGetAttr(data,”setting_check_size”)) {
setting_check_size = atoi(mxmlElementGetAttr(data,”setting_check_size”));
}[/sourcecode]
We do the same for the rest of our settings.
[sourcecode language=’c’] if (mxmlElementGetAttr(data,” setting_rumble “)) {
setting_rumble = atoi(mxmlElementGetAttr(data,”setting_rumble”));
}
if (mxmlElementGetAttr(data,”setting_tips”)) {
setting_tips = atoi(mxmlElementGetAttr(data,”setting_tips”));
}[/sourcecode]
We can remove the XML file from memory and we are done.
[sourcecode language=’c’] mxmlDelete(data);
mxmlDelete(tree);
printf(“Settings loaded.\n”);
}
else {
fclose(fp);
}
}
}[/sourcecode]
We’ve now successfully read all our settings from the XML we saved and that wraps up this tutorial. You can now save and load your applications simple settings using XML files.
Thanks – this will be extremely useful!
Yet another well written guide, Teknecal.
Nice tutorial again! Could you please add the PDF version? Nicer to print and easier to organize. Thanks in advance.
It’s on my todo list I’ll try and get it written this week.
Sorry if I post on this tutorial, but since i’ve started 2 days ago programming i’ve started from the first tutorial…but it’s quite old and the post are old too…so i’ll ask my question here:
I’ve problems with tutorial 4 and 5 (6 and so on not tested yet),I get (on the hbc) the message that the executable i’ve built is not a valid wii application.
Any idea? (I’ve tryed with the sd method and using wiiload,same result).
Many thanks!
That’s odd. What version of HBC do you have? Do you have a firewall and if so can you try turning it off? What happens when you place the boot.dol on your SD card and try like that, does it work?
I’ve the latest version of HBC, the first 3 tutorials works perfectly (so that’s not a firewall problem, anyway i’ve disabled it), if I put the file (renaming it to boot.dol inside a subfolder of apps, as always I do), it gives me the same error.
It’s very odd, but i need to solve the problem 🙂
Just in case…i’m using fw 4.0 if it can help
Next tutorials…
Why not talking about debugging applications?
Little question…can you send me the .dol file of the tutorial n.4? just to test if it’s a compiler problem or a wii problem.
Please, send the .dol file to smile_k@libero.it (can it be a problem of the latest devkit?)
I’m waiting for the file!
Many many thanks!
Great tutorials!
Have sent you an email with it.
Your .dol works perfectly :\
So it’s a compiler problem…
I’m using devkitProUpdater-1.5.0.exe and the latest HBC,
which version of devkit and hbc are you using?
I’m using DevKitPro r16 and HBC 1.0.1.
r16 is not out :\ ?!?!?
http://sourceforge.net/project/showfiles.php?group_id=114505&package_id=160396
My compiler produce an 84kb file instead of your (about 200kb).
:\ :\ :\ :\
Found it!
LOL…total my fault…i was trying to run http://www.codemii.com/wp-content/uploads/2008/08/tutorial4-blank.zip on the wii 😛
I’m very sorry…very sorry.
Thanks man,great work!
Ah 🙂
Think I spotted an error
—
You’ll need to add –lxmxl to LIBS: in your makefile and also add #include in your main.c file. Also make sure you have #include and the other necessary fat initialisation functions.
—
I guess this should be -lmxml
It should be include mxml.h
Thank you once again for this tutorial Teknecal – it really helped me to get going with the mxml lib. I’m using this to ‘internationalise’ BootMii Config editor.
It’s worth taking a look at the official documentation for this.
http://www.minixml.org/mxml.html if people have more questions.
Even with this documentation, I still haven’t figured out how to get a text value out of an element rather than an attribute, but for now, I’ve put everything into attributes to make it easier, and I’ll try and figure this out some other time.
hi
im spanish sorry for my english
thanks for tutorials, very nice work.
i have a dude, can i edit a boot.dol ?
can i open the .dol of other programs to see the code in c ? im think is very useful to learn to program.
please if you know a form do a tutorial or send me a email thanks
The dol is the compiled version of the code. You won’t be able to see the C code.
sorry other question :
are you doing a pdf ? i wanna it because im printing all pdf to do a book 😛
thanks a lot
and thanks pembo for your bootmii config editor because i changed the options in a file in pc but no change in wii lol, but whit your program i can see in colour the bootmii in pal =)
I’ll ask Ryan to PDF it.
Done. Just sent it to you..
Sorry again for the delay.
Thanks.
thanks a lot
mmmm sorry but when i press to tutorial 13, it isn´t a pdf are the archives to compile
Sorry about that, has been fixed.
working =P thanks
It’s been a while, so I’m not sure if you’re still making them, but if you are, would it be possible to write a tutorial on how to display video?
hi! looks like libxml link is dead now, as stated in the wiibrew page. if you still have the file, can you archive it?