Another way to create XML data structures from game objects and properties is by serializing the contents of an object automatically. This technique automatically generates XML for all the public properties of an object.
In the 0423_08_06
folder, you'll find the listings for all four classes described in this recipe.
To create XML text data through serialization, perform the following steps:
PlayerScore
:// file: PlayerScore.cs public class PlayerScore { public string name; public int score; // default constructor, needed for serialization public PlayerScore() {} public PlayerScore(string newName, int newScore) { name = newName; score = newScore; } }
SerializeManager
:// file: SerializeManager.cs // // acknowledgements - this code has been adapted from: //www.eggheadcafe.com/articles/system.xml.xmlserialization.asp using System.Xml; using System.Xml.Serialization; using System.IO; using System.Text; using System.Collections.Generic; public class SerializeManager<T> { public string SerializeObject(T pObject) { string XmlizedString = null; MemoryStream memoryStream = new MemoryStream(); XmlSerializer xs = new XmlSerializer(typeof(T)); XmlTextWriter xmlTextWriter = new XmlTextWriter(memoryStream, Encoding.UTF8); xs.Serialize(xmlTextWriter, pObject); memoryStream = (MemoryStream)xmlTextWriter.BaseStream; XmlizedString = UTF8ByteArrayToString(memoryStream.ToArray()); return XmlizedString; } public object DeserializeObject(string pXmlizedString) { XmlSerializer xs = new XmlSerializer(typeof(T)); MemoryStream memoryStream = new MemoryStream(StringToUTF8ByteArray(pXmlizedString)); return xs.Deserialize(memoryStream); } private string UTF8ByteArrayToString(byte[] characters) { UTF8Encoding encoding = new UTF8Encoding(); string constructedString = encoding.GetString(characters); return (constructedString); } private byte[] StringToUTF8ByteArray(string pXmlString) { UTF8Encoding encoding = new UTF8Encoding(); byte[] byteArray = encoding.GetBytes(pXmlString); return byteArray; } }
// file: SerialiseToXML.cs using UnityEngine; using System.Collections; using System.Collections.Generic; public class SerialiseToXML : MonoBehaviour { private string output = "(nothing yet)"; void Start () { SerializeManager<PlayerScore> serializer = new SerializeManager<PlayerScore>(); PlayerScore myData = new PlayerScore("matt", 200); output = serializer.SerializeObject(myData); } void OnGUI() { GUILayout.Label( output ); } }
The Start()
method creates serializer
, a new SerializeManager()
object for objects of the PlayerScore
class. A new PlayerScore
object, myData
, is created with the values "Matt"
and 200
. The serializer
object is then passed the myData
object, and the XML text data is returned as a string and stored in output
. Our OnGUI()
method displays the contents of output
.
The SerializeManager
class has been adapted from the code published by EggHeadCafe at the following URL:
www.eggheadcafe.com/articles/system.xml.xmlserialization.asp
You shouldn't need to worry too much about understanding all the code in this class—unless you want to :-). We have adapted the class so that it can be used for any data object class via C# generics; all you need to do is the following:
<PlayerScore>
with <YourDataClassName>
when declaring and creating an instance of SerializationManager
; in our example, this is in the first statement of the Start()
methodserializer.SerializeObject()
The following site is a good place to learn more about Unity XML serialization:
http://wiki.unity3d.com/index.php?title=Saving_and_Loading_Data:_XmlSerializer
Some details you don't want to miss:
Just having public properties is generally considered poor practice, because any part of an application with a reference to an object can make any kind of changes to those properties. However, if you wish to use this serialization recipe, you have to have public properties.
A good solution is to provide public accessor methods, which behave like public properties but allow you to add a validation code behind the get/set methods for each corresponding hidden private property. Here, we have provided such an improved implementation of the PlayerScore
class, PlayerScore2
. Data is stored in the private variables _name
and _score
; they are accessed via the public variables Name
and Score
, which have get/set statements that handle changes to the private variables, and for which the appropriate validation logic could be implemented (for example, only changing Score
if the new score is zero or higher, to prevent negative scores):
// file: PlayerScore2.cs using System.Xml.Serialization; [XmlRoot("player_score_2")] public class PlayerScore2 { private string _name; private int _score; [XmlElement("name")] public string Name { get{ return _name; } set{ _name = value; } } [XmlElement("score")] public int Score { get{ return _score;} set{ _score = value;} } // default constructor, needed for serialization public PlayerScore2() {} public PlayerScore2(string newName, int newScore) { Name = newName; Score = newScore; } }
Variable naming styles vary between programmers and organizations. One approach to naming private member variables is to prefix them with an underscore (as we have done in the previous code snippet). An alternative, which some programmers prefer, involves using no underscore and disambiguating the argument of a setter method from the member variable with the same identifier by using keyword this
; for example, this.name = name
.
18.118.189.251