Tutorial 13: Loading and saving simple XML files

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:

<?xml version="1.0" ?>
<app version="1">
<name>Homebrew Browser</name>
<coder>teknecal</coder>
<version>0.3.1</version>
<release_date>200905010000</release_date>
<short_description>Browse homebrew apps</short_description>
</app>

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.

<?xml version="1.0" ?> 

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.

<app version="1"> 

Moving on, we have an element beneath the “app” element.

<name>Homebrew Browser</name>

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.

</app>

You can either end the file or keep adding more elements at the end such as:

Homebrew Browser 2
teknecal2
…
</app>

You will firstly need to download libxml which can be found here: http://wiichat.googlecode.com/files/mxml-wii.tgz http://sourceforge.net/projects/devkitpro/files/portlibs/mxml-2.6-ppc.tar.bz2/download

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.

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");
}
}

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.

mxml_node_t *xml;
mxml_node_t *data;
xml = mxmlNewXML("1.0");

We now create a new element with the name settings which would look like in the file.

data = mxmlNewElement(xml, "settings");

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.

char set1[1];
sprintf(set1, "%i", setting_background_music); 

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).

mxmlElementSetAttr(data, "setting_background_music", set1); 

Now we just repeat this to the rest of our variables.

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); 

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.

FILE *f;
f = fopen("sd:/settings.xml", "wb");

if (f == NULL) {
fclose(f);
printf("File could not be written to\n");
}

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.

else {
mxmlSaveFile(xml, f, MXML_NO_CALLBACK);
fclose(f);
mxmlDelete(data);
mxmlDelete(xml);
printf("XML Saved\n");
}

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.

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");
}
}
}

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.

void load_settings() {
mxml_node_t *tree;
mxml_node_t *data;

FILE *fp = fopen("sd:/settings.xml", "rb");
if (fp == NULL) {
fclose(fp);
}

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.

	else {
fseek (fp , 0, SEEK_END);
long settings_size = ftell (fp);
rewind (fp);

if (settings_size > 0) {

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.

			tree = mxmlLoadFile(NULL, fp, MXML_NO_CALLBACK);
fclose(fp);

data = mxmlFindElement(tree, tree, "settings", NULL, NULL, MXML_DESCEND); 

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”.

			if (mxmlElementGetAttr(data,"setting_check_size")) {
setting_check_size = atoi(mxmlElementGetAttr(data,"setting_check_size"));
}

We do the same for the rest of our settings.

			if (mxmlElementGetAttr(data," setting_rumble ")) {
setting_rumble = atoi(mxmlElementGetAttr(data,"setting_rumble"));
}
if (mxmlElementGetAttr(data,"setting_tips")) {
setting_tips = atoi(mxmlElementGetAttr(data,"setting_tips"));
}

We can remove the XML file from memory and we are done.

			mxmlDelete(data);
mxmlDelete(tree);
printf("Settings loaded.\n");
}
else {
fclose(fp);
}
}
}

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.

