Сериализация списков классов в XML - PullRequest
33 голосов
/ 07 октября 2008

У меня есть коллекция классов, которые я хочу сериализовать в файл 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>

где все Бары в Barlist записаны со всеми их свойствами. Я вполне уверен, что мне понадобится некоторая разметка для определения класса, чтобы это сработало, но я не могу найти правильную комбинацию.

Я пометил Foo с атрибутом

[XmlRoot("Foo")]  

и list<Bar> с атрибутом

[XmlArray("BarList"), XmlArrayItem(typeof(Bar), ElementName="Bar")]

в попытке сообщить Сериализатору, что я хочу, чтобы произошло. Это, похоже, не работает, и я просто получаю пустой тег, похожий на этот:

<?xml version="1.0" encoding="utf-8"?>
<Foo> 
  <Barlist />
</Foo>

Я не уверен, что тот факт, что я использую автоматические свойства, должен иметь какой-либо эффект, или использование обобщений требует какой-то особой обработки. Я получил это для работы с более простыми типами, такими как список строк, но список классов до сих пор ускользает от меня.

Ответы [ 4 ]

31 голосов
/ 07 октября 2008

Просто чтобы проверить, пометили ли вы Бар как [Сериализуемый]?

Кроме того, для десериализации вам необходим ctor без параметров на 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>
4 голосов
/ 07 октября 2008

Все выглядит отлично. Как сказал @Carl, вам нужно добавить атрибут [Serializable] к вашим классам, но кроме этого ваше XML-создание должно работать find.

Foo

[Serializable]
[XmlRoot("Foo")]
public class Foo
{
    [XmlArray("BarList"), XmlArrayItem(typeof(Bar), ElementName = "Bar")]
    public List<Bar> BarList { get; set; }
}

Бар

[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>
1 голос
/ 01 августа 2013

Прошло более 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

С этим определением класс (де) сериализуется без каких-либо проблем. Это XML, который выходит отсюда:

<MyClass> MyFirstProperty="" MySecondProperty=""
    <Children>
        <ChildClass> MyFirstProperty="" MySecondProperty=""
        </ChildClass>
   </Children>
</MyClass>

Мне потребовалось всего два дня, чтобы понять, что решением было исключить префикс <XmlElement> элементов List (of T).

0 голосов
/ 10 ноября 2017
var xmlfromLINQ = new XElement("BarList",
            from c in BarList 
            select new XElement("Bar",
                new XElement("Property1", c.Property1),
                new XElement("Property2", c.Property2)
             ));
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...