Reputation: 1203
I am attempting to deserialize some xml into a list of objects.
Where I am running into trouble is that the secondary objects Resources
within the Event
object doesn't have the values populated. For a little more background, this is a unity project, I'm deserializing a list of random events that can happen.
Below is the XML I am testing on:
<?xml version='1.0'?>
<Events>
<Event>
<Description>
this is a test
</Description>
<Reward>
<Food>
0
</Food>
<Energy>
1
</Energy>
<Happiness>
2
</Happiness>
<ShipHp>
3
</ShipHp>
<Garbage>
4
</Garbage>
</Reward>
<Cost>
<Food>
0
</Food>
<Energy>
1
</Energy>
<Happiness>
2
</Happiness>
<ShipHp>
3
</ShipHp>
<Garbage>
4
</Garbage>
</Cost>
<EventType>
Good
</EventType>
<EventId>
1
</EventId>
</Event>
<Event>
<Description>
this is a test
</Description>
<Reward>
<Food>
0
</Food>
<Energy>
1
</Energy>
<Happiness>
2
</Happiness>
<ShipHp>
3
</ShipHp>
<Garbage>
4
</Garbage>
</Reward>
<Cost>
<Food>
0
</Food>
<Energy>
1
</Energy>
<Happiness>
2
</Happiness>
<ShipHp>
3
</ShipHp>
<Garbage>
4
</Garbage>
</Cost>
<EventType>
Good
</EventType>
<EventId>
1
</EventId>
</Event>
</Events>
Here are the Objects (Event and Resources):
public class Event {
[XmlElement("Description")]
public string Description { get; set; }
[XmlElement("Reward")]
public Resources Reward { get; set; }
[XmlElement("Cost")]
public Resources Cost { get; set; }
[XmlElement("EventId")]
public int EventId { get; set; }
[XmlElement("EventType")]
public string EventType { get; set; }
}
[XmlType("Resources")]
public class Resources {
//Each prop can be extended to food being a Food object with expiry, etc
[XmlElement("Food")]
public int Food { get; set; } // 0 to cap
[XmlElement("Happiness")]
public int Happiness { get; set; } // 0 to 100
[XmlElement("Energy")]
public int Energy { get; set; } //0 to cap
[XmlElement("ShipHp")]
public int ShipHp { get; set; }// cap to 0
[XmlElement("Garbage")]
public int Garbage { get; set; } // 0 to cap
}
And here is the deserialzation code I have:
public class EventHandler : MonoBehaviour
{
[XmlInclude(typeof(Event))]
[XmlInclude(typeof(Resources))]
[Serializable, XmlRoot("Events")]
public class EventData
{
[XmlElement("Event")]
public List<Event> Events { get; set; }
public EventData()
{
List<Event> Events = new List<Event>();
}
}
List<Event> Events = new List<Event>();
public static EventHandler instance;
// Use this for initialization, called on script enabling
void Start()
{
var serializer = new XmlSerializer(typeof(EventData));
try
{
string xml = File.ReadAllText("Assets/TextResources/Events.xml");
xml = xml.Replace("\n", string.Empty);
xml = xml.Replace("\r", string.Empty);
xml = xml.Replace("\t", string.Empty);
using (var stringReader = new StringReader(xml))
{
using (var reader = XmlReader.Create(stringReader))
{
var result = (EventData)serializer.Deserialize(reader);
Events = result.Events;
}
}
}
catch(Exception ex)
{
Debug.Log(ex);
}
}
}
so from this code, my Event Objects are being populated with the values for Description
, EventType
and EventId
, but Reward
and Cost
Resources Objects are not being populated with the values and so far, I am at a loss why this is the case. For bonus points, I also am struggling to find a way to simply remove all of the dead space that I get from parsing a string. (ie Good gets changed to "\n\r Good ").
Upvotes: 0
Views: 1522
Reputation: 1203
OK. So I found a solution to the problem, I'm no expert with any of this as so if there is any corrections more experienced people want to add to improve the code I'll be happy to make changes.
First of all, there was a formating issue with my XML, To find this I actually serialized a list of event objects and used the resulting text to find a solution to that, Below is the revised text:
<ArrayOfEvent xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Event>
<Description>abc</Description>
<Reward>
<Food>0</Food>
<Happiness>2</Happiness>
<Energy>1</Energy>
<ShipHp>3</ShipHp>
<Garbage>4</Garbage>
</Reward>
<Cost>
<Food>0</Food>
<Happiness>2</Happiness>
<Energy>1</Energy>
<ShipHp>3</ShipHp>
<Garbage>4</Garbage>
</Cost>
<EventId>1</EventId>
<EventType>Good</EventType>
</Event>
<Event>
<Description>def</Description>
<Reward>
<Food>0</Food>
<Happiness>2</Happiness>
<Energy>1</Energy>
<ShipHp>3</ShipHp>
<Garbage>4</Garbage>
</Reward>
<Cost>
<Food>0</Food>
<Happiness>2</Happiness>
<Energy>1</Energy>
<ShipHp>3</ShipHp>
<Garbage>4</Garbage>
</Cost>
<EventId>2</EventId>
<EventType>Good</EventType>
</Event>
</ArrayOfEvent>
so first thing to notice is that I serialized a list of event objects, this the <ArrayOfEvent>
tag and the xml Name Space attributes that were generated. from that. this also meant that I had to change from the EventData
class to just a List<Event>
which was more convenient any way. as from my Event
and Resources
classes, I added the [Serializable, XmlRoot()]
tag to their classes.
One other thing to note is that i swapped EventType
from a string to an enum, the code for that enum will be provided below as well
These Fixes also fixed the formatting issues i was getting from the xml plain text to XmlReader
I will share the complete code below for future readers:
[Serializable, XmlRoot("Event")]
public class Event
{
[XmlElement("Description")]
public string Description { get; set; }
[XmlElement("Reward")]
public Resources Reward { get; set; }
[XmlElement("Cost")]
public Resources Cost { get; set; }
[XmlElement("EventId")]
public int EventId { get; set; }
[XmlElement("EventType")]
public EventType EventType { get; set; }
[XmlIgnore]
public string MarkUp { get; set; }
}
[Serializable, XmlRoot("Resources")]
public class Resources
{
//Each prop can be extended to food being a Food object with expiry, etc
[XmlElement("Food")]
public int Food { get; set; } // 0 to cap
[XmlElement("Happiness")]
public int Happiness { get; set; } // 0 to 100
[XmlElement("Energy")]
public int Energy { get; set; } //0 to cap
[XmlElement("ShipHp")]
public int ShipHp { get; set; }// cap to 0
[XmlElement("Garbage")]
public int Garbage { get; set; } // 0 to cap
}
[XmlType("EventType")]
public enum EventType
{
[XmlEnum("Good")]
Good = 0,
[XmlEnum("Bad")]
Bad,
[XmlEnum("Neutral")]
Neutral
}
public class EventHandler : MonoBehaviour
{
List<Event> Events = new List<Event>();
// Use this for initialization, called on script enabling
void Start()
{
try
{
var serializer = new XmlSerializer(typeof(List<Event>));
string xml = File.ReadAllText("Assets/TextResources/Events.xml");
xml = XDocument.Parse(xml).ToString(SaveOptions.DisableFormatting);
using (var stringReader = new StringReader(xml))
{
using (var reader = XmlReader.Create(stringReader))
{
var result = (List<Event>)serializer.Deserialize(reader);
Events = result;
}
}
}
catch (Exception ex)
{
Debug.Log(ex);
}
}
}
Basic serializer method
private void serializeList()
{
XmlSerializer ser = new XmlSerializer(typeof(List<Event>));
List<Event> list = new List<Event>();
list.Add(new Event { EventId = 1, Description = "abc", EventType = EventType.Good, Cost = new Resources { Food = 0, Energy = 1, Happiness = 2, ShipHp = 3, Garbage = 4 }, Reward = new Resources { Food = 0, Energy = 1, Happiness = 2, ShipHp = 3, Garbage = 4 } });
list.Add(new Event { EventId = 2, Description = "def", EventType = EventType.Good, Cost = new Resources { Food = 0, Energy = 1, Happiness = 2, ShipHp = 3, Garbage = 4 }, Reward = new Resources { Food = 0, Energy = 1, Happiness = 2, ShipHp = 3, Garbage = 4 } });
list.Add(new Event { EventId = 3, Description = "ghi", EventType = EventType.Good, Cost = new Resources { Food = 0, Energy = 1, Happiness = 2, ShipHp = 3, Garbage = 4 }, Reward = new Resources { Food = 0, Energy = 1, Happiness = 2, ShipHp = 3, Garbage = 4 } });
StreamWriter sw = new StreamWriter("Assets/TextResources/test.xml");
ser.Serialize(sw, list);
sw.Close();
}
Upvotes: 1