48 Responses to “Tutorial 13: Loading and saving simple XML files”

  1. pembo says:

    Thanks – this will be extremely useful!

  2. Nicholas Anthony Roge says:

    Yet another well written guide, Teknecal.

  3. John says:

    Nice tutorial again! Could you please add the PDF version? Nicer to print and easier to organize. Thanks in advance.

  4. Michele says:

    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!

  5. pembo says:

    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

  6. pembo says:

    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.

  7. pececito says:

    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

  8. pececito says:

    sorry other question :
    are you doing a pdf ? i wanna it because im printing all pdf to do a book :P
    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 =)

  9. Fall of Socrates says:

    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?

  10. David.ta says:

    Hello Teknecal. I have a quick question for you, that is a little much for the comments. It’s not really related to this article, but I couldn’t find any other way to contact you.

    Basically I would like some clarification on how the gxSprite program works in the Wii examples for devkitPro. Basically what I would like to know is how to make it so it can read 6 different images from the sprite sheet(instead of 4). I tried looking at it today, but I am completely confused. Could you perhaps make a tutorial on it, or email me at david.ta@nikuai.net

    I’m sorry if I am not giving enough information. Thank you.

  11. Görgen says:

    I just want to give my THANKS for this blog post. The original documentation didn’t quite teach me the basics of reading xml through mxml.. thanks once again and keep up this good work of great documentation.

  12. prampa says:

    Hello Teknecal. I have a question for you but I don’k know if this is the right place. I have a terrible problem with a my homebrew. I am not able to download some data from a my url (writingbook.netsons.org/provawii.php for example).
    I connect to the server but the homework crashes (SDI error) when I try to read the html. Could you write a tutorial about it? It could be very interesting for everyone…..
    regards

    • teknecal says:

      Hi, I have two examples, one downloads everything to a file and reads it and the other prints everything to the screen.

      They can be found here: http://www.wiibrew.org/wiki/Homebrew_Browser#NetSend_Example_.2B_HTTP_Download_Example

      • prampa says:

        In first, thank for the help. I tried the two examples.
        With Netsend I get a “400 bad request”, and with http_download_example I get the error 10076. (I used the link : www,writingbook.netsons.org/provawii.php)
        I’d like to connect a server, to execute a script server side and then to parse the result (xlm or html). This is my goal. I tried with many examples of homebrew, wiiearth, wiiconnect, magacodedownload, but nothing to do. My homework doesn’t work. Could it depend from the server and not from my code?
        best regards

  13. prampa says:

    I have resolved!!!! Basically I used fMyLife project (www.wiibrew.org/wiki/FMyLife). I don’t know why, but my homework works fine, now.
    Thank everyone and thank for all tutorials!!!! Is the idea of a network tutorial valid?
    hi

  14. Kelson says:

    These tutorials have been great. Could you please write one for the GRRlib library? I’m having a hell of a time just getting the environment working, and a really simple tutorial to print out a graphic would help a lot.

    • teknecal says:

      First try running the install.bat file in GRRLIB\GRRLIB\lib.

      I think you need to copy the folder called “GRRLIB” that has the all the .c and .h files to C:\devkitPro\libogc\include. Then open the “lib” directory, in there you have jpeg, png and pngu. Open jpeg, copy include and lib directories to C:\devkitPro\libogc and do this for the rest.

      You should take a look at example2 but yeah I should start doing more tutorials. I’m still using GRRLIB 3.0 :P

      • Kelson says:

        Didn’t work, libraries still aren’t linked, I give up.

      • Kelson says:

        This is driving me nuts. I tried doing the thing in your post but it didn’t link. I’m trying to do it the way they have in the readme but I don’t know what this line means:

        After all three image processing libraries are installed, we can now install
        libgrrlib:
        c:
        cd \grr\trunk\GRRLIB\GRRLIB
        make clean all install

        • teknecal says:

          I’ve just started off from scratch, downloaded devkitppc and then downloaded grrlib.

          First thing is to run that install.bat found in GRRLIB\GRRLIB\lib.
          Second thing is to open up CMD (Start -> Run, type cmd.exe), then navigate to the GRRLIB\GRRLIB\GRRLIB directory (e.g. cd GRRLIB\GRRLIB\GRRLIB) that contains a file called “Makefile”. Type in “make clean all install”, hit enter and it should be good to go.

  15. SilentCoder says:

    Hey, these are really great man thanks for posting them! Do you know where I could find some tutorials on C++ Development for the Wii? I Have tried to convert most of these, but run into some “most likely nooby” problems. Not trying to be a lazy ass, I have done my research, but just hoping you could maybe help me out. Again, great tuts, helped me out a lot!

    • teknecal says:

      Not that I know of however if you start learning C++ by itself, you will be able to apply what you’ve learned to the Wii.

      • SilentCoder says:

        K thanks, and yeah if I was sufficient in C++ I would easily be able to convert them, but as I’m just starting I was looking for a way to get started faster than learner ALL or more C++, then coming back to this. Do you know if there is a reference to the API? If not it’s cool, I’m just going to find functions I need, and write everything in C++ from scratch.

        • teknecal says:

          There isn’t too much documentation out for the Wii however all the functions that you can use are found in C:\devkitPro\libogc\include and all the Wii control access, etc is in C:\devkitPro\libogc\include\wiiuse,

          Other than that I would look through WiiBrew for some open source C++ Wii applications and try to learn from them.

  16. SilentCoder says:

    Hey, just wanted to say that I have found out how to use C++ and SDL on the Wii, just throwing that out there for people who might have wanted to get started, but couldn’t. Again, great tutorials; these got me on track for Wii Development. If anyone would like to know how to do this, please contact my email. (silentscriptz@yahoo.com)

  17. Jordan says:

    Hi teknecal, i just wanted to say that i think you doing a great job with these tutorials i`m under 12 and understand them completely. I was also wonder if you could recomend any father tutorials in Wii Homebrew Dev? Or a tutorial on how to use GRRLIB and would you recomend it, GRRLIB i mean?

    Thanks!

    • teknecal says:

      Hi Jordan,

      Another place you can check out for tutorials is Arikdo’s Blog: http://arikadosblog.blogspot.com/2009/06/coding-section.html

      I find GRRLIB to be easy to use (but I’m also using the older 3.0.1), I’m not sure of any tutorials for it other than the examples that included with it. Another way to check it out homebrew using it, the Homebrew Sorter uses it and it’s not too much of a complex application so you should find it easy to learn from (or so I hope).

      Hmm I should get back to writing more tutorials. :P

Leave a Reply