Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Xml Serialization? (how to read/write?)

Discussion in 'Scripting' started by ChrisSch, Feb 8, 2015.

  1. ChrisSch

    ChrisSch

    Joined:
    Feb 15, 2013
    Posts:
    763
    I made a mistake and posted this in answers, but its more of a discussion I guess, so here goes here too.

    I finally decided to stop being scared of xml and just learn it already and stop avoiding it. And now I'm so confused. I've been through dozens of google/forums/youtube searches and I can not understand this XML serialization. Its all alien language to me.

    First it took me a bit to realize that there's a few ways to go about reading and writing in xml files. There's that XmlDocument thing, and theres the serialization, and probably something else too. If I understood it correctly, those two things are different ways, and serializing is better. I sort of understood the document way, but serialization is confusing me even more.

    Now I've been to the unify community tutorial about it and I don't get it. How exactly are you reading or writing anything? I just don't see it happening in the code. And why do I need more than one script? I can't find a simple example at all on how to do this. Or I'm just too stupid for this.

    I wanted to learn by making a simple checklist program, and saving/loading the data from an xml file.

    Here's the short version:

    Code (CSharp):
    1. <Checklists>
    2.         <Checklist_1>
    3.             <Day_1>
    4.                 <Thing_1>example 1</Thing_1>
    5.                 <Thing_2>example 2</Thing_2>
    6.             </Day_1>
    7.             <Day_2>
    8.                 <Thing_1>example 1</Thing_1>
    9.                 <Thing_2>example 2</Thing_2>
    10.             </Day_2>
    11.         </Checklist_1>
    12.         <Checklist_2>
    13.             <Day_1>
    14.                 <Thing_1>example 1</Thing_1>
    15.                 <Thing_2>example 2</Thing_2>
    16.             </Day_1>
    17.             <Day_2>
    18.                 <Thing_1>example 1</Thing_1>
    19.                 <Thing_2>example 2</Thing_2>
    20.             </Day_2>
    21.         </Checklist_2>
    22.     </Checklists>
    Now what to do in actual code? It got confusing real fast because this turns out to be an array within an array within an array.

    This is as far as I got:

    Code (CSharp):
    1. [XmlRoot("Checklists")]
    2.     public class Checklists
    3.     {
    4.         [XmlArray("Checklist_1")]
    5.         [XmlArrayItem("Day_1")]
    6.         public List<Day_1> Checklist_1 = new List<Day_1>();
    7.     }
    8.    
    9.     public class Day_1
    10.     {
    11.         public string Thing_1;
    12.         public string Thing_2;
    13.     }
    Yeah I know... its sad. Now if this is correct at all, I don't understand the reading and writing part in the tutorial. I don't see any variables like health being assigned or read there. Is it because of the [XmlRoot("Checklists")] part? The vars and the xml file are being connected? And then the read write is just syncing everything from and to? What if you just wanted to sync one var? And how is then the public class Day_1 being connected with the file? Because its being declared in Checklists class? Or am I completely off on this?

    Thank you.
     
  2. tango209

    tango209

    Joined:
    Feb 23, 2011
    Posts:
    379
    You haven't defined anything for Day_2, it's expecting a Day_2 class.
     
  3. ChrisSch

    ChrisSch

    Joined:
    Feb 15, 2013
    Posts:
    763
    I didn't because I just wanted to test it. Its not giving me any errors so I thought it was fine. What do I do after I define day_2 as well? I still don't understand everything I mentioned.
     
  4. billykater

    billykater

    Joined:
    Mar 12, 2011
    Posts:
    327
    The XmlSerializer itself uses .NETs meta information / reflection system to look at your classes and decide what should go where.

    As shown in the sections "Reading data" and "Writing data" you tell the XmlSerializer which of your classes you want to serialize.The XmlSerializer class will now look at your type. If you don't define any XmlElement, XmlArray,... things the serializer will just assume they have to be named exactly like the field/type is. e.g. for your public string Thing_1 the XmlSerializer assumes that it will be named "Thing_1". Using things like XmlElement or XmlArray you can tell the XmlSerializer exactly how you want to name things. This data will then be used during the .Serialize() and Deserialize() call to map the xml you give it to the class you defined.

    Most of the "magical" code is hidden inside XmlSerializer so you don't have to manually code the whole process outlined above yourself by doing something like (as you assume) Health = int.Parse(xmlDoc.Element[0].GetElement("Health").InnerText).

    Generally the XmlSerializer approach isn't better than any other approach it just saves you a lot of time typing the same repetitive code like I showed as an example before at the expense of some runtime overhead which is mostly negligible for the typical scenario of saving and loading.
     
    ChrisSch likes this.
  5. bear_love_honey

    bear_love_honey

    Joined:
    Jan 7, 2015
    Posts:
    31
    Code (CSharp):
    1.             var encoding = Encoding.GetEncoding("UTF-16");
    2.             var fs = new FileStream(path, FileMode.Create);
    3.  
    4.             var w = new XmlSerializer(typeof(OptionsSettings));          
    5.             //<< -------------- "OptionsSettings" put here your class
    6.  
    7.             var sw = new StreamWriter(fs, encoding);
    8.             w.Serialize(sw, settings);
    9.             sw.Close();
    10.             fs.Close();
    So i no idia mb this help my simple code for serialize.

    <?xml version="1.0" encoding="utf-16"?>
    <OptionsSettings xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <Autosave>true</Autosave>
    <TurnsBeforeAutosave>10</TurnsBeforeAutosave>
    <DisplayResolutionWidth>1920</DisplayResolutionWidth>
    <DisplayResolutionHeight>1080</DisplayResolutionHeight>
    <Fullscreen>true</Fullscreen>
    <TextureQuality>0</TextureQuality>
    <Language>English</Language>
    <CameraMoveSpeed>20</CameraMoveSpeed>
    <CameraScrollSpeed>20</CameraScrollSpeed>
    <MusicVolume>51</MusicVolume>
    <SoundVolume>32</SoundVolume>
    </OptionsSettings>

    My class.
    Code (CSharp):
    1. [Serializable]
    2.     public class OptionsSettings
    3.     {
    4.         #region Options
    5.         // --------------------------- GamePlay ---------------------------
    6.         public bool Autosave { get; set; }
    7.         public int TurnsBeforeAutosave { get; set; }
    8.         // --------------------------- GamePlay ---------------------------
    9.  
    10.         // --------------------------- Graphics ---------------------------
    11.         public int DisplayResolutionWidth { get; set; }
    12.         public int DisplayResolutionHeight { get; set; }
    13.         public bool Fullscreen { get; set; }
    14.         public int TextureQuality { get; set; }
    15.         // --------------------------- Graphics ---------------------------
    16.  
    17.         // --------------------------- Interface --------------------------
    18.         public string Language { get; set; }
    19.         public int CameraMoveSpeed { get; set; }
    20.         public int CameraScrollSpeed { get; set; }
    21.         // --------------------------- Interface --------------------------
    22.  
    23.         // --------------------------- Sound ------------------------------
    24.         public int MusicVolume { get; set; }
    25.         public int SoundVolume { get; set; }
    26.         // --------------------------- Sound ------------------------------
    27.         #endregion Options
    28.     }

    If you wanna save simple settings, localisations etc use XML serialiser. Human can read this and change in xml file.
    If you wanna save some specific functions use only BinaryFormatter, this Formatter can serialize ALL like dictionary and others but human cant read this.
     
    Last edited: Feb 8, 2015
    ChrisSch likes this.
  6. ChrisSch

    ChrisSch

    Joined:
    Feb 15, 2013
    Posts:
    763
    Ok I got this far. Is this correct? If so, how do I now test it out? Since' it doesn't extend from monobehaviour I can't use the code on its own. Do I need another code after all? And extend this with it, or something?

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3. using System.Collections.Generic;
    4. using System.Xml;
    5. using System.Xml.Serialization;
    6. using UnityEngine.UI;
    7. using System.IO;
    8.  
    9. [XmlRoot("Checklists")]
    10. public class Checklists
    11. {
    12.     [XmlArray("Checklist_1")]
    13.     [XmlArrayItem("Day_1")]
    14.     public List<Day_1> Day_1 = new List<Day_1>();
    15.  
    16.     [XmlArray("Checklist_1")]
    17.     [XmlArrayItem("Day_2")]
    18.     public List<Day_2> Day_2 = new List<Day_2>();
    19.        
    20.     public void LoadFromXml()
    21.     {
    22.         string path = Application.dataPath + @"/Checklists.xml";
    23.         var serializer = new XmlSerializer(typeof(Checklists));
    24.         var stream = new FileStream(path, FileMode.Open);
    25.         var container = serializer.Deserialize(stream) as Checklists;
    26.         stream.Close();
    27.     }
    28.    
    29.     public void WriteToXml()
    30.     {
    31.         string path = Application.dataPath + @"/Checklists.xml";
    32.         var serializer = new XmlSerializer(typeof(Checklists));
    33.         var stream = new FileStream(path, FileMode.Create);
    34.         serializer.Serialize(stream, this);
    35.         stream.Close();
    36.     }
    37. }
    38.  
    39. public class Day_1
    40. {
    41.     public string Thing_1;
    42.     public string Thing_2;
    43. }
    44.  
    45. public class Day_2
    46. {
    47.     public string Thing_1;
    48.     public string Thing_2;
    49. }
     
  7. billykater

    billykater

    Joined:
    Mar 12, 2011
    Posts:
    327
    I suggest reading about C# coding works in general as you seem to only have experience with dragging scripts to gameobjects in unity. Generally you just use "new" to create a new instance of a class that doesn't have anything to do with unity.

    Your loading code also contains an error: You are not returning or doing anything with the "container" variable that comes out of the Deserialize call. After the function finishes it will just vanish with your data. In the wiki page I am making a static function that returns the loaded container (Another thing you might want to read up on before you start to use it).

    As for the usage: After you change the loading code to be like in the tutorial the next section "usage" works just as described there. You just call the static load function to load your data and then use the result of the function just like you would use a component after you called GetComponent(). And yes you will need another script that will call the load/save functions for you and do something with the data you have.

    Depending on what exactly you want to accomplish with the data there might be other options than using xml files which are more in sync with how the unity ecosystem works in general.
     
  8. ChrisSch

    ChrisSch

    Joined:
    Feb 15, 2013
    Posts:
    763
    Haha, thanks, no I have experience with C#, 99.5% of the time I code up what I need by my self, I almost never use someone else's code even it means reinventing the wheel. That being said, there's always new things to learn, and I still consider my self a beginner after 3 years.

    I'll go back to learn section, and revise on classes. I just avoided extending classes (not always), and rarely used anything that doesn't extend from monobehaviour, and xml is entirely new to me so I don't understand how it works with C# or Unity. So I sound pretty new to coding, apparently, and I feel like it, going into this Xml stuff. I've never dealt with xml before, so its really confusing to me. Which is a shame because its really useful, and I'm really starting to need it lately. I know there's plenty saving/loading assets out there, but like I said, for learning purposes I prefer to code everything up my self, instead of relying on other peoples work. At least until the point I understand how it works. Then I feel like its ok downloading/buying an asset that does it better. :)

    I'll Google and read up on Xml some more. I've been over, and over that, and other tutorials, questions, and topics, and I'm trying really hard but I just don't get it. Hopefully I figure it out soon, because I really need it for my next project, and I really really really do not want to download an asset that does it for me, without first learning how it works.
     
  9. tango209

    tango209

    Joined:
    Feb 23, 2011
    Posts:
    379
    Typically, that class will be used in a MonoBehaviour GameObject. So, you would create the data class, deserialize from your datastore, and then for anything you want visible in the inspector you would create a variable in your MonoBehaviour handle access to the data variable. Unfortunately, the inspector doesn't show properties, so you will have to handle updating your data class prior to Serializing it again.

    Something like this:

    Code (csharp):
    1.  
    2. ...
    3. public class UnityWrapper : MonoBehaviour
    4. {
    5.   public string StringData;
    6.  
    7.   public DataClass Data;
    8.  
    9.   public Start()
    10.   {
    11.     this.Data = DataClass.DeSerialize();
    12.     this.StringData = this.Data.StringData;
    13.   }
    14. }
    15.  
     
    ChrisSch likes this.
  10. billykater

    billykater

    Joined:
    Mar 12, 2011
    Posts:
    327
    I had the luck to know a lot about programming before unity came along (Good old Pascal/bios mode days ^^) so it was quite much easier for me when I wrote the tutorial to skim over the basics. Just keep asking questions and we will try to answer them as good as possible. tango209 already provided a good example of how it could be used.
    • Where exactly do you think you need xml files? Other formats might be just as good and a lot easier to process.
    • Should I write a more detailed explanation about the matching process? (as you already mentioned having trouble finding the place where Health gets assigned).
     
    ChrisSch likes this.
  11. ChrisSch

    ChrisSch

    Joined:
    Feb 15, 2013
    Posts:
    763
    Sorry for the late reply, I'm trying to readjust my sleep schedule so I'm pretty much tired all day now, and I'm having some other issues.

    Yeah, I didn't have that luck. I only messed with Basic once 10 years ago or so, and a bit with c++ along the way trying to do something in UDK and failing. And don't even get me started on our schools and college. I had one programming class using C which I passed without bothering to learn anything, that's how easy/useless it was.

    I need it to remember character customization, and because I personally want to learn it.
    No I don't want you to go through all the trouble. Unless its no issue to write a code that serializes one var back and forth, including the "frontline" script. But its ok its probably too much.

    I think my biggest problem is not understanding most of those phrases like serializer, and stream, and so on, and how they work. I tried reading the official documentation on Microsoft's .NET pages but its even more confusing. I rewatched all the learn tutorials involving classes tho, and I was missing some knowledge bits I found there. I guess I forgot because at the time of watching the first time I didn't think I'd be using those things right away, and then I never came back to it. Also never used some stuff like the "this" keyword or passing arguments into methods, and so on. Tried avoiding it as much as possible. But now I'm seeing how it makes things easier. :p

    I'm assuming, correct me if I'm wrong, to write something to to an xml file we first serialize it into a stream and then send it to the file? Because stream is like a pipe, and that's the only way the data can travel between your code and the xml file or any other file? And for reading you do the opposite with deserialize?

    I'm gonna keep looking over the dozen xml pages and examples I have open and try to hack something up. xD
     
  12. ChrisSch

    ChrisSch

    Joined:
    Feb 15, 2013
    Posts:
    763
    Ok what am I doing wrong here? I'm just trying to write for now.

    I got the class I want to serialize:

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3. using System.Xml;
    4. using System.Xml.Serialization;
    5. using System.IO;
    6.  
    7. [XmlRoot("Movies")]
    8. public class Movie
    9. {
    10.     [XmlElement("Title")]
    11.     public string Title = "Inception";
    12.     [XmlElement("Rating")]
    13.     public float rating = 9.5f;
    14.  
    15.     public void Write()
    16.     {
    17.         var serializer = new XmlSerializer(typeof(Movie));
    18.         var stream = new FileStream(Path.Combine(Application.persistentDataPath, "Movie.xml"), FileMode.Create);
    19.         serializer.Serialize(stream, this);
    20.         stream.Close();
    21.         Debug.Log ("2");
    22.     }
    23.      
    24. }
    And the class through which I call Write through the UI button:

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class GameUI : MonoBehaviour
    5. {
    6.     public void SaveToXml()
    7.     {
    8.         var movie = new Movie();
    9.         movie.Write();
    10.         Debug.Log ("1");
    11.     }
    12. }
    Both debugs happen, but nothing gets written to the xml file.

    PS. I never used stuff like "this" (yes I know its self explanatory) and "using", "FileMode.Open", "FileMode.Create", "return", and so on. So a lot of this is new to me. I just always worked differently.

    For some reason I think my mistake is at "var movie = new Movie();" but I don't know why, or what to change it to.
     
  13. ChrisSch

    ChrisSch

    Joined:
    Feb 15, 2013
    Posts:
    763
    Alright thanks guys, I figured out the writing part, its working now! Can you please explain to me the bits I commented on with question marks? And if my other assumptions are wrong.

    The class I wanna save to xml:

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3. using System.Xml;
    4. using System.Xml.Serialization;
    5. using System.IO;
    6.  
    7. [XmlRoot("Movies")]
    8. public class Movie
    9. {
    10.     [XmlElement("Title")]
    11.     public string title = "Inception";
    12.     [XmlElement("Rating")]
    13.     public float rating = 9.5f;
    14.  
    15.     public void Write(Movie thisMovie)
    16.     {
    17.         //And now the magic I don't quite understand...
    18.         var serializer = new XmlSerializer(typeof(Movie)); //we make a new serializer and tell it we'll be handling type Movie?
    19.         var stream = new FileStream(Path.Combine(Application.dataPath, "Movie.xml"), FileMode.Create); //we create a new filestream
    20.         //(why not StreamWriter?) and we assemble the path. then we create a new file, and overwrite old?
    21.         serializer.Serialize(stream, thisMovie); //the part where we write it into the file?
    22.         stream.Close(); //and we close it
    23.         //Debug.Log (thisMovie.title); //works, but not with persistentDataPath
    24.     }
    25. }
    Frontend code:

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class GameUI : MonoBehaviour
    5. {
    6.     //stuff changed ingame. for testing purposes a movie title and rating
    7.     public string movieTitleToSave;
    8.     public float ratingToSave;
    9.  
    10.     public void SaveToXml() //called through a button
    11.     {
    12.         var movie = new Movie(); //create an instance of the class we wanna serialize
    13.         movie.title = movieTitleToSave; //assign the new title to the instance
    14.         movie.rating = ratingToSave; //and rating
    15.         movie.Write(movie); //pass it on to the class for serialization
    16.         //Debug.Log ("1");
    17.     }
    18. }
    It works now. Is it the right way of doing it? Or did I overcomplicate it?
    Creates this:

    Code (CSharp):
    1. <?xml version="1.0" encoding="Windows-1252"?>
    2. <Movies xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    3.   <Title>Horrible Bosses</Title>
    4.   <Rating>9</Rating>
    5. </Movies>
    Now on to reading it!
     
  14. KelsoMRK

    KelsoMRK

    Joined:
    Jul 18, 2010
    Posts:
    5,539
    - Your Write method would make more sense taking 0 arguments and just referencing itself with "this".
    - FileMode.Create will overwrite an existing file
    - StreamWriter would probably be too "low-level" for something like this. In either case - the argument has to be a Stream and StreamWriter isn't a Stream (it's a TextWriter).
     
    ChrisSch likes this.
  15. tango209

    tango209

    Joined:
    Feb 23, 2011
    Posts:
    379
    That code works for me. Add Debug.Log(Application.persistentDataPath); in your Write() method and make sure you are looking in the right directory.
     
    ChrisSch likes this.
  16. ChrisSch

    ChrisSch

    Joined:
    Feb 15, 2013
    Posts:
    763
    Ok thanks guys. I made those changes. Umm... I'm lost again now.

    Now that its deserialized in the container variable. How can I bring it back to the front end code?

    Class to save:
    Code (CSharp):
    1. .....
    2.  
    3. public void Read()
    4.     {
    5.         var serializer = new XmlSerializer(typeof(Movie));
    6.         var stream = new FileStream(Path.Combine(Application.dataPath, "Movie.xml"), FileMode.Open);
    7.         var container = serializer.Deserialize(stream) as Movie;
    8.         stream.Close();
    9.     }
    Frontend:
    Code (CSharp):
    1. public void LoadFromXml()
    2.     {
    3.         var movie = new Movie();
    4.         movie.Read();
    5.         movieTitleToSave.text = movie.title;
    6.         ratingToSave.text = movie.rating;
    7.     }
    I know I can just do like this:

    Code (CSharp):
    1. public void Read()
    2.     {
    3.         var serializer = new XmlSerializer(typeof(Movie));
    4.         var stream = new FileStream(Path.Combine(Application.dataPath, "Movie.xml"), FileMode.Open);
    5.         var container = serializer.Deserialize(stream) as Movie;
    6.         title = container.title;
    7.         rating = container.rating;
    8.         stream.Close();
    9.     }
    But is there a better way to send the entire container back to the frontend, and then assigning those variables through it there? (lol I'm pressing F7 so much I was trying to post this by pressing F7)
     
  17. KelsoMRK

    KelsoMRK

    Joined:
    Jul 18, 2010
    Posts:
    5,539
    Code (csharp):
    1.  
    2.  
    3. public Movie Read()
    4. {
    5.     // load your stuff like you are
    6.     return serializer.Deserialize(stream) as Movie;
    7. }
    8.  
    It seems like you're getting confused because you're using the thing to load and save itself. That'd probably be better served in some kind of utility class that returns new instances of those things for you. As it stands now you're making a new empty thing just to load another new thing from a file.
     
  18. ChrisSch

    ChrisSch

    Joined:
    Feb 15, 2013
    Posts:
    763
    You mean like this? (and yes lots of confusion going on here, but clearer than two days ago)

    Code (CSharp):
    1.     public Movie Read()
    2.     {
    3.         var serializer = new XmlSerializer(typeof(Movie));
    4.         var stream = new FileStream(Path.Combine(Application.dataPath, "Movie.xml"), FileMode.Open);
    5.         return serializer.Deserialize(stream) as Movie;
    6.         stream.Close();
    7.     }
    I tried that first but it doesnt give me the deserialized vars, it gives me the ones from this class, which is "Inception" and "9.5". And makes "stream.Close()" unreachable. But if I put return after, it tells me I'm trying to return something that's already disposed of. Did I not do it right? :S
     
  19. KelsoMRK

    KelsoMRK

    Joined:
    Jul 18, 2010
    Posts:
    5,539
    I would do it like this
    Code (csharp):
    1.  
    2. public Movie Read()
    3. {
    4.     XmlSerializer serial = new XmlSerializer(typeof(Movie));
    5.     Movie movie = null;
    6.     using (FileStream steam = new FileStream(...))
    7.     {
    8.         movie = serial.Deserialize(stream) as Movie;
    9.     }
    10.     return movie;
    11. }
    12.  
     
  20. ChrisSch

    ChrisSch

    Joined:
    Feb 15, 2013
    Posts:
    763
    You see, that's what I don't understand. That's what billykater did in his tutorial. Whats "using" and how does it work? I can't find documentation on it.

    And damn, it still gives me the same result.

    Code (CSharp):
    1. public Movie Read()
    2.     {
    3.         XmlSerializer serial = new XmlSerializer(typeof(Movie));
    4.         Movie movie = null;
    5.         using (FileStream stream = new FileStream(Path.Combine(Application.dataPath, "Movie.xml"), FileMode.Open))
    6.         {
    7.             movie = serial.Deserialize(stream) as Movie;
    8.         }
    9.         return movie;
    10.     }
    EDIT:

    I tried delaying changing vars in the front end by 1 second, just in case it somehow got assigned before it was returned, or something, but its not the case.
     
    Last edited: Feb 11, 2015
  21. KelsoMRK

    KelsoMRK

    Joined:
    Jul 18, 2010
    Posts:
    5,539
  22. ChrisSch

    ChrisSch

    Joined:
    Feb 15, 2013
    Posts:
    763
    Thanks KelsoMRK. I get it now. Still can't figure out how to load it tho. Except the first way I tried. Here's the project files if anyone wants to take a look.

    Writing works fine, but the reading is refusing to. >.<
     

    Attached Files:

  23. KelsoMRK

    KelsoMRK

    Joined:
    Jul 18, 2010
    Posts:
    5,539
    Post the error messages you're getting.
     
  24. ChrisSch

    ChrisSch

    Joined:
    Feb 15, 2013
    Posts:
    763
    That's the thing, I'm not getting any error messages.

    Frontend:
    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3. using UnityEngine.UI;
    4.  
    5. public class GameUI : MonoBehaviour
    6. {
    7.     public InputField movieTitleToSave;
    8.     public InputField ratingToSave;
    9.  
    10.     public void SaveToXml()
    11.     {
    12.         var movie = new Movie();
    13.         movie.title = movieTitleToSave.text;
    14.         movie.rating = ratingToSave.text;
    15.         movie.Write();
    16.     }
    17.  
    18.     public void LoadFromXml()
    19.     {
    20.         Movie movie = new Movie();
    21.         movie.Read();
    22.         movieTitleToSave.text = movie.title;
    23.         ratingToSave.text = movie.rating;
    24.     }
    25. }
    Class we're saving/reading:

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3. using System.Xml;
    4. using System.Xml.Serialization;
    5. using System.IO;
    6.  
    7. [XmlRoot("Movies")]
    8. public class Movie
    9. {
    10.     [XmlElement("Title")]
    11.     public string title = "Inception";
    12.     [XmlElement("Rating")]
    13.     public string rating = "9.5";
    14.  
    15.     public void Write()
    16.     {
    17.         var serializer = new XmlSerializer(typeof(Movie));
    18.         var stream = new FileStream(Path.Combine(Application.dataPath, "Movie.xml"), FileMode.Create);
    19.         serializer.Serialize(stream, this);
    20.         stream.Close();
    21.     }
    22.  
    23.     public Movie Read()
    24.     {
    25.         var serializer = new XmlSerializer(typeof(Movie));
    26.         using (var stream = new FileStream(Path.Combine(Application.dataPath, "Movie.xml"), FileMode.Open))
    27.         {
    28.             return serializer.Deserialize(stream) as Movie;
    29.         }
    30.     }
    31. }
    XML file: (current one)

    Code (CSharp):
    1. <?xml version="1.0" encoding="Windows-1252"?>
    2. <Movies xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    3.   <Title>Doom 2003</Title>
    4.   <Rating>8.3</Rating>
    5. </Movies>
    I used write to change it to "Doom 2003" and "8.3", and now I wanna test the loading, but it always loads "Inception" and "9.5".

    Unless I change the read to something like:

    Code (CSharp):
    1. public void Read()
    2.     {
    3.         var serializer = new XmlSerializer(typeof(Movie));
    4.         var stream = new FileStream(Path.Combine(Application.dataPath, "Movie.xml"), FileMode.Open);
    5.         var container = serializer.Deserialize(stream) as Movie;
    6.         title = container.title;
    7.         rating = container.rating;
    8.         stream.Close();
    9.     }
    But I assumed "return" would do that for me?
     
  25. KelsoMRK

    KelsoMRK

    Joined:
    Jul 18, 2010
    Posts:
    5,539
    When you return a value from Read() you need to assign the result to something. You never do so the stuff you load never gets stored anywhere and all you get are the default values.

    It sounds like you might need to back track a little bit and get a better grasp of the language before going down this path.
     
  26. ChrisSch

    ChrisSch

    Joined:
    Feb 15, 2013
    Posts:
    763
    I'm backtracking as I go along. I never used the return keyword for anything, so I'm a bit confused.

    Is this what you mean? That's the only way it loads. But in billykater's tutorial I don't see him assigning anything before return.

    Code (CSharp):
    1. public Movie Read()
    2.     {
    3.         var serializer = new XmlSerializer(typeof(Movie));
    4.         using (var stream = new FileStream(Path.Combine(Application.dataPath, "Movie.xml"), FileMode.Open))
    5.         {
    6.             var movie = serializer.Deserialize(stream) as Movie;
    7.             title = movie.title;
    8.             rating = movie.rating;
    9.             return movie;
    10.         }
    11.     }
     
  27. KelsoMRK

    KelsoMRK

    Joined:
    Jul 18, 2010
    Posts:
    5,539
    No.

    Code (csharp):
    1.  
    2. Movie newMovie = movie.Read();
    3.  
     
  28. ChrisSch

    ChrisSch

    Joined:
    Feb 15, 2013
    Posts:
    763
    Like so? Its working like this too. You're right I am missing some fundamental stuff, like I said, I worked around it so far, but no running from it now. On the plus side I'm filling in the gaps and learning a lot of new things now. :)

    Frontend code (GameUI.cs):
    Code (CSharp):
    1. public void LoadFromXml()
    2.     {
    3.         Movie movie = new Movie();
    4.         movie.Read();
    5.         Movie newMovie = movie.Read();
    6.         movieTitleToSave.text = newMovie.title;
    7.         ratingToSave.text = newMovie.rating;
    8.     }
     
  29. KelsoMRK

    KelsoMRK

    Joined:
    Jul 18, 2010
    Posts:
    5,539
    You really need to move the Read() method from where it is because you're still instantiating a new thing just to read the file. Also, you're calling Read twice - line 4 is redundant.

    For the sake of argument - you could just make Read static
    Code (csharp):
    1.  
    2. public static Movie Read()
    3.  
    Then remove line 3 and change line 5 to be
    Code (csharp):
    1.  
    2. Movie newMovie = Movie.Read();
    3.  
     
    ChrisSch likes this.
  30. ChrisSch

    ChrisSch

    Joined:
    Feb 15, 2013
    Posts:
    763
    Thanks! That did the trick. Yeah I noticed I'm calling Read twice, that would have been my next question. I'll pause now, and go over everything, before going further with this. Thank you for bearing with me. :D