How to Deserialize Xml into List<T>

Is it possible to deserialize XML into List T ?

You can encapsulate the list trivially:

using System;
using System.Collections.Generic;
using System.Xml.Serialization;

[XmlRoot("user_list")]
public class UserList
{
public UserList() {Items = new List<User>();}
[XmlElement("user")]
public List<User> Items {get;set;}
}
public class User
{
[XmlElement("id")]
public Int32 Id { get; set; }

[XmlElement("name")]
public String Name { get; set; }
}

static class Program
{
static void Main()
{
XmlSerializer ser= new XmlSerializer(typeof(UserList));
UserList list = new UserList();
list.Items.Add(new User { Id = 1, Name = "abc"});
list.Items.Add(new User { Id = 2, Name = "def"});
list.Items.Add(new User { Id = 3, Name = "ghi"});
ser.Serialize(Console.Out, list);
}
}

Deserialize xml into list of objects

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();
}

Deserializing XML from stream to List T

One way of achieving the result you are expecting is like below

[XmlRoot(ElementName = "invoices")]
public class Invoices
{
[XmlElement(ElementName = "invoice")]
public List<Invoice> Invoice { get; set; }
}

[XmlRoot("invoice")]
public class Invoice
{
[XmlElement(ElementName = "description", IsNullable = true)]
public string Description { get; set; }

[XmlElement(ElementName = "invoice_date")]
public string InvoiceDate { get; set; }

[XmlElement(ElementName = "invoice_number")]
public string InvoiceNumber { get; set; }

[XmlElement(ElementName = "date_due")]
public string DateDue { get; set; }

[XmlElement(ElementName = "amount")]
public string Amount { get; set; }
}

And your parse records function should like something like below

