I have a class PersonList
[XmlRoot(\"Persons\")]
PersonList : List
when I serialize this to XML, by default it wi
I know it's an old question but I ran into the same problem and none of the solutions seems to adresse the OP's question. So here is my solution (comments are in french if you wonder) :
#region Références
using System.Collections.Generic;
using System.Linq;
using System.Xml;
using System.Xml.Schema;
using System.Xml.Serialization;
#endregion
namespace XmlSerializationTests
{
///
/// Représente une liste qui peut être sérialisée en XML en tant que noeud racine.
///
/// Type des éléments de la liste.
public class XmlSerializableList
: List, IXmlSerializable
{
#region Variables
private static readonly XmlSerializer _ItemSerializer = new XmlSerializer(typeof(T));
private static readonly string _ItemName;
private string _RootName;
#endregion
#region Méthodes
///
/// Initialisation statique
///
static XmlSerializableList()
{
_ItemName = (typeof(T).GetCustomAttributes(typeof(XmlRootAttribute), true).FirstOrDefault() as XmlRootAttribute)?.ElementName ?? typeof(T).Name;
}
///
/// Obtient le nom racine.
///
protected virtual string RootName
{
get
{
if (string.IsNullOrWhiteSpace(_RootName)) _RootName = (GetType().GetCustomAttributes(typeof(XmlRootAttribute), true).FirstOrDefault() as XmlRootAttribute)?.ElementName ?? GetType().Name;
return _RootName;
}
}
///
/// Obtient le nom des éléments.
///
protected virtual string ItemName
{
get { return _ItemName; }
}
///
/// Cette méthode est réservée et ne doit pas être utilisée.Lorsque vous implémentez l'interface IXmlSerializable, vous devez retourner la valeur null (Nothing dans Visual Basic) à partir cette méthode et, si la spécification d'un schéma personnalisé est requise, appliquez à la place à la classe.
///
/// qui décrit la représentation XML de l'objet qui est généré par la méthode et utilisé par la méthode .
public XmlSchema GetSchema()
{
return null;
}
///
/// Génère un objet à partir de sa représentation XML.
///
/// source à partir de laquelle l'objet est désérialisé.
public void ReadXml(XmlReader reader)
{
if (!reader.IsEmptyElement)
{
reader.ReadStartElement();
while (reader.NodeType != XmlNodeType.EndElement)
{
T item = (T) _ItemSerializer.Deserialize(reader);
Add(item);
}
reader.ReadEndElement();
}
else reader.ReadStartElement();
}
///
/// Convertit un objet en sa représentation XML.
///
/// flux dans lequel l'objet est sérialisé.
public void WriteXml(XmlWriter writer)
{
foreach (var i in this)
{
XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
ns.Add("", "");
_ItemSerializer.Serialize(writer, i, ns);
}
}
#endregion
}
}
And here a unit test class to demonstrate use and results :
#region Références
using System.IO;
using System.Text;
using System.Xml.Serialization;
using Microsoft.VisualStudio.TestTools.UnitTesting;
#endregion
namespace XmlSerializationTests
{
[TestClass]
public class XmlSerializableListTests
{
public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
public int Birth { get; set; }
}
[XmlRoot("color")]
public class ColorDefinition
{
[XmlElement("name")] public string Name { get; set; }
[XmlElement("r")] public int Red { get; set; }
[XmlElement("g")] public int Green { get; set; }
[XmlElement("b")] public int Blue { get; set; }
}
public class Persons : XmlSerializableList
{
}
[XmlRoot("colors")]
public class ColorList : XmlSerializableList
{
}
private T ReadXml(string text) where T : class
{
XmlSerializer serializer = new XmlSerializer(typeof (T));
using (StringReader sr = new StringReader(text))
{
return serializer.Deserialize(sr) as T;
}
}
private string WriteXml(T data) where T : class
{
XmlSerializer serializer = new XmlSerializer(typeof(T));
StringBuilder sb = new StringBuilder();
using (StringWriter sw = new StringWriter(sb))
{
serializer.Serialize(sw, data);
return sb.ToString();
}
}
[TestMethod]
public void ReadEmpty()
{
string xml = @"
";
XmlSerializableList lst = ReadXml>(xml);
Assert.AreEqual(0, lst.Count);
}
[TestMethod]
public void ReadEmpty2()
{
string xml = @"
";
XmlSerializableList lst = ReadXml>(xml);
Assert.AreEqual(0, lst.Count);
}
[TestMethod]
public void ReadSimpleItems()
{
string xml = @"
0
52
79
";
XmlSerializableList lst = ReadXml>(xml);
Assert.AreEqual(3, lst.Count);
Assert.AreEqual(0, lst[0]);
Assert.AreEqual(52, lst[1]);
Assert.AreEqual(79, lst[2]);
}
[TestMethod]
public void ReadComplexItems()
{
string xml = @"
Linus
Torvalds
1969
Bill
Gates
1955
Steve
Jobs
1955
";
XmlSerializableList lst = ReadXml>(xml);
Assert.AreEqual(3, lst.Count);
Assert.AreEqual("Linus", lst[0].FirstName);
Assert.AreEqual("Torvalds", lst[0].LastName);
Assert.AreEqual(1969, lst[0].Birth);
Assert.AreEqual("Bill", lst[1].FirstName);
Assert.AreEqual("Gates", lst[1].LastName);
Assert.AreEqual(1955, lst[1].Birth);
Assert.AreEqual("Steve", lst[2].FirstName);
Assert.AreEqual("Jobs", lst[2].LastName);
Assert.AreEqual(1955, lst[2].Birth);
}
[TestMethod]
public void ReadInheritedPersons()
{
string xml = @"
Linus
Torvalds
1969
Bill
Gates
1955
Steve
Jobs
1955
";
Persons lst = ReadXml(xml);
Assert.AreEqual(3, lst.Count);
Assert.AreEqual("Linus", lst[0].FirstName);
Assert.AreEqual("Torvalds", lst[0].LastName);
Assert.AreEqual(1969, lst[0].Birth);
Assert.AreEqual("Bill", lst[1].FirstName);
Assert.AreEqual("Gates", lst[1].LastName);
Assert.AreEqual(1955, lst[1].Birth);
Assert.AreEqual("Steve", lst[2].FirstName);
Assert.AreEqual("Jobs", lst[2].LastName);
Assert.AreEqual(1955, lst[2].Birth);
}
[TestMethod]
public void ReadInheritedColors()
{
string xml = @"
red
255
0
0
green
0
255
0
yellow
255
255
0
";
ColorList lst = ReadXml(xml);
Assert.AreEqual(3, lst.Count);
Assert.AreEqual("red", lst[0].Name);
Assert.AreEqual(255, lst[0].Red);
Assert.AreEqual(0, lst[0].Green);
Assert.AreEqual(0, lst[0].Blue);
Assert.AreEqual("green", lst[1].Name);
Assert.AreEqual(0, lst[1].Red);
Assert.AreEqual(255, lst[1].Green);
Assert.AreEqual(0, lst[1].Blue);
Assert.AreEqual("yellow", lst[2].Name);
Assert.AreEqual(255, lst[2].Red);
Assert.AreEqual(255, lst[2].Green);
Assert.AreEqual(0, lst[2].Blue);
}
[TestMethod]
public void WriteEmpty()
{
string xml = @"
";
XmlSerializableList lst = new XmlSerializableList();
string result = WriteXml(lst);
Assert.AreEqual(xml, result);
}
[TestMethod]
public void WriteSimpleItems()
{
string xml = @"
0
52
79
";
XmlSerializableList lst = new XmlSerializableList() {0, 52, 79};
string result = WriteXml(lst);
Assert.AreEqual(xml, result);
}
[TestMethod]
public void WriteComplexItems()
{
string xml = @"
Linus
Torvalds
1969
Bill
Gates
1955
Steve
Jobs
1955
";
XmlSerializableList persons = new XmlSerializableList
{
new Person {FirstName = "Linus", LastName = "Torvalds", Birth = 1969},
new Person {FirstName = "Bill", LastName = "Gates", Birth = 1955},
new Person {FirstName = "Steve", LastName = "Jobs", Birth = 1955}
};
string result = WriteXml(persons);
Assert.AreEqual(xml, result);
}
[TestMethod]
public void WriteInheritedPersons()
{
string xml = @"
Linus
Torvalds
1969
Bill
Gates
1955
Steve
Jobs
1955
";
Persons lst = new Persons
{
new Person {FirstName = "Linus", LastName = "Torvalds", Birth = 1969},
new Person {FirstName = "Bill", LastName = "Gates", Birth = 1955},
new Person {FirstName = "Steve", LastName = "Jobs", Birth = 1955}
};
string result = WriteXml(lst);
Assert.AreEqual(xml, result);
}
[TestMethod]
public void WriteInheritedColors()
{
string xml = @"
red
255
0
0
green
0
255
0
yellow
255
255
0
";
ColorList lst = new ColorList
{
new ColorDefinition { Name = "red", Red = 255, Green = 0, Blue = 0 },
new ColorDefinition { Name = "green", Red = 0, Green = 255, Blue = 0 },
new ColorDefinition { Name = "yellow", Red = 255, Green = 255, Blue = 0 }
};
string result = WriteXml(lst);
Assert.AreEqual(xml, result);
}
}
}