- Home /
[SOLVED] XML Deserialization of a single XML file into multiple objects
Greetings. I am new to XML serialization/deserialization and need some help. I have a huge XML file (let's call it ItemDatabase.xml
), and inside of it I want to get all the individual items out of it and assign them to instances of a class I have made in my scripts. Like so:
public List<Item> lootPileContents = new List<Item>();
public void CreateLootPile(TextAsset itemDatabase) {
XmlSerializer serializer = new XmlSerializer(typeof(Item));
for(int i = 0; i < LOOT_PILE_ITEM_LIMIT; i++){
using(StringReader reader = new StringReader(itemDatabase.text) {
lootPileContents[i] = serializer.Deserialize(reader) as Item;
}
}
}
The issue I have with the above code is that I don't know if the whole XML file will just be treated as one whole Item
. The XML file is setup like this:
<?xml version="1.0" encoding="UTF-8"?>
<items>
<category>
<name>A precious stone</name>
<group>
<item>
<word>Pearl</word>
<proportion>0.22</proportion>
</item>
<item>
<word>Gem</word>
<proportion>0.17</proportion>
</item>
<item>
<word>Amethyst</word>
<proportion>0.18</proportion>
</item>
<item>
<word>Opal</word>
<proportion>0.18</proportion>
</item>
</group>
<group>
<item>
<word>Silver</word>
<proportion>0.08</proportion>
</item>
<item>
<word>Jade</word>
<proportion>0.06</proportion>
</item>
<item>
<word>Quartz</word>
<proportion>0.06</proportion>
</item>
<item>
<word>Turquoise</word>
<proportion>0.05</proportion>
</item>
</group>
</category>
...
</items>
I have public members in the Item class to handle category, group, category name, and proportion (All named appropriately: category
, group
, categoryName
, proportion
). So to reiterate: I need to grab individual items out of the XML file and assign them to instances of the Item
class that is in a generic collection.
Eventually I would want to pick an item out at random with some additional constraints (no duplicates or other items from that group/category, etc.)
Any help would be greatly appreciated.
Edit - Update #1: Here is the Item.cs
class
using System.IO;
using System.Xml;
using System.Xml.Serialization;
[XmlArrayItem("item")]
public class Item {
[XmlNode("name")]
public string categoryName;
[XmlNode("word")]
public string word;
[XmlNode("proportion")]
public float proportion;
public Item() {
categoryName = "";
word = "";
proportion = 0.0f;
}
}
Edit - Update #2: I have created container classes for each of the different groupings in the Xml. I also rewrote the Item class to make it more simple.
Revised Item.cs
:
using System.Xml;
using System.Xml.Serialization;
public class Item {
[XmlElement("word")]
public string word;
public ItemTest() {
}
}
New ItemGroup.cs
class:
using System.Xml.Serialization;
using System.Collections.Generic;
public class ItemGroup {
[XmlArray("group"), XmlArrayItem("item")]
public List<ItemGroup> items = new List<ItemGroup>();
public ItemGroup() {
}
}
New ItemCategory.cs
class
using System.Xml.Serialization;
using System.Collections.Generic;
public class ItemCategory {
[XmlElement("name")]
public string name;
[XmlArray("category"), XmlArrayItem("group")]
public List<ItemGroup> groups = new List<ItemGroup>();
public ItemCategory() {
}
}
I have been testing using the smallest unit (item in this case) and adding layers of complexity to test. Currently I am able to correctly deserialize everything at and below the "ItemGroup" level. I can deserialize the following just fine:
<items>
<group>
<item>
<word>Pancake</word>
</item>
<item>
<word>Waffle</word>
</item>
</group>
</items>
Using this code:
ItemGroup DeserializeGroup(string p) {
XmlRootAttribute root = new XmlRootAttribute ("items");
root.IsNullable = true;
XmlSerializer serializer = new XmlSerializer (typeof(ItemGroup), root);
using (FileStream stream = new FileStream(p, FileMode.Open)) {
return serializer.Deserialize(stream) as ItemGroup;
}
}
But as soon as I add another layer of complexity I only get the first layer of information. So something like this:
<items>
<category>
<name>Breakfast Food</name>
<group>
<item>
<word>Pancake</word>
</item>
<item>
<word>Waffle</word>
</item>
</group>
<group>
<item>
<word>Bacon</word>
</item>
<item>
<word>Eggs</word>
</item>
</group>
</category>
</items>
With deserialization code:
ItemCategory DeserializeCategory(string p) {
XmlRootAttribute root = new XmlRootAttribute ("items");
root.IsNullable = true;
XmlSerializer serializer = new XmlSerializer (typeof(ItemCategory), root);
using (FileStream stream = new FileStream(p, FileMode.Open)) {
return serializer.Deserialize(stream) as ItemCategory;
}
}
Will only yield having the groups list in category being populated with empty groups. So how can I enable deep serialization of the rest of the XML file?
Answer by Senuska · Jul 13, 2015 at 08:46 PM
I Found that someone has asked a similar question when I was searching for deserializing nested Xml collections: XML Deserialize Nested Collection. Turns out you can't use a [Xml---("---")] for the same tag more than once. Replacing the XmlArray and XmlArrayItem with XmlElement of the collection type works well.
Answer by CaKeMeaT · Jul 10, 2015 at 11:25 PM
XmlSerializer serializer = new XmlSerializer(typeof(Item));
is dealing specifically with the serialization of type Item.
I would utilize your X$$anonymous$$L as if it was a big list of individual items:
XmlSerializer serializer = new XmlSerializer(typeof(ListOfItems));
after deserialization of your "ListOfItems" I would match up the values to where you actually want them.
$$anonymous$$yList.thingy = DeserializedList.thingy
Your answer
Follow this Question
Related Questions
Xml Serialization of "sub classes" 0 Answers
URGENT - Cannot be serialized because it does not have a default public constructor.... 1 Answer
Error while deserializing an xml file 2 Answers
Unity Serialization with XML Root problem: 'Does Not Denote Valid Type' 0 Answers
ArgumentException: Path is empty while saving data in an XML 0 Answers