- What to expect
Data can be saved in many different formats. Xml is one of the more standardized ones. There are several different ways to parse an xml file. The XmlSerializer is one of the easiest way included directly with every .NET/mono installation.
The whole tutorial is available at the unify wiki too http://www.unifycommunity.com/wiki/index.php?title=Saving_and_Loading_Data:_XmlSerializer
The goal of this tutorial will be to save and load data with the following xml structure.
<MonsterCollection>
<Monsters>
<Monster name="a">
<Health>5</Health>
</Monster>
<Monster name="b">
<Health>3</Health>
</Monster>
</Monsters>
</MonsterCollection>
-
This is the C# version for the Unityscript/Javascript version look here*
-
Preparing the Monster class
-
Monster.cs*
using System.Xml;
using System.Xml.Serialization;
public class Monster
{
[XmlAttribute("name")]
public string Name;
public int Health;
}
The XmlSerializer automatically knows about each public variable or read/write property in any type you can throw at it. Primitive types like string, int, float and enums can be automatically serialized.
Through attributes you can further tell the XmlSerializer about how you want the xml to be parsed.
By default every variable will be translated to one xml element (e.g. 5).
If you want it to be parsed as attribute ( e.g. ) you have to use XmlAttribute(name) like in the sample.
- The MonsterContainer
To store all of the monsters we need a list of all of them.
using System.Collections.Generic;
using System.Xml;
[XmlRoot("MonsterCollection")]
public class MonsterContainer
{
[XmlArray("Monsters"),XmlArrayItem("Monster")]
public List<Monster> Monsters = new List<Monster>();
}
The root element of each xml file should be annotated with the XmlRoot attribute. This way the XmlSerializer will know which XmlElement is to be expected as the root element.
A list is just like an array with the added bonus of being able to add new elements easily.
With XmlArray and XmlArrayItem you can declare how the list should be represented within the xml file.
- Reading data
var serializer = new XmlSerializer(typeof(MonsterContainer));
var stream = new FileStream(path, FileMode.Open);
var container = serializer.Deserialize(stream) as MonsterContainer;
stream.Close();
- Writing data
var serializer = new XmlSerializer(typeof(MonsterContainer));
var stream = new FileStream(path, FileMode.Create));
serializer.Serialize(stream, this);
stream.Close();
Make sure you call the Close or Dispose method after writing else the file you just created will only be created in memory and will never be actually written to the file.
- Convenience
I personally like putting read and write methods in the root class like this.
using System.Collections.Generic;
using System.Xml;
using System.Xml.Serialization;
using System.IO;
[XmlRoot("MonsterCollection")]
public class MonsterContainer
{
[XmlArray("Monsters"),XmlArrayItem("Monster")]
public Monster[] Monsters;
public void Save(string path)
{
var serializer = new XmlSerializer(typeof(MonsterContainer));
using(var stream = new FileStream(path, FileMode.Create))
{
serializer.Serialize(stream, this);
}
}
public static MonsterContainer Load(string path)
{
var serializer = new XmlSerializer(typeof(MonsterContainer));
using(var stream = new FileStream(path, FileMode.Open))
{
return serializer.Deserialize(stream) as MonsterContainer;
}
}
}
- Usage
- Reading*
var monsterCollection = MonsterContainer.Load(Path.Combine(Application.dataPath, "monsters.xml"));
- Writing*
monsterCollection.Save(Path.Combine(Application.persistentDataPath, "monsters.xml"));
As you may have noticed I am using Application.dataPath and Application.persistentDataPath in my pathes.
-
Application.dataPath points to your asset/project directory.
If you have your xml file stored in your project at DataFiles/test/monsters.xml you can access it by using Path.Combine(Application.dataPath, “DataFiles/test/monsters.xml”); -
Application.persistentDataPath points to a directory where your application can store user specific data on the target computer. This is a recommended way to store files locally for a user like highscores or savegames.
Additional Notes
- You have to define at least one constructor without parameters for the XmlSerializer to work correctly
- If your class contains a struct or class Variable that contains the supported data types the XmlSerializer can automatically serialize it too.
- All fields and properties you want to serialize have to be public!
- If you want to serialize a property both a getter and a setter have to be present
More information about the the xmlserializer and all its special features can be found at
Any feedback is welcome. Should I continue with other tutorials about reading and writing data(Textfiles, Binary files) and provide some samples for unityscript and boo?