public Invoices ParseRecords(Stream stream)
{
Invoices invoices;

try
{
stream.Position = 0;
XmlSerializer serializer = new XmlSerializer(typeof(Invoices);
invoices = (Invoices)serializer.Deserialize(stream);
}
catch (Exception ex)
{
log.Error(ex);
}

return invoices;
}

Deserializing XML to objects which has list of objects in C#

Variable need to be public.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Serialization;
using System.IO;

namespace ConsoleApplication1
{
class Program
{
const string FILENAME = @"c:\temp\test.xml";
static void Main(string[] args)
{
string xml = File.ReadAllText(FILENAME);

XmlSerializer serializer = new XmlSerializer(typeof(Result));
StringReader rdr = new StringReader(xml);
Result resultingMessage = (Result)serializer.Deserialize(rdr);


}
}
public enum ReportType
{
[XmlEnum("0")]
InternalErrorReport,
[XmlEnum("1")]
ErrorReport,
[XmlEnum("2")]
InternalSuccessReport
}

[XmlRoot(ElementName = "result")]
public class Result
{
[XmlElement(ElementName = "reporttype")]
public ReportType reportType { get; set; }
public Items items { get; set; }
public string error { get; set; }


}
[XmlRoot("items")]
public class Items
{
[XmlElement(ElementName = "item")]
public List<Item> items = new List<Item>();
}
[XmlRoot("item")]
public class Item
{
[XmlElement(ElementName = "sku")]
public string sku { get; set; }
[XmlElement(ElementName = "style")]
public string style { get; set; }
[XmlElement(ElementName = "reason")]
public string reason { get; set; }
}
}

Deserializing XML to a List

You XML data is wrong . You don't get an exception on Deserialization?

Boxdata element closes before it starts.
Correct examples:

<boxdata></boxdata>
<boxdata/>

Your case looks like:

</boxdata>

So the correct xml you should try to serialize should be:

<?xml version="1.0" encoding="UTF-8"?>
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Header />
<S:Body>
<ns2:PushDataArray xmlns:ns2="http://sender.push.ws.nicbase.com/">
<pushDataArray>
<assetId>00000993</assetId>
<assetName>Some name</assetName>
<boxData/>
<externalCustomerIdentification>DFDS</externalCustomerIdentification>
</pushDataArray>
<pushDataArray>
<assetId>00000993</assetId>
<assetName>Some name</assetName>
<boxData/>
<externalCustomerIdentification>DFDS</externalCustomerIdentification>
</pushDataArray>
<pushDataArray>
<assetId>00000993</assetId>
<assetName>Some name</assetName>
<boxData/>
<externalCustomerIdentification>DFDS</externalCustomerIdentification>
</pushDataArray>
</ns2:PushDataArray>
</S:Body>
</S:Envelope>

Also modify your classes to the following:

[SerializableAttribute()]
[XmlTypeAttribute(AnonymousType = true, Namespace = "http://schemas.xmlsoap.org/soap/envelope/")]
[XmlRootAttribute(Namespace = "http://schemas.xmlsoap.org/soap/envelope/", IsNullable = false)]
public partial class Envelope
{
public object Header { get; set; }
public EnvelopeBody Body { get; set; }
}

[SerializableAttribute()]
[XmlTypeAttribute(AnonymousType = true, Namespace = "http://schemas.xmlsoap.org/soap/envelope/")]
public partial class EnvelopeBody
{
[XmlArrayAttribute(Namespace = "http://sender.push.ws.nicbase.com/")]
[XmlArrayItemAttribute("pushDataArray", Namespace = "", IsNullable = false)]
public pushDataArray[] PushDataArray { get; set; }
}

[SerializableAttribute()]
[XmlTypeAttribute(AnonymousType = true)]
[XmlRootAttribute(Namespace = "", IsNullable = false)]
public partial class pushDataArray
{
public ushort assetId { get; set; }

public string assetName { get; set; }

public object boxData { get; set; }

public string externalCustomerIdentification { get; set; }
}

I tried your code with the above xml data and classes and it works. Give it a try.

How to deserialize xml into list in c#

If you are using the following class definitions then your deserializer + serializer code will work fine with single or multiple <Match> nodes:

[XmlRoot]
public class BetradarLiveOdds
{
[XmlElement]
public Match[] Match { get; set; }

[XmlAttribute(AttributeName = "timestamp")]
public string Timestamp { get; set; }
[XmlAttribute(AttributeName = "status")]
public string Status { get; set; }
}
  • I have omitted all those attributes, which are unnecessary
  • XmlSerializer can work with List<Match> as well if you need a list rather than an array
public class Match
{
public MatchInfo MatchInfo { get; set; }
public Translation Translation { get; set; }

[XmlAttribute(AttributeName = "active")]
public string Active { get; set; }
[XmlAttribute(AttributeName = "booked")]
public string Booked { get; set; }
[XmlAttribute(AttributeName = "matchid")]
public string Matchid { get; set; }
[XmlAttribute(AttributeName = "status")]
public string Status { get; set; }
}
public class MatchInfo
{
public string DateOfMatch { get; set; }
public Common Sport { get; set; }
public Common Category { get; set; }
public Common Tournament { get; set; }
public Common HomeTeam { get; set; }
public Common AwayTeam { get; set; }
public string TvChannels { get; set; }
}
  • I've introduced a Common class which can be used in MatchInfo and in Translation
  • In case of MatchInfo the Name collections will be empty (an initialized list with 0 element)
    • If that's undesirable then you can introduce yet another class which will not contain the Name property
public class Translation
{
public Common Sport { get; set; }
public Common Category { get; set; }
public Common Tournament { get; set; }
public Common HomeTeam { get; set; }
public Common AwayTeam { get; set; }
}
public class Common
{
[XmlAttribute(AttributeName = "id")]
public string Id { get; set; }
[XmlText]
public string Text { get; set; }
[XmlElement]
public List<Name> Name { get; set; }
}
public class Name
{
[XmlAttribute(AttributeName = "lang")]
public string Lang { get; set; }
[XmlText]
public string Text { get; set; }
}

Deserialize XML to Lists in C#

I got your code working with minor modifications that have nothing to do with serialization itself, hence the issue doesn't seem to be with the xml serialization itself but with how it is called:

public static void deserializeXml<T>(this T toDeserialize, string filename)
{
// !!!! toDeserialize is a copy to instance in the heap, so -> ...

XmlSerializer xmlSerializer = new XmlSerializer(toDeserialize.GetType());

Stream stream = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read);
// -> ... here we assign reference of deserialized instance to toDeserialize(which is a copy)
toDeserialize = (T) xmlSerializer.Deserialize(stream);

// we need to return result here, otherwise this reference copy will be left dying here
}

