Сериализация списков классов для XML
У меня есть набор классов, которые я хочу сериализовать в XML файл. Это выглядит примерно так:
public class Foo
{
public List<Bar> BarList { get; set; }
}
Если панель является просто оболочкой для набора свойств, например:
public class Bar
{
public string Property1 { get; set; }
public string Property2 { get; set; }
}
Я хочу отметить это так, чтобы он выводился в файл XML - это будет использоваться как для сохранения, так и для рендеринга настроек через XSLT в удобную для человека форму.
Я хочу получить хорошее представление XML следующим образом:
<?xml version="1.0" encoding="utf-8"?>
<Foo>
<BarList>
<Bar>
<Property1>Value</Property1>
<Property2>Value</Property2>
</Bar>
<Bar>
<Property1>Value</Property1>
<Property2>Value</Property2>
</Bar>
</Barlist>
</Foo>
где все бары в Барлисте выписаны со всеми их свойствами. Я уверен, что мне понадобится разметка для определения класса, чтобы он работал, но я не могу найти правильную комбинацию.
Я отметил Foo атрибутом
[XmlRoot("Foo")]
и list<Bar>
с атрибутом
[XmlArray("BarList"), XmlArrayItem(typeof(Bar), ElementName="Bar")]
пытаясь рассказать Сериализатору, что я хочу. Однако это не работает, и я просто получаю пустой тег, выглядящий следующим образом:
<?xml version="1.0" encoding="utf-8"?>
<Foo>
<Barlist />
</Foo>
Я не уверен, что тот факт, что я использую автоматические свойства, должен иметь какой-либо эффект, или если использование дженериков требует какой-либо специальной обработки. Я получил это, чтобы работать с более простыми типами, такими как список строк, но список классов до сих пор ускользает от меня.
Ответы
Ответ 1
Просто, чтобы проверить, вы отметили Bar как [Serializable]?
Кроме того, вам нужен параметр-less ctor on Bar, для десериализации
Хмм, я использовал:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
Foo f = new Foo();
f.BarList = new List<Bar>();
f.BarList.Add(new Bar { Property1 = "abc", Property2 = "def" });
XmlSerializer ser = new XmlSerializer(typeof(Foo));
using (FileStream fs = new FileStream(@"c:\sertest.xml", FileMode.Create))
{
ser.Serialize(fs, f);
}
}
}
public class Foo
{
[XmlArray("BarList"), XmlArrayItem(typeof(Bar), ElementName = "Bar")]
public List<Bar> BarList { get; set; }
}
[XmlRoot("Foo")]
public class Bar
{
public string Property1 { get; set; }
public string Property2 { get; set; }
}
И это произвело:
<?xml version="1.0"?>
<Foo xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<BarList>
<Bar>
<Property1>abc</Property1>
<Property2>def</Property2>
</Bar>
</BarList>
</Foo>
Ответ 2
Все выглядит великолепно. Поскольку @Carl сказал, что вам нужно добавить аттрибут [Serializable] для ваших классов, но помимо этого ваше XML-создание должно работать.
Foo
[Serializable]
[XmlRoot("Foo")]
public class Foo
{
[XmlArray("BarList"), XmlArrayItem(typeof(Bar), ElementName = "Bar")]
public List<Bar> BarList { get; set; }
}
Bar
[Serializable]
public class Bar
{
public string Property1 { get; set; }
public string Property2 { get; set; }
}
Код для проверки
Foo f = new Foo();
f.BarList = new List<Bar>();
f.BarList.Add(new Bar() { Property1 = "s", Property2 = "2" });
f.BarList.Add(new Bar() { Property1 = "s", Property2 = "2" });
FileStream fs = new FileStream("c:\\test.xml", FileMode.OpenOrCreate);
System.Xml.Serialization.XmlSerializer s = new System.Xml.Serialization.XmlSerializer(typeof(Foo));
s.Serialize(fs, f);
Выход
<?xml version="1.0" ?>
<Foo xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<BarList>
<Bar>
<Property1>s</Property1>
<Property2>2</Property2>
</Bar>
<Bar>
<Property1>s</Property1>
<Property2>2</Property2>
</Bar>
</BarList>
</Foo>
Ответ 3
Прошло более 5 лет с момента публикации этого элемента. Я даю свой опыт с июля 2013 года (.NET Framework 4.5). Для чего это стоит и кому это может касаться:
Когда я определяю такой класс: (код VB.Net)
<Serializable> Public Class MyClass
Public Property Children as List(of ChildCLass)
<XmlAttribute> Public Property MyFirstProperty as string
<XmlAttribute> Public Property MySecondProperty as string
End Class
<Serializable> Public Class ChildClass
<XmlAttribute> Public Property MyFirstProperty as string
<XmlAttribute> Public Property MySecondProperty as string
End Class
С этим определением класс (de) сериализуется без каких-либо проблем. Это XML, который выходит отсюда:
<MyClass> MyFirstProperty="" MySecondProperty=""
<Children>
<ChildClass> MyFirstProperty="" MySecondProperty=""
</ChildClass>
</Children>
</MyClass>
Мне потребовалось всего два дня, чтобы понять, что решение состоит в том, чтобы оставить префикс <XmlElement>
элементов List (of T).
Ответ 4
var xmlfromLINQ = new XElement("BarList",
from c in BarList
select new XElement("Bar",
new XElement("Property1", c.Property1),
new XElement("Property2", c.Property2)
));