The code:

static class Serializer
{
// note here: deserializeXml returns reference to deserialized instance
public static T deserializeXml<T>(string filename)
{
XmlSerializer xmlSerializer = new XmlSerializer(typeof(T));

using (Stream stream = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read))
{
var toDeserialize = (T)xmlSerializer.Deserialize(stream);
return toDeserialize;
}
}

public static void serializeToXml<T>(T instance, string filename)
{
var xmlSerializer = new XmlSerializer(instance.GetType());
using (Stream stream = new FileStream(filename, FileMode.Create, FileAccess.ReadWrite, FileShare.Read))
{
xmlSerializer.Serialize(stream, instance);
}
}
}

So running it in the following way:

    Plan p = new Plan();
p.elements.Items.Add(new Element { id = 1 });
p.elements.Items.Add(new Element { id = 2 });
p.elements.Items.Add(new Element { id = 3 });

Serializer.serializeToXml(p, @"D:\1.xml");
var p2 = Serializer.deserializeXml<Plan>(@"D:\1.xml");
Console.WriteLine(p2.elements.Items.Count);
Serializer.serializeToXml(p2, @"D:\2.xml");

gives identical D:\1.xml and D:\2.xml in the end.
Hope this helps

Deserialize XML into C# object with list

I tweaked your classes a little bit for your deserialization code to work:

[Serializable, XmlRoot("Entry")]
public class DeserializedClass
{
public string entryValue1;
public string entryValue2;

[XmlElement("RootElement")]
public List<RootElement> rootElement { get; set; }
}

public class RootElement
{
public string rootElementValue1 { get; set; }
public string rootElementValue2 { get; set; }
}

Now it works fine.

I don't know why you declared your XmlRoot as "Form" as there is no element in the XML with that name so I replaced it with "Entry".

You cannot use an Entry class with entryvalue1 and entryvalue2 properties because they are direct children of the root (Event) and there is no child as Entry. In short your classes must reflect the hierarchy of the XML so that deserialization can work properly.

Convert xml to List by Deserialize in c#

This should work:

[XmlElement("CustomerRet")]
public List<Customer> Customers { get; set; }

And a full example:

[XmlTypeAttribute(AnonymousType = true)]
public class CustomersData
{
[XmlElement("CustomerRet")]
public List<Customer> Customers { get; set; }

public CustomersData()
{
Customers = new List<Customer>();
}
}

public class Customer
{
[XmlElement(ElementName = "ListID")]
public string ListID { get; set; }

[XmlElement(ElementName = "Name")]
public string Name { get; set; }

[XmlElement(ElementName = "FullName")]
public string FullName { get; set; }

[XmlElement(ElementName = "Phone")]
public string Phone { get; set; }
}

class Program
{
static void Main()
{
var xml =
@"<?xml version=""1.0"" ?>
<CustomerQueryRs>
<CustomerRet>
<ListID>6BE0000-1159990808</ListID>
<Name>+ Blaine Bailey</Name>
<FullName>+ Blaine Bailey</FullName>
<Phone>866-855-0800</Phone>
</CustomerRet>
<CustomerRet>
<ListID>9BA0000-1165353294</ListID>
<Name>+ Brian Boyd</Name>
<FullName>+ Brian Boyd</FullName>
<Phone>203-245-1877</Phone>
</CustomerRet>
<CustomerRet>
<ListID>9280000-1164147562</ListID>
<Name>+ Brian Leahy</Name>
<FullName>+ Brian Leahy</FullName>
<Phone>508-341-0955</Phone>
</CustomerRet>
</CustomerQueryRs>";
var serializer = new XmlSerializer(typeof(CustomersData), new XmlRootAttribute("CustomerQueryRs"));
using (var stringReader = new StringReader(xml))
using (var reader = XmlReader.Create(stringReader))
{
var result = (CustomersData)serializer.Deserialize(reader);
Console.WriteLine(result.Customers[1].FullName);
}
}
}


Related Topics



Leave a reply



Submit